--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqserviceadaptor.cpp Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,982 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, version 2.1 of the License.
+*
+* 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program. If not,
+* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+*
+* Description:
+*
+*/
+
+#include "xqservicelog.h"
+
+#include "xqserviceglobal.h"
+#include "xqserviceadaptor.h"
+#include "xqservicechannel.h"
+#include "xqservicethreaddata.h"
+#include "xqserviceipcclient.h"
+
+#include <xqserviceutil.h>
+#include <xqrequestutil.h>
+#include <qmetaobject.h>
+#include <QMap>
+#include <QDataStream>
+#include <qatomic.h>
+#include <QDebug>
+#include <QVarLengthArray>
+#include <e32err.h>
+#include <xqsharablefile.h>
+
+/*!
+ \class XQServiceAdaptor
+ \inpublicgroup QtBaseModule
+
+ \ingroup ipc
+ \brief The XQServiceAdaptor class provides an interface to messages on a XQService IPC channel which simplifies remote signal and slot invocations.
+
+ Using this class, it is very easy to convert a signal emission into an IPC
+ message on a channel, and to convert an IPC message on a channel into a
+ slot invocation. In the following example, when the signal \c{valueChanged(int)}
+ is emitted from the object \c source, the IPC message \c{changeValue(int)} will
+ be sent on the channel \c{QPE/Foo}:
+
+ \code
+ XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
+ XQServiceAdaptor::connect
+ (source, SIGNAL(valueChanged(int)), adaptor, MESSAGE(changeValue(int)));
+ \endcode
+
+ Note that we use XQServiceAdaptor::connect() to connect the signal to the
+ IPC message, not QObject::connect(). A common error is to use \c{connect()}
+ without qualifying it with \c{XQServiceAdaptor::} and picking up
+ QObject::connect() by mistake.
+
+ On the server side of an IPC protocol, the \c{changeValue(int)} message can
+ be connected to the slot \c{setValue()} on \c dest:
+
+ \code
+ XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
+ XQServiceAdaptor::connect
+ (adaptor, MESSAGE(changeValue(int)), dest, SLOT(setValue(int)));
+ \endcode
+
+ Now, whenever the client emits the \c{valueChanged(int)} signal, the
+ \c{setValue(int)} slot will be automatically invoked on the server side,
+ with the \c int parameter passed as its argument.
+
+ Only certain parameter types can be passed across an IPC boundary in this fashion.
+ The type must be visible to QVariant as a meta-type. Many simple built-in
+ types are already visible; for user-defined types, use Q_DECLARE_METATYPE()
+ and qRegisterMetaTypeStreamOperators().
+
+ \sa XQServiceChannel
+*/
+
+class XQServiceAdaptorChannel : public XQServiceChannel
+{
+ Q_OBJECT
+public:
+ XQServiceAdaptorChannel(const QString& channel, XQServiceAdaptor *adapt)
+ : XQServiceChannel(channel, true, adapt), adaptor(adapt)
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::XQServiceAdaptorChannel");
+ }
+
+ ~XQServiceAdaptorChannel()
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::~XQServiceAdaptorChannel");
+ }
+
+ QVariant receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf);
+ void commandReceive(const XQServiceCommand cmd);
+
+private slots:
+
+private:
+ XQServiceAdaptor *adaptor;
+};
+
+QVariant XQServiceAdaptorChannel::receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::receive");
+ return adaptor->received(msg, data, sf);
+}
+
+void XQServiceAdaptorChannel::commandReceive(const XQServiceCommand cmd)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::commandReceive %d", cmd);
+ switch (cmd)
+ {
+ case ReturnValueDelivered:
+ emit adaptor->returnValueDelivered() ;
+ break;
+
+ case ClientDisconnected:
+ emit adaptor->clientDisconnected() ;
+ break;
+
+ default:
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::unhandled command %d", cmd);
+ break;
+ }
+}
+
+class XQServiceAdaptorSignalInfo
+{
+public:
+ QObject *sender;
+ int signalIndex;
+ int destroyIndex;
+ QString message;
+ int *types;
+ int numArgs;
+};
+
+class XQServiceAdaptorSlotInfo
+{
+public:
+ ~XQServiceAdaptorSlotInfo()
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorSlotInfo::~XQServiceAdaptorSlotInfo");
+ qFree(types);
+ }
+
+ QObject *receiver;
+ int memberIndex;
+ bool destroyed;
+ int returnType;
+ int *types;
+ int numArgs;
+};
+
+class XQServiceAdaptorPrivate : public QObject
+{
+ // Do not put Q_OBJECT here.
+public:
+ XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan);
+ ~XQServiceAdaptorPrivate();
+
+ QAtomicInt ref;
+ XQServiceAdaptor *parent;
+ QString channelName;
+ bool connected;
+ const QMetaObject *publishedTo;
+ QMultiMap<QString, XQServiceAdaptorSlotInfo *> invokers;
+ QList<XQServiceAdaptorSignalInfo *> signalList;
+ int slotIndex;
+
+ static const int QVariantId = -243;
+ static int *connectionTypes(const QByteArray& member, int& nargs);
+ static int typeFromName(const QByteArray& name);
+
+protected:
+ int qt_metacall(QMetaObject::Call c, int id, void **a);
+};
+
+XQServiceAdaptorPrivate::XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan)
+ : ref(1), channelName(chan)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::XQServiceAdaptorPrivate");
+ parent = obj;
+ connected = false;
+ publishedTo = 0;
+
+ // Fake slots start at this index in the QMetaObject.
+ slotIndex = staticMetaObject.methodCount();
+}
+
+XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate");
+ qDeleteAll(invokers);
+
+ // Disconnect all of the signals associated with this adaptor.
+ int index = slotIndex;
+ XQSERVICE_DEBUG_PRINT("index: %d", index);
+ foreach (XQServiceAdaptorSignalInfo *info, signalList) {
+ XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
+ if (info->signalIndex >= 0) {
+ QMetaObject::disconnect(info->sender, info->signalIndex,
+ this, index);
+ }
+ XQSERVICE_DEBUG_PRINT("info->destroyIndex: %d", info->destroyIndex);
+ if (info->destroyIndex >= 0) {
+ QMetaObject::disconnect(info->sender, info->destroyIndex,
+ this, index + 1);
+ }
+ qFree(info->types);
+ delete info;
+ index += 2;
+ }
+}
+
+// Get the QVariant type number for a type name.
+int XQServiceAdaptorPrivate::typeFromName( const QByteArray& type )
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::typeFromName");
+ XQSERVICE_DEBUG_PRINT("type: %s", type.constData());
+ if (type.endsWith('*')){
+ XQSERVICE_DEBUG_PRINT("Pointer");
+ return QMetaType::VoidStar;
+ }
+ else if ( type.size() == 0 || type == "void" ){
+ XQSERVICE_DEBUG_PRINT("Void");
+ return QMetaType::Void;
+ }
+ else if ( type == "QVariant" ){
+ XQSERVICE_DEBUG_PRINT("QVariant");
+ return XQServiceAdaptorPrivate::QVariantId;
+ }
+ int id = QMetaType::type( type.constData() );
+ XQSERVICE_DEBUG_PRINT("id: %d", id);
+ if ( id != (int)QMetaType::Void )
+ return id;
+ return QVariant::nameToType(type);
+}
+
+// Returns the connection types associated with a signal or slot member.
+int *XQServiceAdaptorPrivate::connectionTypes( const QByteArray& member, int& nargs )
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::connectionTypes");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ // Based on Qt's internal queuedConnectionTypes function.
+ nargs = 0;
+ int *types = 0;
+ const char *s = member.constData();
+ while (*s != '\0' && *s != '(') { ++s; }
+ if ( *s == '\0' )
+ return 0;
+ ++s;
+ const char *e = s;
+ while (*e != ')') {
+ ++e;
+ if (*e == ')' || *e == ',')
+ ++nargs;
+ }
+
+ types = (int *) qMalloc((nargs+1)*sizeof(int));
+ types[nargs] = 0;
+ for (int n = 0; n < nargs; ++n) {
+ e = s;
+ while (*s != ',' && *s != ')')
+ ++s;
+ QByteArray type(e, s-e);
+ ++s;
+
+ types[n] = typeFromName(type);
+ if (!types[n]) {
+ XQSERVICE_WARNING_PRINT("XQServiceAdaptorPrivate::connectionTypes: Cannot marshal arguments of type '%s'", type.constData());
+ qFree(types);
+ return 0;
+ }
+ }
+ XQSERVICE_DEBUG_PRINT("types: %d", types);
+ return types;
+}
+
+int XQServiceAdaptorPrivate::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::qt_metacall");
+ id = QObject::qt_metacall(c, id, a);
+ XQSERVICE_DEBUG_PRINT("id: %d", id);
+ if (id < 0)
+ return id;
+ if (c == QMetaObject::InvokeMetaMethod) {
+ XQSERVICE_DEBUG_PRINT("InvokeMetaMethod");
+ // Each signal that we have intercepted has two fake slots
+ // associated with it. The first is the activation slot.
+ // The second is the destroyed() slot for the signal's object.
+ if (id < signalList.size() * 2) {
+ XQServiceAdaptorSignalInfo *info = signalList[id / 2];
+ if ((id % 2) == 0) {
+ // The signal we are interested in has been activated.
+ if (info->types) {
+ XQSERVICE_DEBUG_PRINT("Signal has been activated");
+ QList<QVariant> args;
+ XQSERVICE_DEBUG_PRINT("info->numArgs: %d", info->numArgs);
+ for (int i = 0; i < info->numArgs; ++i) {
+ if (info->types[i] != XQServiceAdaptorPrivate::QVariantId) {
+ QVariant arg(info->types[i], a[i + 1]);
+ XQSERVICE_DEBUG_PRINT("arg: %s", qPrintable(arg.toString()));
+ args.append(arg);
+ } else {
+ args.append(*((const QVariant *)(a[i + 1])));
+ }
+ }
+ //TODO: CHECK HERE
+ QVariant retValue;
+ parent->sendMessage(info->message, args,retValue);
+ }
+ } else {
+ XQSERVICE_DEBUG_PRINT("Sender has been destroyed");
+ // The sender has been destroyed. Clear the signal indices
+ // so that we don't try to do a manual disconnect when our
+ // own destructor is called.
+ info->signalIndex = -1;
+ info->destroyIndex = -1;
+ }
+ }
+ id -= signalList.size() * 2;
+ }
+ XQSERVICE_DEBUG_PRINT("id: %d", id);
+ return id;
+}
+
+/*!
+ Construct a Qt Extended IPC message object for \a channel and attach it to \a parent.
+ If \a channel is empty, then messages are taken from the application's
+ \c{appMessage} channel.
+*/
+XQServiceAdaptor::XQServiceAdaptor(const QString& channel, QObject *parent)
+ : QObject(parent)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::XQServiceAdaptor");
+ d = new XQServiceAdaptorPrivate(this, channel);
+}
+
+/*!
+*/
+XQServiceAdaptor::~XQServiceAdaptor()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::~XQServiceAdaptor");
+ if (!d->ref.deref())
+ delete d;
+ d = 0;
+}
+
+/*!
+ Returns the name of the channel that this adaptor is associated with.
+*/
+QString XQServiceAdaptor::channel() const
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::channel");
+ XQSERVICE_DEBUG_PRINT("d->channelName: %s", qPrintable(d->channelName));
+ return d->channelName;
+}
+
+/*!
+ Connects \a signal on \a sender to \a member on \a receiver. Returns true
+ if the receiveion was possible; otherwise returns false.
+
+ If either \a sender or \a receiver are instances of
+ XQServiceAdaptor, this function will arrange for the signal
+ to be delivered over a Qt Extended IPC channel. If both \a sender and
+ \a receiver are local, this function is identical
+ to QObject::connect().
+
+ If the same signal is connected to same slot multiple times,
+ then signal delivery will happen that many times.
+
+ \sa XQServiceAdaptor::ChannelSelector
+*/
+bool XQServiceAdaptor::connect(QObject *sender, const QByteArray& signal,
+ QObject *receiver, const QByteArray& member)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connect");
+ XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ XQServiceAdaptor *senderProxy;
+ XQServiceAdaptor *receiverProxy;
+
+ // Bail out if the parameters are invalid.
+ if (!sender || signal.isEmpty() || !receiver || member.isEmpty()){
+ XQSERVICE_DEBUG_PRINT("Parameters are invalid");
+ return false;
+ }
+
+ // Resolve the objects to find the remote proxies.
+ senderProxy = qobject_cast<XQServiceAdaptor *>(sender);
+ receiverProxy = qobject_cast<XQServiceAdaptor *>(receiver);
+
+ // Remove proxies if the signal or member is not tagged with MESSAGE().
+ if (!member.startsWith(QMESSAGE_CODE + '0')){
+ XQSERVICE_DEBUG_PRINT("No received proxy");
+ receiverProxy = 0;
+ }
+ if (!signal.startsWith(QMESSAGE_CODE + '0')){
+ XQSERVICE_DEBUG_PRINT("No sender proxy");
+ senderProxy = 0;
+ }
+
+ // If neither has a proxy, then use a local connect.
+ if (!senderProxy && !receiverProxy){
+ XQSERVICE_DEBUG_PRINT("Local connect");
+ return QObject::connect(sender, signal, receiver, member);
+ }
+
+ // If both are still remote proxies, then fail the request.
+ if (senderProxy && receiverProxy) {
+ XQSERVICE_WARNING_PRINT("XQServiceAdaptor::connect: cannot connect MESSAGE() to MESSAGE()");
+ return false;
+ }
+
+ // Determine which direction the connect needs to happen in.
+ if (receiverProxy) {
+ XQSERVICE_DEBUG_PRINT("Connecting a local signal to a remote slot");
+ // Connecting a local signal to a remote slot.
+ return receiverProxy->connectLocalToRemote(sender, signal, member);
+ } else {
+ XQSERVICE_DEBUG_PRINT("Connecting a remote signal to a local slot");
+ // Connecting a remote signal to a local slot.
+ return senderProxy->connectRemoteToLocal(signal, receiver, member);
+ }
+}
+
+/*!
+ Publishes the signal or slot called \a member on this object on
+ the Qt Extended IPC channel represented by this XQServiceAdaptor.
+
+ If \a member is a slot, then whenever an application sends a
+ message to the channel with that name, the system will arrange
+ for the slot to be invoked.
+
+ If \a member is a signal, then whenever this object emits that
+ signal, the system will arrange for a message with that name to
+ be sent on the channel.
+
+ Returns false if \a member does not refer to a valid signal or slot.
+
+ \sa publishAll()
+*/
+bool XQServiceAdaptor::publish(const QByteArray& member)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publish");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ // '1' is QSLOT_CODE in Qt 4.4 and below,
+ // '5' is QSLOT_CODE in Qt 4.5 and higher.
+ if (member.size() >= 1 && (member[0] == '1' || member[0] == '5')) {
+ XQSERVICE_DEBUG_PRINT("Exporting a slot");
+ // Exporting a slot.
+ return connectRemoteToLocal("3" + member.mid(1), this, member);
+ } else {
+ XQSERVICE_DEBUG_PRINT("Exporting a sigal");
+ // Exporting a signal.
+ return connectLocalToRemote(this, member, member);
+ }
+}
+
+/*!
+ \enum XQServiceAdaptor::PublishType
+ Type of members to publish via XQServiceAdaptor.
+
+ \value Signals Publish only signals.
+ \value Slots Publish only public slots.
+ \value SignalsAndSlots Publish both signals and public slots.
+*/
+
+/*!
+ Publishes all signals or public slots on this object within subclasses of
+ XQServiceAdaptor. This is typically called from a subclass constructor.
+ The \a type indicates if all signals, all public slots, or both, should
+ be published. Private and protected slots will never be published.
+
+ \sa publish()
+*/
+void XQServiceAdaptor::publishAll(XQServiceAdaptor::PublishType type)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(1)");
+ publishAll(this,XQServiceAdaptor::staticMetaObject.methodCount(),type);
+}
+
+void XQServiceAdaptor::publishAll(QObject* object,int metCount, XQServiceAdaptor::PublishType type)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(2)");
+ XQSERVICE_DEBUG_PRINT("metCount: %d", metCount);
+ const QMetaObject *meta = object->metaObject();
+ if (meta != d->publishedTo) {
+ int count = meta->methodCount();
+ XQSERVICE_DEBUG_PRINT("count: %d", count);
+ int index;
+ if (d->publishedTo)
+ index = d->publishedTo->methodCount();
+ else
+ index = metCount;
+ XQSERVICE_DEBUG_PRINT("index: %d", index);
+ for (; index < count; ++index) {
+
+ QMetaMethod method = meta->method(index);
+ if (method.methodType() == QMetaMethod::Slot &&
+ method.access() == QMetaMethod::Public &&
+ (type == Slots || type == SignalsAndSlots)) {
+ QByteArray name = method.signature();
+ XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
+ XQSERVICE_DEBUG_PRINT("connectRemoteToLocal");
+ connectRemoteToLocal("3" + name, object, "1" + name);
+ } else if (method.methodType() == QMetaMethod::Signal &&
+ (type == Signals || type == SignalsAndSlots)) {
+ QByteArray name = method.signature();
+ XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
+ XQSERVICE_DEBUG_PRINT("connectLocalToRemote");
+ connectLocalToRemote(object, "2" + name, "3" + name);
+ }
+ }
+ d->publishedTo = meta;
+ }
+}
+
+/*!
+ Sends a message on the Qt Extended IPC channel which will cause the invocation
+ of the single-argument \a member on receiving objects, with the
+ argument \a arg1.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, QVariant &retData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1)");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ XQSERVICE_DEBUG_PRINT("arg1: %s", qPrintable(arg1.toString()));
+ QList<QVariant> args;
+ args.append(arg1);
+ return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+ Sends a message on the Qt Extended IPC channel which will cause the invocation
+ of the double-argument \a member on receiving objects, with the
+ arguments \a arg1 and \a arg2.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, const QVariant &arg2, QVariant &retData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()));
+ QList<QVariant> args;
+ args.append(arg1);
+ args.append(arg2);
+ return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+ Sends a message on the Qt Extended IPC channel which will cause the invocation
+ of the triple-argument \a member on receiving objects, with the
+ arguments \a arg1, \a arg2, and \a arg3.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1,
+ const QVariant &arg2, const QVariant &arg3, QVariant &retData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(3)");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s, arg3: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()), qPrintable(arg3.toString()));
+ QList<QVariant> args;
+ args.append(arg1);
+ args.append(arg2);
+ args.append(arg3);
+ return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+ Sends a message on the Qt Extended IPC channel which will cause the invocation
+ of the multi-argument \a member on receiving objects, with the
+ argument list \a args.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QList<QVariant>& args, QVariant &retData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(4)");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ for(int i=0;i<args.size();++i){
+ XQSERVICE_DEBUG_PRINT("args[%d]: %s", i, qPrintable(args[i].toString()));
+ }
+ return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+ Returns true if the message on the Qt Extended IPC channel corresponding to \a signal
+ has been connected to a local slot; otherwise returns false.
+*/
+bool XQServiceAdaptor::isConnected(const QByteArray& signal)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::isConnected");
+ XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+ return d->invokers.contains(memberToMessage(signal));
+}
+
+/*!
+ Converts a signal or slot \a member name into a Qt Extended IPC message name.
+ The default implementation strips the signal or slot prefix number
+ from \a member and then normalizes the name to convert types
+ such as \c{const QString&} into QString.
+
+ \sa QMetaObject::normalizedSignature()
+*/
+QString XQServiceAdaptor::memberToMessage(const QByteArray& member)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::memberToMessage");
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ if (member.size() >= 1 && member[0] >= '0' && member[0] <= '9') {
+ return QString::fromLatin1
+ (QMetaObject::normalizedSignature(member.constData() + 1));
+ } else {
+ return QString::fromLatin1(member.data(), member.size());
+ }
+}
+
+QVariant XQServiceAdaptor::received(const QString& msg, const QByteArray& data, const XQSharableFile &sf)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::received");
+ XQSERVICE_DEBUG_PRINT("\tmsg: %s", qPrintable(msg));
+ XQSERVICE_DEBUG_PRINT("\tdata: %s", data.constData());
+ QVariant returnValue;
+ bool found = false;
+ // Increase the reference count on the private data just
+ // in case the XQServiceAdaptor is deleted by one of the slots.
+ XQServiceAdaptorPrivate *priv = d;
+ priv->ref.ref();
+
+ // Iterate through the slots for the message and invoke them.
+ QMultiMap<QString, XQServiceAdaptorSlotInfo *>::ConstIterator iter;
+ for (iter = priv->invokers.find(msg);
+ iter != priv->invokers.end() && iter.key() == msg; ++iter) {
+ XQServiceAdaptorSlotInfo *info = iter.value();
+ if (info->destroyed){
+ XQSERVICE_DEBUG_PRINT("\tDestroyed");
+ continue;
+ }
+
+ // Convert "data" into a set of arguments suitable for qt_metacall.
+ QDataStream stream(data);
+ QList<QVariant> args;
+ // a[0] is return value (numArgs+1)
+ QVarLengthArray<void *, 32> a(info->numArgs + 1);
+
+ XQSERVICE_DEBUG_PRINT("\tinfo->returnType: %d", info->returnType);
+
+ if (info->returnType != (int)QVariant::Invalid) {
+ returnValue = QVariant(info->returnType, (const void *)0);
+ a[0] = returnValue.data();
+ } else {
+ a[0] = 0;
+ }
+ // Need to pick also the last XQRequestInfo form the stream
+ // That's why iterating up to numArgs+1
+
+ int reqInfoIndex = info->numArgs;
+
+
+ for (int arg = 0; arg < info->numArgs+1; ++arg)
+ {
+ XQSERVICE_DEBUG_PRINT("\tDesserialize argument: %d", arg);
+ if (arg == reqInfoIndex)
+ {
+ // The last argument should be the request index
+ XQSERVICE_DEBUG_PRINT("\tDesserialize XQRequestInfo");
+ QVariant v;
+ stream >> v;
+ XQSERVICE_DEBUG_PRINT("\tXQRequestInfo:QVariant type=%s", v.typeName());
+ if (QString(v.typeName()) == QString("XQRequestInfo"))
+ {
+ XQRequestInfo info = v.value<XQRequestInfo>();
+
+ //bring foreground or background based on RequestInfo from client side.
+ bool bg = info.isBackground();
+ bool fg = info.isForeground();
+ if (bg && !fg)
+ {
+ XQSERVICE_DEBUG_PRINT("\tApply background option");
+ XQServiceUtil::toBackground(true);
+ }
+ else if (fg && !bg)
+ {
+ XQSERVICE_DEBUG_PRINT("\tApply foreground option");
+ XQServiceUtil::toBackground(false);
+ }
+ // If both off or both on, do not do anything
+
+ XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+ // Attach to current request before the metacall below !
+ cl->setRequestInfo(info);
+ }
+ }
+ else if (info->types[arg] == XQServiceAdaptorPrivate::QVariantId)
+ {
+ // We need to handle QVariant specially because we actually
+ // need the type header in this case.
+ QVariant temp;
+ stream >> temp;
+
+ XQSERVICE_DEBUG_PRINT("\tQVariantId:QVariant type=%s", temp.typeName());
+
+ if (QString(temp.typeName()) == QString("XQSharableFile"))
+ {
+ //apply the patch
+ if ( sf.isValid())
+ {
+ temp = qVariantFromValue( sf );
+ }
+ }
+
+ args.append(temp);
+ a[arg + 1] = (void *)&(args[arg]);
+ }
+ else {
+ //
+ // The default handling
+ //
+ QVariant temp;
+ stream >> temp;
+
+ XQSERVICE_DEBUG_PRINT("\tDefault:QVariant type=%s", temp.typeName());
+
+ if (QString(temp.typeName()) == QString("XQSharableFile"))
+ {
+ //apply the patch
+ if ( sf.isValid())
+ {
+ temp = qVariantFromValue( sf );
+ }
+ }
+
+ args.append(temp);
+ a[arg + 1] = (void *)(args[arg].data());
+ }
+ }
+
+ // Invoke the specified slot.
+ #if !defined(QT_NO_EXCEPTIONS)
+ try {
+ #endif
+ XQSERVICE_DEBUG_PRINT("Try to make metacall");
+ info->receiver->qt_metacall
+ (QMetaObject::InvokeMetaMethod, info->memberIndex, a.data());
+ found = true;
+ #if !defined(QT_NO_EXCEPTIONS)
+ } catch (...) {
+ }
+ #endif
+ }
+ if (!found)
+ {
+ XQSERVICE_DEBUG_PRINT("Not found");
+ XQService::serviceThreadData()->setLatestError(XQService::EMessageNotFound);
+ }
+ // Decrease the reference count and delete if necessary.
+ if (!priv->ref.deref())
+ delete priv;
+
+ XQSERVICE_DEBUG_PRINT("returnValue: %s", qPrintable(returnValue.toString()));
+ return returnValue;
+}
+
+void XQServiceAdaptor::receiverDestroyed()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::receiverDestroyed");
+ // Mark all slot information blocks that match the receiver
+ // as destroyed so that we don't try to invoke them again.
+ QObject *obj = sender();
+ QMultiMap<QString, XQServiceAdaptorSlotInfo *>::Iterator it;
+ for (it = d->invokers.begin(); it != d->invokers.end(); ++it) {
+ if (it.value()->receiver == obj)
+ it.value()->destroyed = true;
+ }
+}
+
+bool XQServiceAdaptor::connectLocalToRemote
+ (QObject *sender, const QByteArray& signal, const QByteArray& member)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectLocalToRemote");
+ XQSERVICE_DEBUG_PRINT("sender->objectName(): %s", qPrintable(sender->objectName()));
+ XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ XQServiceAdaptorSignalInfo *info = new XQServiceAdaptorSignalInfo();
+ info->sender = sender;
+ info->message = memberToMessage(member);
+
+ // Resolve the signal name on the sender object.
+ if (signal.size() > 0) {
+ if (signal[0] != (QSIGNAL_CODE + '0')) {
+ XQSERVICE_WARNING_PRINT("XQServiceAdaptor: `%s' is not a valid signal specification", signal.constData());
+ delete info;
+ return false;
+ }
+ QByteArray signalName =
+ QMetaObject::normalizedSignature(signal.constData() + 1);
+ info->signalIndex
+ = sender->metaObject()->indexOfSignal(signalName.constData());
+ XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
+ if (info->signalIndex < 0) {
+ XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such signal: %s::%s",
+ sender->metaObject()->className(), signalName.constData());
+ delete info;
+ return false;
+ }
+ info->destroyIndex
+ = sender->metaObject()->indexOfSignal("destroyed()");
+ info->types = XQServiceAdaptorPrivate::connectionTypes
+ (signalName, info->numArgs);
+ } else {
+ XQSERVICE_DEBUG_PRINT("No signal");
+ delete info;
+ return false;
+ }
+
+ // Connect up the signals.
+ int index = d->slotIndex + d->signalList.size() * 2;
+ XQSERVICE_DEBUG_PRINT("index: %d", index);
+ QMetaObject::connect(sender, info->signalIndex, d, index,
+ Qt::DirectConnection, 0);
+ if (info->destroyIndex >= 0) {
+ QMetaObject::connect(sender, info->destroyIndex, d, index + 1,
+ Qt::DirectConnection, 0);
+ }
+
+ // Add the signal information to the active list.
+ d->signalList.append(info);
+ return true;
+}
+
+bool XQServiceAdaptor::connectRemoteToLocal
+ (const QByteArray& signal, QObject *receiver, const QByteArray& member)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectRemoteToLocal");
+ XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+ XQSERVICE_DEBUG_PRINT("receiver->objectName(): %s", qPrintable(receiver->objectName()));
+ XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+ // Make sure that we are actively monitoring the channel for messages.
+ if (!d->connected) {
+ XQSERVICE_DEBUG_PRINT("Try to connect to channel");
+ QString chan = d->channelName;
+ // Short-cut the signal emits in XQServiceChannel for greater
+ // performance when dispatching incoming messages.
+ XQServiceAdaptorChannel* adaptorChannel = new XQServiceAdaptorChannel(chan, this);
+ bool ret = adaptorChannel ? adaptorChannel->connectChannel() : false;
+ XQSERVICE_DEBUG_PRINT("ret: %d", ret);
+ if (!ret) {
+ return ret;
+ }
+ d->connected = true;
+ }
+
+ // Create a slot invoker to handle executing the member when necessary.
+ XQServiceAdaptorSlotInfo *info = new XQServiceAdaptorSlotInfo();
+ QByteArray name;
+ if (member.size() > 0 && member[0] >= '0' && member[0] <= '9') {
+ // Strip off the member type code.
+ name = QMetaObject::normalizedSignature(member.constData() + 1);
+ } else {
+ name = QMetaObject::normalizedSignature(member.constData());
+ }
+ info->receiver = receiver;
+ info->returnType = 0;
+ info->types = 0;
+ info->numArgs = 0;
+ info->destroyed = false;
+ if (receiver && name.size() > 0) {
+ info->memberIndex
+ = receiver->metaObject()->indexOfMethod(name.constData());
+ XQSERVICE_DEBUG_PRINT("info->memberIndex: %d", info->memberIndex);
+ if (info->memberIndex != -1) {
+ connect(receiver, SIGNAL(destroyed()), this, SLOT(receiverDestroyed()));
+ QMetaMethod method = receiver->metaObject()->method(info->memberIndex);
+ info->returnType = XQServiceAdaptorPrivate::typeFromName(method.typeName());
+ info->types = XQServiceAdaptorPrivate::connectionTypes(name, info->numArgs);
+ if (!(info->types))
+ info->destroyed = true;
+ } else {
+ XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such member: %s::%s",
+ receiver->metaObject()->className(), name.constData());
+ }
+ } else {
+ info->memberIndex = -1;
+ }
+ if (info->memberIndex == -1) {
+ XQSERVICE_DEBUG_PRINT("No receiver");
+ delete info;
+ return false;
+ }
+ d->invokers.insert(memberToMessage(signal), info);
+ return true;
+}
+
+bool XQServiceAdaptor::sendMessage(const QString& msg, const QList<QVariant>& args, QVariant &retData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::sendMessage");
+ return send(d->channelName, msg, args, retData);
+}
+
+
+bool XQServiceAdaptor::send(const QString& channel,
+ const QString& msg,
+ const QList<QVariant>& args,
+ QVariant& retValue,
+ bool sync,
+ XQServiceRequestCompletedAsync* rc)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1). No user data");
+ return send(channel,msg,args,retValue,sync,rc,NULL);
+}
+
+bool XQServiceAdaptor::send(const QString& channel,
+ const QString& msg,
+ const QList<QVariant>& args,
+ QVariant& retValue,
+ bool sync,
+ XQServiceRequestCompletedAsync* rc,
+ const void *userData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
+ XQSERVICE_DEBUG_PRINT("channel: %s, sync: %d", qPrintable(channel), sync);
+ XQSERVICE_DEBUG_PRINT("msg: %s", qPrintable(msg));
+ XQSERVICE_DEBUG_PRINT("userdata: %x",(int)userData);
+ for(int i=0;i<args.size();++i){
+ XQSERVICE_DEBUG_PRINT("args[%d]:type=%s,value=%s", i, args[i].typeName(), qPrintable(args[i].toString()));
+ }
+ if (!sync && !rc) {
+ // Something wrong as no callback given
+ XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
+ return false;
+ }
+ QByteArray array;
+ QDataStream stream(&array, QIODevice::WriteOnly | QIODevice::Append);
+ QList<QVariant>::ConstIterator iter;
+ for (iter = args.begin(); iter != args.end(); ++iter) {
+ stream << *iter;
+ }
+ // Stream is flushed and closed at this point.
+ return XQServiceChannel::send(channel, msg, array, retValue, sync, rc, userData);
+}
+
+bool XQServiceAdaptor::cancelPendingSend(const QString& channel)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::cancelPendingSend");
+ return XQServiceChannel::cancelPendingSend(channel);
+}
+
+int XQServiceAdaptor::latestError()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::latestError");
+ return XQServiceChannel::latestError();
+}
+
+
+
+int XQServiceAdaptor::setCurrentRequestAsync()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::setCurrentRequestAsync");
+ XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+ return cl->setCurrentRequestAsync();
+}
+
+bool XQServiceAdaptor::completeRequest(int index, const QVariant& retValue)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::completeRequest");
+ XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+ return cl->completeRequest(index, retValue);
+}
+
+
+XQRequestInfo XQServiceAdaptor::requestInfo() const
+{
+ XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+ return cl->requestInfo();
+}
+
+#include "xqserviceadaptor.moc"