qthighway/tests/auto/xqservice/common/qsignalintercepter.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 "qsignalintercepter.h"
       
    23 #include <qmetaobject.h>
       
    24 #include <qmetatype.h>
       
    25 #include <qobjectdefs.h>
       
    26 
       
    27 /*!
       
    28     \class QSignalIntercepter
       
    29     \inpublicgroup QtBaseModule
       
    30 
       
    31     \brief The QSignalIntercepter class provides an interface for intercepting signals as meta-calls
       
    32 
       
    33     IPC mechanisms need to intercept signals and convert them into protocol
       
    34     messages, but it is generally impractical to create a slot for every
       
    35     signal that needs to be dispatched.  The QSignalIntercepter class allows
       
    36     signals to be intercepted as meta-calls so that IPC dispatching can
       
    37     be implemented in a generic fashion.
       
    38 
       
    39     The activated() method is called whenever the signal is emitted,
       
    40     with the arguments in a typed list.
       
    41 
       
    42     \sa QSlotInvoker
       
    43 
       
    44     \ingroup objectmodel
       
    45 */
       
    46 
       
    47 class QSignalIntercepterPrivate
       
    48 {
       
    49 public:
       
    50     QObject *sender;
       
    51     QByteArray signal;
       
    52     int signalIndex;
       
    53     int destroyIndex;
       
    54     int slotIndex;
       
    55     int *types;
       
    56     int numArgs;
       
    57 
       
    58     ~QSignalIntercepterPrivate()
       
    59     {
       
    60         if ( types )
       
    61             qFree( types );
       
    62     }
       
    63 };
       
    64 
       
    65 /*!
       
    66     Create a new signal intercepter which traps \a signal on \a sender.
       
    67     The object will be attached to \a parent, if present.
       
    68 */
       
    69 QSignalIntercepter::QSignalIntercepter
       
    70             ( QObject *sender, const QByteArray& signal, QObject *parent )
       
    71     : QObject( parent )
       
    72 {
       
    73     // Initialize the private members.
       
    74     d = new QSignalIntercepterPrivate();
       
    75     d->sender = sender;
       
    76     d->signal = signal;
       
    77     d->signalIndex = -1;
       
    78     d->destroyIndex = -1;
       
    79     d->slotIndex = -1;
       
    80     d->types = 0;
       
    81 
       
    82     // Resolve the indices of the signals we are interested in.
       
    83     if ( sender && signal.size() > 0 ) {
       
    84         // '2' is QSIGNAL_CODE in Qt 4.4 and below,
       
    85         // '6' is QSIGNAL_CODE in Qt 4.5 and higher.
       
    86         if ( signal[0] != '2' && signal[0] != '6' ) {
       
    87             qWarning( "QSignalIntercepter: `%s' is not a valid signal "
       
    88                       "specification", signal.constData() );
       
    89             return;
       
    90         }
       
    91         QByteArray name = QMetaObject::normalizedSignature
       
    92             ( signal.constData() + 1 );
       
    93         d->signalIndex
       
    94             = sender->metaObject()->indexOfSignal( name.constData() );
       
    95         if ( d->signalIndex < 0 ) {
       
    96             qWarning( "QSignalIntercepter: no such signal: %s::%s",
       
    97                       sender->metaObject()->className(), signal.constData() );
       
    98             return;
       
    99         }
       
   100         d->destroyIndex
       
   101             = sender->metaObject()->indexOfSignal( "destroyed()" );
       
   102         d->types = connectionTypes( name, d->numArgs );
       
   103     }
       
   104 
       
   105     // Derive a fake slot index to use in our manual qt_metacall implementation.
       
   106     d->slotIndex = staticMetaObject.methodCount();
       
   107 
       
   108     // Connect up the signals.
       
   109     if ( d->signalIndex >= 0 ) {
       
   110         QMetaObject::connect( sender, d->signalIndex,
       
   111                               this, d->slotIndex,
       
   112                               Qt::DirectConnection, 0 );
       
   113     }
       
   114     if ( d->destroyIndex >= 0 ) {
       
   115         QMetaObject::connect( sender, d->destroyIndex,
       
   116                               this, d->slotIndex + 1,
       
   117                               Qt::DirectConnection, 0 );
       
   118     }
       
   119 }
       
   120 
       
   121 /*!
       
   122     Destroy a signal intercepter.
       
   123 */
       
   124 QSignalIntercepter::~QSignalIntercepter()
       
   125 {
       
   126     if ( d->signalIndex >= 0 ) {
       
   127         QMetaObject::disconnect( d->sender, d->signalIndex,
       
   128                                  this, d->slotIndex );
       
   129     }
       
   130     if ( d->destroyIndex >= 0 ) {
       
   131         QMetaObject::disconnect( d->sender, d->destroyIndex,
       
   132                                  this, d->slotIndex + 1 );
       
   133     }
       
   134     delete d;
       
   135 }
       
   136 
       
   137 /*!
       
   138     Returns the sender that this signal interceptor is attached to.
       
   139 */
       
   140 QObject *QSignalIntercepter::sender() const
       
   141 {
       
   142     return d->sender;
       
   143 }
       
   144 
       
   145 /*!
       
   146     Returns the name of the signal that this signal interceptor is attached to.
       
   147 */
       
   148 QByteArray QSignalIntercepter::signal() const
       
   149 {
       
   150     return d->signal;
       
   151 }
       
   152 
       
   153 /*!
       
   154     Returns true if this signal intercepter is valid; that is, there was
       
   155     a signal present with the specified parameters when this object
       
   156     was constructed.
       
   157 */
       
   158 bool QSignalIntercepter::isValid() const
       
   159 {
       
   160     return ( d->signalIndex != -1 );
       
   161 }
       
   162 
       
   163 /*!
       
   164     \internal
       
   165 */
       
   166 int QSignalIntercepter::qt_metacall(QMetaObject::Call c, int id, void **a)
       
   167 {
       
   168     id = QObject::qt_metacall(c, id, a);
       
   169     if (id < 0)
       
   170         return id;
       
   171     if (c == QMetaObject::InvokeMetaMethod) {
       
   172         switch (id) {
       
   173             case 0: {
       
   174                 // The signal we are interested in has been activated.
       
   175                 if ( d->types ) {
       
   176                     QList<QVariant> args;
       
   177                     for ( int i = 0; i < d->numArgs; ++i ) {
       
   178                         if ( d->types[i] != QVariantId ) {
       
   179                             QVariant arg( d->types[i], a[i + 1] );
       
   180                             args.append( arg );
       
   181                         } else {
       
   182                             args.append( *((const QVariant *)( a[i + 1] )) );
       
   183                         }
       
   184                     }
       
   185                     activated( args );
       
   186                 }
       
   187             }
       
   188             break;
       
   189 
       
   190             case 1: {
       
   191                 // The sender has been destroyed.  Clear the signal indices
       
   192                 // so that we don't try to do a manual disconnect when our
       
   193                 // own destructor is called.
       
   194                 d->signalIndex = -1;
       
   195                 d->destroyIndex = -1;
       
   196             }
       
   197             break;
       
   198         }
       
   199         id -= 2;
       
   200     }
       
   201     return id;
       
   202 }
       
   203 
       
   204 /*!
       
   205     \fn void QSignalIntercepter::activated( const QList<QVariant>& args )
       
   206 
       
   207     Called when the signal that is being intercepted is activated.
       
   208     The arguments to the signal are passed in the list \a args.
       
   209 */
       
   210 
       
   211 // Get the QVariant type number for a type name.
       
   212 int QSignalIntercepter::typeFromName( const QByteArray& type )
       
   213 {
       
   214     int id;
       
   215     if (type.endsWith('*'))
       
   216         return QMetaType::VoidStar;
       
   217     else if ( type.size() == 0 || type == "void" )
       
   218         return QMetaType::Void;
       
   219     else if ( type == "QVariant" )
       
   220         return QSignalIntercepter::QVariantId;
       
   221     id = QMetaType::type( type.constData() );
       
   222     if ( id != (int)QMetaType::Void )
       
   223         return id;
       
   224     return QVariant::nameToType(type);
       
   225 }
       
   226 
       
   227 /*!
       
   228     Returns the connection types associated with a signal or slot \a member
       
   229     specification.  The array of types is returned from this function,
       
   230     and the number of arguments is returned in \a nargs.  Returns null
       
   231     if \a member is invalid.  The return value must be freed with qFree().
       
   232 */
       
   233 int *QSignalIntercepter::connectionTypes( const QByteArray& member, int& nargs )
       
   234 {
       
   235     // Based on Qt's internal queuedConnectionTypes function.
       
   236     nargs = 0;
       
   237     int *types = 0;
       
   238     const char *s = member.constData();
       
   239     while (*s != '\0' && *s != '(') { ++s; }
       
   240     if ( *s == '\0' )
       
   241         return 0;
       
   242     ++s;
       
   243     const char *e = s;
       
   244     while (*e != ')') {
       
   245         ++e;
       
   246         if (*e == ')' || *e == ',')
       
   247             ++nargs;
       
   248     }
       
   249 
       
   250     types = (int *) qMalloc((nargs+1)*sizeof(int));
       
   251     types[nargs] = 0;
       
   252     for (int n = 0; n < nargs; ++n) {
       
   253         e = s;
       
   254         while (*s != ',' && *s != ')')
       
   255             ++s;
       
   256         QByteArray type(e, s-e);
       
   257         ++s;
       
   258 
       
   259         types[n] = typeFromName(type);
       
   260         if (!types[n]) {
       
   261             qWarning("QSignalIntercepter::connectionTypes: Cannot marshal arguments of type '%s'", type.data());
       
   262             qFree(types);
       
   263             return 0;
       
   264         }
       
   265     }
       
   266     return types;
       
   267 }