qthighway/tests/auto/xqservice/common/qslotinvoker.cpp
changeset 18 1b485afba084
parent 16 19b186e43276
child 28 19321a443c34
equal deleted inserted replaced
16:19b186e43276 18:1b485afba084
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * This program is free software: you can redistribute it and/or modify
       
     6 * it under the terms of the GNU Lesser General Public License as published by
       
     7 * the Free Software Foundation, version 2.1 of the License.
       
     8 * 
       
     9 * This program is distributed in the hope that it will be useful,
       
    10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 * GNU Lesser General Public License for more details.
       
    13 *
       
    14 * You should have received a copy of the GNU Lesser General Public License
       
    15 * along with this program.  If not, 
       
    16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
       
    17 *
       
    18 * Description:                                                         
       
    19 *
       
    20 */ 
       
    21 
       
    22 #include "qslotinvoker.h"
       
    23 #include "qsignalintercepter.h"
       
    24 #include <qmetaobject.h>
       
    25 #include <qmetatype.h>
       
    26 #include <qvarlengtharray.h>
       
    27 
       
    28 /*!
       
    29     \class QSlotInvoker
       
    30     \inpublicgroup QtBaseModule
       
    31 
       
    32     \brief The QSlotInvoker class provides an interface for invoking slots with explicit arguments
       
    33 
       
    34     IPC mechanisms need to intercept protocol messages and convert them into
       
    35     slot invocations, but it is generally impractical to create explicit code
       
    36     for every slot that needs to be dispatched.  The QSlotInvoker class allows
       
    37     an IPC dispatching mechanism to invoke slots in a generic fashion using
       
    38     the invoke() method.
       
    39 
       
    40     Methods that are marked with Q_INVOKABLE or Q_SCRIPTABLE can also
       
    41     be invoked with this class.
       
    42 
       
    43     \sa QSignalIntercepter
       
    44 
       
    45     \ingroup objectmodel
       
    46 */
       
    47 
       
    48 class QSlotInvokerPrivate
       
    49 {
       
    50 public:
       
    51     QObject *receiver;
       
    52     QByteArray member;
       
    53     int memberIndex;
       
    54     bool destroyed;
       
    55     int returnType;
       
    56     int *types;
       
    57     int numArgs;
       
    58 
       
    59     ~QSlotInvokerPrivate()
       
    60     {
       
    61         if ( types )
       
    62             qFree( types );
       
    63     }
       
    64 };
       
    65 
       
    66 /*!
       
    67     Create a slot invoker that can invoke \a member on \a receiver.
       
    68     The object will be attached to \a parent, if present.
       
    69 */
       
    70 QSlotInvoker::QSlotInvoker( QObject *receiver, const QByteArray &member,
       
    71                             QObject *parent )
       
    72     : QObject( parent )
       
    73 {
       
    74     d = new QSlotInvokerPrivate();
       
    75     d->receiver = receiver;
       
    76     QByteArray name;
       
    77     if ( member.size() > 0 && member[0] >= '0' && member[0] <= '9' ) {
       
    78         // Strip off the member type code.
       
    79         name = member.mid(1);
       
    80     } else {
       
    81         name = member;
       
    82     }
       
    83     name = QMetaObject::normalizedSignature( name.constData() );
       
    84     d->member = name;
       
    85     d->destroyed = false;
       
    86     d->returnType = 0;
       
    87     d->types = 0;
       
    88     d->numArgs = 0;
       
    89     if ( receiver && name.size() > 0 ) {
       
    90         d->memberIndex
       
    91             = receiver->metaObject()->indexOfMethod( name.constData() );
       
    92     } else {
       
    93         d->memberIndex = -1;
       
    94     }
       
    95     if ( d->memberIndex != -1 ) {
       
    96         QMetaMethod method = receiver->metaObject()->method
       
    97                 ( d->memberIndex );
       
    98         {
       
    99             connect( receiver, SIGNAL(destroyed()),
       
   100                      this, SLOT(receiverDestroyed()) );
       
   101             d->returnType =
       
   102                 QSignalIntercepter::typeFromName( method.typeName() );
       
   103             d->types = QSignalIntercepter::connectionTypes
       
   104                 ( name, d->numArgs );
       
   105             if ( !( d->types ) )
       
   106                 d->destroyed = true;
       
   107         }
       
   108     } else {
       
   109         d->destroyed = true;
       
   110     }
       
   111 }
       
   112 
       
   113 /*!
       
   114     Destroy a slot invoker.
       
   115 */
       
   116 QSlotInvoker::~QSlotInvoker()
       
   117 {
       
   118     delete d;
       
   119 }
       
   120 
       
   121 /*!
       
   122     Returns true if the member is present on the object.
       
   123 */
       
   124 bool QSlotInvoker::memberPresent() const
       
   125 {
       
   126     return ! d->destroyed;
       
   127 }
       
   128 
       
   129 /*!
       
   130     Returns true if the member can be invoked with \a numArgs arguments.
       
   131     That is, the receiver has not been destroyed, the member is present,
       
   132     and it requires \a numArgs or less arguments.
       
   133 */
       
   134 bool QSlotInvoker::canInvoke( int numArgs ) const
       
   135 {
       
   136     if ( d->destroyed )
       
   137         return false;
       
   138     return ( numArgs >= d->numArgs );
       
   139 }
       
   140 
       
   141 /*!
       
   142     Returns the object that will receive slot invocations.
       
   143 */
       
   144 QObject *QSlotInvoker::receiver() const
       
   145 {
       
   146     return d->receiver;
       
   147 }
       
   148 
       
   149 /*!
       
   150     Returns the member that will receiver slot invocations.
       
   151 */
       
   152 QByteArray QSlotInvoker::member() const
       
   153 {
       
   154     return d->member;
       
   155 }
       
   156 
       
   157 /*!
       
   158     Returns the parameter types associated with this member.
       
   159 */
       
   160 int *QSlotInvoker::parameterTypes() const
       
   161 {
       
   162     return d->types;
       
   163 }
       
   164 
       
   165 /*!
       
   166     Returns the number of parameter types associated with this member.
       
   167 */
       
   168 int QSlotInvoker::parameterTypesCount() const
       
   169 {
       
   170     return d->numArgs;
       
   171 }
       
   172 
       
   173 /*!
       
   174     Invokes the slot represented by this object with the argument
       
   175     list \a args.  The slot's return value is returned from
       
   176     this method.  If the slot's return type is "void", then a
       
   177     QVariant instance of type QVariant::Invalid will be returned.
       
   178 
       
   179     If it is possible that the slot may throw an exception,
       
   180     it is the responsibility of the caller to catch and
       
   181     handle the exception.
       
   182 */
       
   183 QVariant QSlotInvoker::invoke( const QList<QVariant>& args )
       
   184 {
       
   185     int arg;
       
   186     QVariant returnValue;
       
   187 
       
   188     // Create a default instance of the return type for the result buffer.
       
   189     if ( d->returnType != (int)QVariant::Invalid ) {
       
   190         returnValue = QVariant( d->returnType, (const void *)0 );
       
   191     }
       
   192 
       
   193     // Bail out if the receiver object has already disappeared.
       
   194     if ( d->destroyed )
       
   195         return returnValue;
       
   196 
       
   197     // Check that the number of arguments is compatible with the slot.
       
   198     int numArgs = args.size();
       
   199     if ( numArgs < d->numArgs ) {
       
   200         qWarning( "QSlotInvoker::invoke: insufficient arguments for slot" );
       
   201         return returnValue;
       
   202     } else if ( numArgs > d->numArgs ) {
       
   203         // Drop extraneous arguments.
       
   204         numArgs = d->numArgs;
       
   205     }
       
   206 
       
   207     // Construct the raw argument list.
       
   208     QVarLengthArray<void *, 32> a( numArgs + 1 );
       
   209     if ( d->returnType == (int)QVariant::Invalid )
       
   210         a[0] = 0;
       
   211     else
       
   212         a[0] = returnValue.data();
       
   213     for ( arg = 0; arg < numArgs; ++arg ) {
       
   214         if ( d->types[arg] == QSignalIntercepter::QVariantId ) {
       
   215             a[arg + 1] = (void *)&( args[arg] );
       
   216         } else if ( args[arg].userType() != d->types[arg] ) {
       
   217             qWarning( "QSlotInvoker::invoke: argument %d has incorrect type",
       
   218                       arg );
       
   219             return QVariant();
       
   220         } else {
       
   221             a[arg + 1] = (void *)( args[arg].data() );
       
   222         }
       
   223     }
       
   224 
       
   225     // Invoke the specified slot.
       
   226     d->receiver->qt_metacall( QMetaObject::InvokeMetaMethod,
       
   227                                      d->memberIndex, a.data() );
       
   228     return returnValue;
       
   229 }
       
   230 
       
   231 void QSlotInvoker::receiverDestroyed()
       
   232 {
       
   233     d->destroyed = true;
       
   234 }