src/corelib/kernel/qobject.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qobject.h"
00025 #include "qobject_p.h"
00026 
00027 #include "qabstracteventdispatcher.h"
00028 #include "qcoreapplication.h"
00029 #include "qcoreapplication_p.h"
00030 #include "qvariant.h"
00031 #include "qmetaobject.h"
00032 #include <qregexp.h>
00033 #include <qthread.h>
00034 #include <private/qthread_p.h>
00035 #include <qdebug.h>
00036 #include <qhash.h>
00037 #include <qpair.h>
00038 #include <qvarlengtharray.h>
00039 #include <qset.h>
00040 
00041 #include <new>
00042 
00043 #include <ctype.h>
00044 #include <limits.h>
00045 
00046 static int DIRECT_CONNECTION_ONLY = 0;
00047 
00048 Q_GLOBAL_STATIC(QReadWriteLock, qt_object_read_write_lock)
00049 QReadWriteLock *QObjectPrivate::readWriteLock() { return qt_object_read_write_lock(); }
00050 
00051 static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
00052 {
00053     int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int)));
00054     for (int i = 0; i < typeNames.count(); ++i) {
00055         const QByteArray typeName = typeNames.at(i);
00056         if (typeName.endsWith('*'))
00057             types[i] = QMetaType::VoidStar;
00058         else
00059             types[i] = QMetaType::type(typeName);
00060 
00061         if (!types[i]) {
00062             qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
00063                      "(Make sure '%s' is registed using qRegisterMetaType().)",
00064                      typeName.constData(), typeName.constData());
00065             qFree(types);
00066             return 0;
00067         }
00068     }
00069     types[typeNames.count()] = 0;
00070 
00071     return types;
00072 }
00073 
00074 struct QConnection {
00075     QObject *sender;
00076     int signal;
00077     QObject *receiver;
00078     int method;
00079     uint refCount:30;
00080     uint type:2; // 0 == auto, 1 == direct, 2 == queued
00081     int *types;
00082 };
00083 Q_DECLARE_TYPEINFO(QConnection, Q_MOVABLE_TYPE);
00084 
00085 class QConnectionList
00086 {
00087 public:
00088     QReadWriteLock lock;
00089 
00090     typedef QMultiHash<const QObject *, int> Hash;
00091     Hash sendersHash, receiversHash;
00092     QList<int> unusedConnections;
00093     typedef QList<QConnection> List;
00094     List connections;
00095 
00096     void remove(QObject *object);
00097 
00098     void addConnection(QObject *sender, int signal,
00099                        QObject *receiver, int method,
00100                        int type = 0, int *types = 0);
00101     bool removeConnection(QObject *sender, int signal,
00102                           QObject *receiver, int method);
00103 };
00104 
00105 Q_GLOBAL_STATIC(QConnectionList, connectionList)
00106 
00107 
00112 void QConnectionList::remove(QObject *object)
00113 {
00114     for (int i = 0; i < 2; ++i) {
00115         Hash &hash1 = i == 0 ? sendersHash : receiversHash;
00116         Hash &hash2 = i == 0 ? receiversHash : sendersHash;
00117 
00118         Hash::iterator it = hash1.find(object);
00119         const Hash::iterator end = hash1.end();
00120         while (it != end && it.key() == object) {
00121             const int at = it.value();
00122             QConnection &c = connections[at];
00123             if (c.sender) {
00124                 if (c.types && c.types != &DIRECT_CONNECTION_ONLY) {
00125                     qFree(c.types);
00126                     c.types = 0;
00127                 }
00128                 it = hash1.erase(it);
00129 
00130                 const QObject * const partner = i == 0 ? c.receiver : c.sender;
00131                 Hash::iterator x = hash2.find(partner);
00132                 const Hash::iterator xend = hash2.end();
00133                 while (x != xend && x.key() == partner) {
00134                     if (x.value() == at) {
00135                         x = hash2.erase(x);
00136                         break;
00137                     } else {
00138                         ++x;
00139                     }
00140                 }
00141 
00142                 uint refCount = c.refCount;
00143                 memset(&c, 0, sizeof(c));
00144                 c.refCount = refCount;
00145                 Q_ASSERT(!unusedConnections.contains(at));
00146                 unusedConnections.prepend(at);
00147             } else {
00148                 ++it;
00149             }
00150         }
00151     }
00152 }
00153 
00157 void QConnectionList::addConnection(QObject *sender, int signal,
00158                                     QObject *receiver, int method,
00159                                     int type, int *types)
00160 {
00161     QConnection c = { sender, signal, receiver, method, 0, 0, types };
00162     c.type = type; // don't warn on VC++6
00163     int at = -1;
00164     for (int i = 0; i < unusedConnections.size(); ++i) {
00165         if (!connections.at(unusedConnections.at(i)).refCount) {
00166             // reuse an unused connection
00167             at = unusedConnections.takeAt(i);
00168             connections[at] = c;
00169             break;
00170         }
00171     }
00172     if (at == -1) {
00173         // append new connection
00174         at = connections.size();
00175         connections << c;
00176     }
00177     sendersHash.insert(sender, at);
00178     receiversHash.insert(receiver, at);
00179 }
00180 
00186 bool QConnectionList::removeConnection(QObject *sender, int signal,
00187                                        QObject *receiver, int method)
00188 {
00189     bool success = false;
00190     Hash::iterator it = sendersHash.find(sender);
00191     while (it != sendersHash.end() && it.key() == sender) {
00192         const int at = it.value();
00193         QConnection &c = connections[at];
00194         if (c.receiver
00195             && (signal < 0 || signal == c.signal)
00196             && (receiver == 0
00197                 || (c.receiver == receiver && (method < 0 || method == c.method)))) {
00198             if (c.types) {
00199                 if (c.types != &DIRECT_CONNECTION_ONLY)
00200                     qFree(c.types);
00201                 c.types = 0;
00202             }
00203             it = sendersHash.erase(it);
00204 
00205             Hash::iterator x = receiversHash.find(c.receiver);
00206             const Hash::iterator xend = receiversHash.end();
00207             while (x != xend && x.key() == c.receiver) {
00208                 if (x.value() == at) {
00209                     x = receiversHash.erase(x);
00210                     break;
00211                 } else {
00212                     ++x;
00213                 }
00214             }
00215 
00216             uint refCount = c.refCount;
00217             memset(&c, 0, sizeof(c));
00218             c.refCount = refCount;
00219             unusedConnections << at;
00220             success = true;
00221         } else {
00222             ++it;
00223         }
00224     }
00225     return success;
00226 }
00227 
00228 /*
00229   QObjectSet sets the minimum capacity to 4099 (the first prime number
00230   after 4096), so that we can speed up QObject destruction.
00231  */
00232 class QObjectSet : public QSet<QObject *>
00233 {
00234 public:
00235     QObjectSet()
00236     { reserve(4099); }
00237 };
00238 
00239 Q_GLOBAL_STATIC(QObjectSet, allObjects)
00240 
00241 extern "C" Q_CORE_EXPORT void qt_addObject(QObject *object)
00242 {
00243     QWriteLocker locker(QObjectPrivate::readWriteLock());
00244     QObjectSet *set = allObjects();
00245     if (set)
00246         set->insert(object);
00247 }
00248 
00249 extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *object)
00250 {
00251     QObjectSet *set = allObjects();
00252     if (set)
00253         set->remove(object);
00254 }
00255 
00256 #ifdef Q_CC_MSVC
00257 #pragma warning(push)
00258 #pragma warning(disable:4190)
00259 #endif
00260 
00261 extern "C" Q_CORE_EXPORT QList<QObject *> qt_allTopLevelWidgets()
00262 {
00263     QList<QObject *> list;
00264 
00265     QReadLocker locker(QObjectPrivate::readWriteLock());
00266     const QObjectSet *set = allObjects();
00267     if (!set)
00268         return list;
00269 
00270     for (QSet<QObject *>::const_iterator it = set->constBegin(); it != set->constEnd(); ++it) {
00271         if ((*it)->isWidgetType() && !(*it)->parent())
00272             list << *it;
00273     }
00274 
00275     return list;
00276 }
00277 
00278 #ifdef Q_CC_MSVC
00279 #pragma warning(pop)
00280 #endif
00281 
00282 bool QObjectPrivate::isValidObject(QObject *object)
00283 {
00284     QObjectSet *set = allObjects();
00285     return set ? set->contains(object) : false;
00286 }
00287 
00288 QObjectPrivate::QObjectPrivate(int version)
00289     : threadData(0), currentSender(0), currentSenderSignalIdStart(-1), currentSenderSignalIdEnd(-1)
00290 {
00291     if (version != QObjectPrivateVersion)
00292         qFatal("Cannot mix incompatible Qt libraries");
00293 
00294     // QObjectData initialization
00295     q_ptr = 0;
00296     parent = 0;                                 // no parent yet. It is set by setParent()
00297     isWidget = false;                           // assume not a widget object
00298     pendTimer = false;                          // no timers yet
00299     blockSig = false;                           // not blocking signals
00300     wasDeleted = false;                         // double-delete catcher
00301     sendChildEvents = true;                     // if we should send ChildInsert and ChildRemove events to parent
00302     receiveChildEvents = true;
00303     postedEvents = 0;
00304 #ifdef QT3_SUPPORT
00305     postedChildInsertedEvents = 0;
00306 #endif
00307     extraData = 0;
00308 }
00309 
00310 QObjectPrivate::~QObjectPrivate()
00311 {
00312 #ifndef QT_NO_USERDATA
00313     if (extraData)
00314         qDeleteAll(extraData->userData);
00315     delete extraData;
00316 #endif
00317 }
00318 
00319 bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
00320 {
00321     Q_Q(const QObject);
00322     int signal_index = q->metaObject()->indexOfSignal(signal);
00323     if (signal_index < 0)
00324         return false;
00325     QConnectionList *list = ::connectionList();
00326     QReadLocker locker(&list->lock);
00327     QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(q);
00328     while (it != list->sendersHash.constEnd() && it.key() == q) {
00329         const QConnection &c = list->connections.at(it.value());
00330         if (c.signal == signal_index && c.receiver == receiver)
00331             return true;
00332         ++it;
00333     }
00334     return false;
00335 }
00336 
00337 QObjectList QObjectPrivate::receiverList(const char *signal) const
00338 {
00339     Q_Q(const QObject);
00340     QObjectList receivers;
00341     int signal_index = q->metaObject()->indexOfSignal(signal);
00342     if (signal_index < 0)
00343         return receivers;
00344     QConnectionList *list = ::connectionList();
00345     QReadLocker locker(&list->lock);
00346     QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(q);
00347     while (it != list->sendersHash.constEnd() && it.key() == q) {
00348         const QConnection &c = list->connections.at(it.value());
00349         if (c.signal == signal_index)
00350             receivers << c.receiver;
00351         ++it;
00352     }
00353     return receivers;
00354 }
00355 
00356 QObjectList QObjectPrivate::senderList() const
00357 {
00358     Q_Q(const QObject);
00359     QObjectList senders;
00360     QConnectionList *list = ::connectionList();
00361     QReadLocker locker(&list->lock);
00362     QConnectionList::Hash::const_iterator it = list->receiversHash.constFind(q);
00363     while (it != list->receiversHash.constEnd() && it.key() == q) {
00364         const QConnection &c = list->connections.at(it.value());
00365         senders << c.sender;
00366         ++it;
00367     }
00368     return senders;
00369 }
00370 
00371 typedef QMultiHash<QObject *, QObject **> GuardHash;
00372 Q_GLOBAL_STATIC(GuardHash, guardHash)
00373 Q_GLOBAL_STATIC(QReadWriteLock, guardHashLock)
00374 
00377 void QMetaObject::addGuard(QObject **ptr)
00378 {
00379     if (!*ptr)
00380         return;
00381     GuardHash *hash = guardHash();
00382     if (!hash) {
00383         *ptr = 0;
00384         return;
00385     }
00386     QWriteLocker locker(guardHashLock());
00387     hash->insert(*ptr, ptr);
00388 }
00389 
00392 void QMetaObject::removeGuard(QObject **ptr)
00393 {
00394     if (!*ptr)
00395         return;
00396     GuardHash *hash = guardHash();
00397     if (!hash)
00398         return;
00399     QWriteLocker locker(guardHashLock());
00400     GuardHash::iterator it = hash->find(*ptr);
00401     const GuardHash::iterator end = hash->end();
00402     for (; it.key() == *ptr && it != end; ++it) {
00403         if (it.value() == ptr) {
00404             (void) hash->erase(it);
00405             break;
00406         }
00407     }
00408 }
00409 
00412 void QMetaObject::changeGuard(QObject **ptr, QObject *o)
00413 {
00414     GuardHash *hash = guardHash();
00415     if (!hash) {
00416         *ptr = 0;
00417         return;
00418     }
00419     QWriteLocker locker(guardHashLock());
00420     if (*ptr) {
00421         GuardHash::iterator it = hash->find(*ptr);
00422         const GuardHash::iterator end = hash->end();
00423         for (; it.key() == *ptr && it != end; ++it) {
00424             if (it.value() == ptr) {
00425                 (void) hash->erase(it);
00426                 break;
00427             }
00428         }
00429     }
00430     *ptr = o;
00431     if (*ptr)
00432         hash->insert(*ptr, ptr);
00433 }
00434 
00437 void QObjectPrivate::clearGuards(QObject *object)
00438 {
00439     GuardHash *hash = ::guardHash();
00440     if (hash) {
00441         QWriteLocker locker(guardHashLock());
00442         GuardHash::iterator it = hash->find(object);
00443         const GuardHash::iterator end = hash->end();
00444         while (it.key() == object && it != end) {
00445             *it.value() = 0;
00446             it = hash->erase(it);
00447         }
00448     }
00449 }
00450 
00453 QMetaCallEvent::QMetaCallEvent(int id, const QObject *sender,
00454                                int nargs, int *types, void **args)
00455     :QEvent(MetaCall), id_(id), sender_(sender), idFrom_(-1), idTo_(-1),
00456      nargs_(nargs), types_(types), args_(args)
00457 { }
00458 
00461 QMetaCallEvent::QMetaCallEvent(int id, const QObject *sender, int idFrom, int idTo,
00462                                int nargs, int *types, void **args)
00463     : QEvent(MetaCall), id_(id), sender_(sender), idFrom_(idFrom), idTo_(idTo),
00464       nargs_(nargs), types_(types), args_(args)
00465 { }
00466 
00469 QMetaCallEvent::~QMetaCallEvent()
00470 {
00471     for (int i = 0; i < nargs_; ++i) {
00472         if (types_[i] && args_[i])
00473             QMetaType::destroy(types_[i], args_[i]);
00474     }
00475     if (types_) qFree(types_);
00476     if (args_) qFree(args_);
00477 }
00478 
00579 void *qt_find_obj_child(QObject *parent, const char *type, const QString &name)
00580 {
00581     QObjectList list = parent->children();
00582     if (list.size() == 0) return 0;
00583     for (int i = 0; i < list.size(); ++i) {
00584         QObject *obj = list.at(i);
00585         if (name == obj->objectName() && obj->inherits(type))
00586             return obj;
00587     }
00588     return 0;
00589 }
00590 
00591 
00592 /*****************************************************************************
00593   QObject member functions
00594  *****************************************************************************/
00595 
00611 QObject::QObject(QObject *parent)
00612     : d_ptr(new QObjectPrivate)
00613 {
00614     Q_D(QObject);
00615     ::qt_addObject(d_ptr->q_ptr = this);
00616     d->threadData = QThreadData::current();
00617     d->threadData->ref();
00618     if (parent && parent->d_func()->threadData != d->threadData) {
00619         qWarning("QObject: Cannot create children for a parent that is in a different thread.");
00620         parent = 0;
00621     }
00622     setParent(parent);
00623 }
00624 
00625 #ifdef QT3_SUPPORT
00626 
00632 QObject::QObject(QObject *parent, const char *name)
00633     : d_ptr(new QObjectPrivate)
00634 {
00635     Q_D(QObject);
00636     ::qt_addObject(d_ptr->q_ptr = this);
00637     d->threadData = QThreadData::current();
00638     d->threadData->ref();
00639     if (parent && parent->d_func()->threadData != d->threadData) {
00640         qWarning("QObject: Cannot create children for a parent that is in a different thread.");
00641         parent = 0;
00642     }
00643     setParent(parent);
00644     setObjectName(QString::fromAscii(name));
00645 }
00646 #endif
00647 
00650 QObject::QObject(QObjectPrivate &dd, QObject *parent)
00651     : d_ptr(&dd)
00652 {
00653     Q_D(QObject);
00654     ::qt_addObject(d_ptr->q_ptr = this);
00655     d->threadData = QThreadData::current();
00656     d->threadData->ref();
00657     if (parent && parent->d_func()->threadData != d->threadData) {
00658         qWarning("QObject: Cannot create children for a parent that is in a different thread.");
00659         parent = 0;
00660     }
00661     if (d->isWidget) {
00662         if (parent) {
00663             d->parent = parent;
00664             d->parent->d_func()->children.append(this);
00665         }
00666         // no events sent here, this is done at the end of the QWidget constructor
00667     } else {
00668         setParent(parent);
00669     }
00670 }
00671 
00696 QObject::~QObject()
00697 {
00698     Q_D(QObject);
00699     if (d->wasDeleted) {
00700 #if defined(QT_DEBUG)
00701         qWarning("QObject: Double deletion detected");
00702 #endif
00703         return;
00704     }
00705     d->wasDeleted = true;
00706 
00707     d->blockSig = 0; // unblock signals so we always emit destroyed()
00708 
00709     if (!d->isWidget) {
00710         // set all QPointers for this object to zero - note that
00711         // ~QWidget() does this for us, so we don't have to do it twice
00712         QObjectPrivate::clearGuards(this);
00713      }
00714 
00715     emit destroyed(this);
00716 
00717     QConnectionList *list = ::connectionList();
00718     if (list) {
00719         QWriteLocker locker(&list->lock);
00720         list->remove(this);
00721     }
00722 
00723     if (d->pendTimer) {
00724         // unregister pending timers
00725         if (d->threadData->eventDispatcher)
00726             d->threadData->eventDispatcher->unregisterTimers(this);
00727     }
00728 
00729     d->eventFilters.clear();
00730 
00731     if (!d->children.isEmpty())
00732         d->deleteChildren();
00733 
00734     {
00735         QWriteLocker locker(QObjectPrivate::readWriteLock());
00736         ::qt_removeObject(this);
00737 
00738         /*
00739           theoretically, we cannot check d->postedEvents without
00740           holding the postEventList.mutex for the object's thread,
00741           but since we hold the QObjectPrivate::readWriteLock(),
00742           nothing can go into QCoreApplication::postEvent(), which
00743           effectively means no one can post new events, which is what
00744           we are trying to prevent. this means we can safely check
00745           d->postedEvents, since we are fairly sure it will not
00746           change (it could, but only by decreasing, i.e. removing
00747           posted events from a differebnt thread)
00748         */
00749         if (d->postedEvents > 0)
00750             QCoreApplication::removePostedEvents(this);
00751     }
00752 
00753     if (d->parent)        // remove it from parent object
00754         d->setParent_helper(0);
00755 
00756     d->threadData->deref();
00757 
00758     delete d;
00759     d_ptr = 0;
00760 }
00761 
00762 
00905 QString QObject::objectName() const
00906 {
00907     Q_D(const QObject);
00908     return d->objectName;
00909 }
00910 
00911 /*
00912     Sets the object's name to \a name.
00913 */
00914 void QObject::setObjectName(const QString &name)
00915 {
00916     Q_D(QObject);
00917     d->objectName = name;
00918 }
00919 
00920 
00921 #ifdef QT3_SUPPORT
00922 
00926 static QObject *qChildHelper(const char *objName, const char *inheritsClass,
00927                              bool recursiveSearch, const QObjectList &children)
00928 {
00929     if (children.isEmpty())
00930         return 0;
00931 
00932     bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget") == 0);
00933     const QLatin1String oName(objName);
00934     for (int i = 0; i < children.size(); ++i) {
00935         QObject *obj = children.at(i);
00936         if (onlyWidgets) {
00937             if (obj->isWidgetType() && (!objName || obj->objectName() == oName))
00938                 return obj;
00939         } else if ((!inheritsClass || obj->inherits(inheritsClass))
00940                    && (!objName || obj->objectName() == oName))
00941             return obj;
00942         if (recursiveSearch && (obj = qChildHelper(objName, inheritsClass,
00943                                                    recursiveSearch, obj->children())))
00944             return obj;
00945     }
00946     return 0;
00947 }
00948 
00949 
00962 QObject* QObject::child(const char *objName, const char *inheritsClass,
00963                          bool recursiveSearch) const
00964 {
00965     Q_D(const QObject);
00966     return qChildHelper(objName, inheritsClass, recursiveSearch, d->children);
00967 }
00968 #endif
00969 
00991 bool QObject::event(QEvent *e)
00992 {
00993     switch (e->type()) {
00994     case QEvent::Timer:
00995         timerEvent((QTimerEvent*)e);
00996         break;
00997 
00998     case QEvent::ChildAdded:
00999     case QEvent::ChildPolished:
01000 #ifdef QT3_SUPPORT
01001     case QEvent::ChildInserted:
01002 #endif
01003     case QEvent::ChildRemoved:
01004         childEvent((QChildEvent*)e);
01005         break;
01006 
01007     case QEvent::DeferredDelete:
01008         delete this;
01009         break;
01010 
01011     case QEvent::MetaCall:
01012         {
01013             Q_D(QObject);
01014             QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);
01015             QObject *previousSender = d->currentSender;
01016             int previousFrom = d->currentSenderSignalIdStart;
01017             int previousTo = d->currentSenderSignalIdEnd;
01018             d->currentSender = const_cast<QObject*>(mce->sender());
01019             d->currentSenderSignalIdStart = mce->signalIdStart();
01020             d->currentSenderSignalIdEnd = mce->signalIdEnd();
01021 #if defined(QT_NO_EXCEPTIONS)
01022             qt_metacall(QMetaObject::InvokeMetaMethod, mce->id(), mce->args());
01023 #else
01024             try {
01025                 qt_metacall(QMetaObject::InvokeMetaMethod, mce->id(), mce->args());
01026             } catch (...) {
01027                 QReadLocker locker(QObjectPrivate::readWriteLock());
01028                 if (QObjectPrivate::isValidObject(this)) {
01029                     d->currentSender = previousSender;
01030                     d->currentSenderSignalIdStart = previousFrom;
01031                     d->currentSenderSignalIdEnd = previousTo;
01032                 }
01033                 throw;
01034             }
01035 #endif
01036             QReadLocker locker(QObjectPrivate::readWriteLock());
01037             if (QObjectPrivate::isValidObject(this)) {
01038                 d->currentSender = previousSender;
01039                 d->currentSenderSignalIdStart = previousFrom;
01040                 d->currentSenderSignalIdEnd = previousTo;
01041             }
01042             break;
01043         }
01044 
01045     case QEvent::ThreadChange: {
01046         QThreadData *threadData = d_func()->threadData;
01047         QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher;
01048         if (eventDispatcher) {
01049             QList<QPair<int, int> > timers = eventDispatcher->registeredTimers(this);
01050             if (!timers.isEmpty()) {
01051                 eventDispatcher->unregisterTimers(this);
01052                 QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection,
01053                                           Q_ARG(void*, (new QList<QPair<int, int> >(timers))));
01054             }
01055         }
01056         break;
01057     }
01058 
01059     default:
01060         if (e->type() >= QEvent::User) {
01061             customEvent(e);
01062             break;
01063         }
01064         return false;
01065     }
01066     return true;
01067 }
01068 
01082 void QObject::timerEvent(QTimerEvent *)
01083 {
01084 }
01085 
01086 
01118 void QObject::childEvent(QChildEvent * /* event */)
01119 {
01120 }
01121 
01122 
01132 void QObject::customEvent(QEvent * /* event */)
01133 {
01134 }
01135 
01136 
01137 
01197 bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
01198 {
01199     return false;
01200 }
01201 
01225 bool QObject::blockSignals(bool block)
01226 {
01227     Q_D(QObject);
01228     bool previous = d->blockSig;
01229     d->blockSig = block;
01230     return previous;
01231 }
01232 
01238 QThread *QObject::thread() const
01239 {
01240     return d_func()->threadData->thread;
01241 }
01242 
01274 void QObject::moveToThread(QThread *targetThread)
01275 {
01276     Q_D(QObject);
01277 
01278     if (d->threadData->thread == targetThread) {
01279         // object is already in this thread
01280         return;
01281     }
01282 
01283     if (d->parent != 0) {
01284         qWarning("QObject::moveToThread: Cannot move objects with a parent");
01285         return;
01286     }
01287     if (d->isWidget) {
01288         qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
01289         return;
01290     }
01291 
01292     QThreadData *currentData = QThreadData::current();
01293     QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : new QThreadData(0);
01294     if (d->threadData->thread == 0 && currentData == targetData) {
01295         // one exception to the rule: we allow moving objects with no thread affinity to the current thread
01296         currentData = d->threadData;
01297     } else if (d->threadData != currentData) {
01298         qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
01299                  "Cannot move to target thread (%p)\n",
01300                  d->threadData->thread, currentData->thread, targetData->thread);
01301         return;
01302     }
01303 
01304     // prepare to move
01305     d->moveToThread_helper();
01306 
01307     QWriteLocker locker(QObjectPrivate::readWriteLock());
01308     if (currentData != targetData) {
01309         targetData->postEventList.mutex.lock();
01310         while (currentData && !currentData->postEventList.mutex.tryLock()) {
01311             targetData->postEventList.mutex.unlock();
01312             targetData->postEventList.mutex.lock();
01313         }
01314     }
01315 
01316     // keep currentData alive (since we've got it locked)
01317     currentData->ref();
01318 
01319     // move the object
01320     d_func()->setThreadData_helper(currentData, targetData);
01321 
01322     if (currentData != targetData) {
01323         targetData->postEventList.mutex.unlock();
01324         if (currentData)
01325             currentData->postEventList.mutex.unlock();
01326     }
01327 
01328     // now currentData can commit suicide if it wants to
01329     currentData->deref();
01330 }
01331 
01332 void QObjectPrivate::moveToThread_helper()
01333 {
01334     Q_Q(QObject);
01335     QEvent e(QEvent::ThreadChange);
01336     QCoreApplication::sendEvent(q, &e);
01337     for (int i = 0; i < children.size(); ++i) {
01338         QObject *child = children.at(i);
01339         child->d_func()->moveToThread_helper();
01340     }
01341 }
01342 
01343 void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
01344 {
01345     Q_Q(QObject);
01346 
01347     // move posted events
01348     int eventsMoved = 0;
01349     for (int i = 0; i < currentData->postEventList.size(); ++i) {
01350         const QPostEvent &pe = currentData->postEventList.at(i);
01351         if (!pe.event)
01352             continue;
01353         if (pe.receiver == q) {
01354             // move this post event to the targetList
01355             targetData->postEventList.append(pe);
01356             const_cast<QPostEvent &>(pe).event = 0;
01357             ++eventsMoved;
01358         }
01359     }
01360     if (eventsMoved > 0 && targetData->eventDispatcher)
01361         targetData->eventDispatcher->wakeUp();
01362 
01363     // set new thread data
01364     targetData->ref();
01365     threadData->deref();
01366     threadData = targetData;
01367 
01368     for (int i = 0; i < children.size(); ++i) {
01369         QObject *child = children.at(i);
01370         child->d_func()->setThreadData_helper(currentData, targetData);
01371     }
01372 }
01373 
01374 void QObjectPrivate::_q_reregisterTimers(void *pointer)
01375 {
01376     Q_Q(QObject);
01377     QList<QPair<int, int> > *timerList = reinterpret_cast<QList<QPair<int, int> > *>(pointer);
01378     QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher;
01379     for (int i = 0; i < timerList->size(); ++i) {
01380         const QPair<int, int> &pair = timerList->at(i);
01381         eventDispatcher->registerTimer(pair.first, pair.second, q);
01382     }
01383     delete timerList;
01384 }
01385 
01386 
01387 //
01388 // The timer flag hasTimer is set when startTimer is called.
01389 // It is not reset when killing the timer because more than
01390 // one timer might be active.
01391 //
01392 
01450 int QObject::startTimer(int interval)
01451 {
01452     Q_D(QObject);
01453 
01454     if (interval < 0) {
01455         qWarning("QObject::startTimer: QTimer cannot have a negative interval");
01456         return 0;
01457     }
01458 
01459     d->pendTimer = true;                                // set timer flag
01460 
01461     if (!d->threadData->eventDispatcher) {
01462         qWarning("QObject::startTimer: QTimer can only be used with threads started with QThread");
01463         return 0;
01464     }
01465     return d->threadData->eventDispatcher->registerTimer(interval, this);
01466 }
01467 
01477 void QObject::killTimer(int id)
01478 {
01479     Q_D(QObject);
01480     if (d->threadData->eventDispatcher)
01481         d->threadData->eventDispatcher->unregisterTimer(id);
01482 }
01483 
01484 
01516 #ifdef QT3_SUPPORT
01517 static void objSearch(QObjectList &result,
01518                        const QObjectList &list,
01519                        const char  *inheritsClass,
01520                        bool onlyWidgets,
01521                        const char  *objName,
01522                        QRegExp           *rx,
01523                        bool            recurse)
01524 {
01525     for (int i = 0; i < list.size(); ++i) {
01526         QObject *obj = list.at(i);
01527         bool ok = true;
01528         if (onlyWidgets)
01529             ok = obj->isWidgetType();
01530         else if (inheritsClass && !obj->inherits(inheritsClass))
01531             ok = false;
01532         if (ok) {
01533             if (objName)
01534                 ok = (obj->objectName() == QLatin1String(objName));
01535 #ifndef QT_NO_REGEXP
01536             else if (rx)
01537                 ok = (rx->indexIn(obj->objectName()) != -1);
01538 #endif
01539         }
01540         if (ok)                                // match!
01541             result.append(obj);
01542         if (recurse) {
01543             QObjectList clist = obj->children();
01544             if (!clist.isEmpty())
01545                 objSearch(result, clist, inheritsClass,
01546                            onlyWidgets, objName, rx, recurse);
01547         }
01548     }
01549 }
01550 
01594 QObjectList QObject::queryList(const char *inheritsClass,
01595                                 const char *objName,
01596                                 bool regexpMatch,
01597                                 bool recursiveSearch) const
01598 {
01599     Q_D(const QObject);
01600     QObjectList list;
01601     bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget") == 0);
01602 #ifndef QT_NO_REGEXP
01603     if (regexpMatch && objName) {                // regexp matching
01604         QRegExp rx(QString::fromLatin1(objName));
01605         objSearch(list, d->children, inheritsClass, onlyWidgets, 0, &rx, recursiveSearch);
01606     } else
01607 #endif
01608     {
01609         objSearch(list, d->children, inheritsClass, onlyWidgets, objName, 0, recursiveSearch);
01610     }
01611     return list;
01612 }
01613 #endif
01614 
01756 void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re,
01757                          const QMetaObject &mo, QList<void*> *list)
01758 {
01759     if (!parent || !list)
01760         return;
01761     const QObjectList &children = parent->children();
01762     QObject *obj;
01763     for (int i = 0; i < children.size(); ++i) {
01764         obj = children.at(i);
01765         if (mo.cast(obj)) {
01766             if (re) {
01767                 if (re->indexIn(obj->objectName()) != -1)
01768                     list->append(obj);
01769             } else {
01770                 if (name.isNull() || obj->objectName() == name)
01771                     list->append(obj);
01772             }
01773         }
01774         qt_qFindChildren_helper(obj, name, re, mo, list);
01775     }
01776 }
01777 
01780 QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo)
01781 {
01782     if (!parent)
01783         return 0;
01784     const QObjectList &children = parent->children();
01785     QObject *obj;
01786     int i;
01787     for (i = 0; i < children.size(); ++i) {
01788         obj = children.at(i);
01789         if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
01790             return obj;
01791     }
01792     for (i = 0; i < children.size(); ++i) {
01793         obj = qt_qFindChild_helper(children.at(i), name, mo);
01794         if (obj)
01795             return obj;
01796     }
01797     return 0;
01798 }
01799 
01806 void QObject::setParent(QObject *parent)
01807 {
01808     Q_D(QObject);
01809     Q_ASSERT(!d->isWidget);
01810     d->setParent_helper(parent);
01811 }
01812 
01813 void QObjectPrivate::deleteChildren()
01814 {
01815     const bool reallyWasDeleted = wasDeleted;
01816     wasDeleted = true;
01817     // delete children objects
01818     // don't use qDeleteAll as the destructor of the child might
01819     // delete siblings
01820     for (int i = 0; i < children.count(); ++i) {
01821         currentChildBeingDeleted = children.at(i);
01822         children[i] = 0;
01823         delete currentChildBeingDeleted;
01824     }
01825     children.clear();
01826     currentChildBeingDeleted = 0;
01827     wasDeleted = reallyWasDeleted;
01828 }
01829 
01830 void QObjectPrivate::setParent_helper(QObject *o)
01831 {
01832     Q_Q(QObject);
01833     if (o == parent)
01834         return;
01835     if (parent) {
01836         QObjectPrivate *parentD = parent->d_func();
01837         if (parentD->wasDeleted && wasDeleted
01838             && parentD->currentChildBeingDeleted == q) {
01839             // don't do anything since QObjectPrivate::deleteChildren() already
01840             // cleared our entry in parentD->children.
01841         } else {
01842             const int index = parentD->children.indexOf(q);
01843             if (parentD->wasDeleted) {
01844                 parentD->children[index] = 0;
01845             } else {
01846                 parentD->children.removeAt(index);
01847                 if (sendChildEvents && parentD->receiveChildEvents) {
01848                     QChildEvent e(QEvent::ChildRemoved, q);
01849                     QCoreApplication::sendEvent(parent, &e);
01850                 }
01851             }
01852         }
01853     }
01854     parent = o;
01855     if (parent) {
01856         // object hierarchies are constrained to a single thread
01857         if (threadData != parent->d_func()->threadData) {
01858             qWarning("QObject::setParent: New parent must be in the same thread as the previous parent");
01859             parent = 0;
01860             return;
01861         }
01862         parent->d_func()->children.append(q);
01863         if(sendChildEvents && parent->d_func()->receiveChildEvents) {
01864             if (!isWidget) {
01865                 QChildEvent e(QEvent::ChildAdded, q);
01866                 QCoreApplication::sendEvent(parent, &e);
01867 #ifdef QT3_SUPPORT
01868                 QCoreApplication::postEvent(parent, new QChildEvent(QEvent::ChildInserted, q));
01869 #endif
01870             }
01871         }
01872     }
01873 }
01874 
01941 void QObject::installEventFilter(QObject *obj)
01942 {
01943     Q_D(QObject);
01944     if (!obj)
01945         return;
01946 
01947     QWriteLocker locker(QObjectPrivate::readWriteLock());
01948 
01949     // clean up unused items in the list
01950     d->eventFilters.removeAll((QObject*)0);
01951     d->eventFilters.removeAll(obj);
01952     d->eventFilters.prepend(obj);
01953 }
01954 
01970 void QObject::removeEventFilter(QObject *obj)
01971 {
01972     Q_D(QObject);
01973     QWriteLocker locker(QObjectPrivate::readWriteLock());
01974     d->eventFilters.removeAll(obj);
01975 }
01976 
01977 
02006 void QObject::deleteLater()
02007 {
02008     QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
02009 }
02010 
02112 /*****************************************************************************
02113   Signals and slots
02114  *****************************************************************************/
02115 
02116 static bool check_signal_macro(const QObject *sender, const char *signal,
02117                                 const char *func, const char *op)
02118 {
02119     int sigcode = (int)(*signal) - '0';
02120     if (sigcode != QSIGNAL_CODE) {
02121         if (sigcode == QSLOT_CODE)
02122             qWarning("Object::%s: Attempt to %s non-signal %s::%s",
02123                      func, op, sender->metaObject()->className(), signal+1);
02124         else
02125             qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s",
02126                      func, op, sender->metaObject()->className(), signal);
02127         return false;
02128     }
02129     return true;
02130 }
02131 
02132 static bool check_method_code(int code, const QObject *object,
02133                                const char *method, const char *func)
02134 {
02135     if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
02136         qWarning("Object::%s: Use the SLOT or SIGNAL macro to "
02137                  "%s %s::%s", func, func, object->metaObject()->className(), method);
02138         return false;
02139     }
02140     return true;
02141 }
02142 
02143 static void err_method_notfound(int code, const QObject *object,
02144                                  const char *method, const char *func)
02145 {
02146     const char *type = 0;
02147     switch (code) {
02148         case QSLOT_CODE:   type = "slot";   break;
02149         case QSIGNAL_CODE: type = "signal"; break;
02150     }
02151     if (strchr(method,')') == 0)                // common typing mistake
02152         qWarning("Object::%s: Parentheses expected, %s %s::%s",
02153                  func, type, object->metaObject()->className(), method);
02154     else
02155         qWarning("Object::%s: No such %s %s::%s",
02156                  func, type, object->metaObject()->className(), method);
02157 }
02158 
02159 
02160 static void err_info_about_objects(const char * func,
02161                                     const QObject * sender,
02162                                     const QObject * receiver)
02163 {
02164     QString a = sender ? sender->objectName() : QString();
02165     QString b = receiver ? receiver->objectName() : QString();
02166     if (!a.isEmpty())
02167         qWarning("Object::%s:  (sender name:   '%s')", func, a.toLocal8Bit().data());
02168     if (!b.isEmpty())
02169         qWarning("Object::%s:  (receiver name: '%s')", func, b.toLocal8Bit().data());
02170 }
02171 
02189 QObject *QObject::sender() const
02190 {
02191     Q_D(const QObject);
02192     QConnectionList * const list = ::connectionList();
02193     if (!list)
02194         return 0;
02195 
02196     QReadLocker locker(&list->lock);
02197     QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(d->currentSender);
02198     const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();
02199 
02200     // Return 0 if d->currentSender isn't in the senders hash (it has been destroyed?)
02201     if (it == end)
02202         return 0;
02203 
02204     // Only return d->currentSender if it's actually connected to "this"
02205     for (; it != end && it.key() == d->currentSender; ++it) {
02206         const int at = it.value();
02207         const QConnection &c = list->connections.at(at);
02208 
02209         if (c.receiver == this)
02210             return d->currentSender;
02211     }
02212 
02213     return 0;
02214 }
02215 
02244 int QObject::receivers(const char *signal) const
02245 {
02246     int receivers = 0;
02247     if (signal) {
02248         QByteArray signal_name = QMetaObject::normalizedSignature(signal);
02249         signal = signal_name;
02250 #ifndef QT_NO_DEBUG
02251         if (!check_signal_macro(this, signal, "receivers", "bind"))
02252             return 0;
02253 #endif
02254         signal++; // skip code
02255         const QMetaObject *smeta = this->metaObject();
02256         int signal_index = smeta->indexOfSignal(signal);
02257         if (signal_index < 0) {
02258 #ifndef QT_NO_DEBUG
02259             err_method_notfound(QSIGNAL_CODE, this, signal, "receivers");
02260 #endif
02261             return false;
02262         }
02263         QConnectionList *list = ::connectionList();
02264         QReadLocker locker(&list->lock);
02265         QHash<const QObject *, int>::const_iterator i = list->sendersHash.constFind(this);
02266         while (i != list->sendersHash.constEnd() && i.key() == this) {
02267             if (list->connections.at(i.value()).signal == signal_index)
02268                 ++receivers;
02269             ++i;
02270         }
02271     }
02272     return receivers;
02273 }
02274 
02368 bool QObject::connect(const QObject *sender, const char *signal,
02369                       const QObject *receiver, const char *method,
02370                       Qt::ConnectionType type)
02371 {
02372     {
02373         const void *cbdata[] = { sender, signal, receiver, method, &type };
02374         if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
02375             return true;
02376     }
02377 
02378 #ifndef QT_NO_DEBUG
02379     bool warnCompat = true;
02380 #endif
02381     if (type == Qt::AutoCompatConnection) {
02382         type = Qt::AutoConnection;
02383 #ifndef QT_NO_DEBUG
02384         warnCompat = false;
02385 #endif
02386     }
02387 
02388     if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
02389         qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
02390                  sender ? sender->metaObject()->className() : "(null)",
02391                  (signal && *signal) ? signal+1 : "(null)",
02392                  receiver ? receiver->metaObject()->className() : "(null)",
02393                  (method && *method) ? method+1 : "(null)");
02394         return false;
02395     }
02396     QByteArray tmp_signal_name;
02397 
02398     if (!check_signal_macro(sender, signal, "connect", "bind"))
02399         return false;
02400     const QMetaObject *smeta = sender->metaObject();
02401     ++signal; //skip code
02402     int signal_index = smeta->indexOfSignal(signal);
02403     if (signal_index < 0) {
02404         // check for normalized signatures
02405         tmp_signal_name = QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
02406         signal = tmp_signal_name.constData() + 1;
02407         signal_index = smeta->indexOfSignal(signal);
02408         if (signal_index < 0) {
02409             err_method_notfound(QSIGNAL_CODE, sender, signal, "connect");
02410             err_info_about_objects("connect", sender, receiver);
02411             return false;
02412         }
02413     }
02414 
02415     QByteArray tmp_method_name;
02416     int membcode = method[0] - '0';
02417 
02418     if (!check_method_code(membcode, receiver, method, "connect"))
02419         return false;
02420     ++method; // skip code
02421 
02422     const QMetaObject *rmeta = receiver->metaObject();
02423     int method_index = -1;
02424     switch (membcode) {
02425     case QSLOT_CODE:
02426         method_index = rmeta->indexOfSlot(method);
02427         break;
02428     case QSIGNAL_CODE:
02429         method_index = rmeta->indexOfSignal(method);
02430         break;
02431     }
02432     if (method_index < 0) {
02433         // check for normalized methods
02434         tmp_method_name = QMetaObject::normalizedSignature(method);
02435         method = tmp_method_name.constData();
02436         switch (membcode) {
02437         case QSLOT_CODE:
02438             method_index = rmeta->indexOfSlot(method);
02439             break;
02440         case QSIGNAL_CODE:
02441             method_index = rmeta->indexOfSignal(method);
02442             break;
02443         }
02444     }
02445 
02446     if (method_index < 0) {
02447         err_method_notfound(membcode, receiver, method, "connect");
02448         err_info_about_objects("connect", sender, receiver);
02449         return false;
02450     }
02451     if (!QMetaObject::checkConnectArgs(signal, method)) {
02452         qWarning("QObject::connect: Incompatible sender/receiver arguments"
02453                  "\n\t%s::%s --> %s::%s",
02454                  sender->metaObject()->className(), signal,
02455                  receiver->metaObject()->className(), method);
02456         return false;
02457     }
02458 
02459     int *types = 0;
02460     if (type == Qt::QueuedConnection
02461             && !(types = ::queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))
02462         return false;
02463 
02464 #ifndef QT_NO_DEBUG
02465     {
02466         QMetaMethod smethod = smeta->method(signal_index);
02467         QMetaMethod rmethod = rmeta->method(method_index);
02468         if (warnCompat) {
02469             if(smethod.attributes() & QMetaMethod::Compatibility) {
02470                 if (!(rmethod.attributes() & QMetaMethod::Compatibility))
02471                     qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)", smeta->className(), signal);
02472             } else if(rmethod.attributes() & QMetaMethod::Compatibility && membcode != QSIGNAL_CODE) {
02473                 qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
02474                          smeta->className(), signal, rmeta->className(), method);
02475             }
02476         }
02477     }
02478 #endif
02479     QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
02480     const_cast<QObject*>(sender)->connectNotify(signal - 1);
02481     return true;
02482 }
02483 
02484 
02570 bool QObject::disconnect(const QObject *sender, const char *signal,
02571                          const QObject *receiver, const char *method)
02572 {
02573     if (sender == 0 || (receiver == 0 && method != 0)) {
02574         qWarning("Object::disconnect: Unexpected null parameter");
02575         return false;
02576     }
02577 
02578     {
02579         const void *cbdata[] = { sender, signal, receiver, method };
02580         if (QInternal::activateCallbacks(QInternal::DisconnectCallback, (void **) cbdata))
02581             return true;
02582     }
02583 
02584     QByteArray signal_name;
02585     bool signal_found = false;
02586     if (signal) {
02587         signal_name = QMetaObject::normalizedSignature(signal);
02588         signal = signal_name;
02589         if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
02590             return false;
02591         signal++; // skip code
02592     }
02593 
02594     QByteArray method_name;
02595     int membcode = -1;
02596     bool method_found = false;
02597     if (method) {
02598         method_name = QMetaObject::normalizedSignature(method);
02599         method = method_name;
02600         membcode = method[0] - '0';
02601         if (!check_method_code(membcode, receiver, method, "disconnect"))
02602             return false;
02603         method++; // skip code
02604     }
02605 
02606     /* We now iterate through all the sender's and receiver's meta
02607      * objects in order to also disconnect possibly shadowed signals
02608      * and slots with the same signature.
02609     */
02610     bool res = false;
02611     const QMetaObject *smeta = sender->metaObject();
02612     do {
02613         int signal_index = -1;
02614         if (signal) {
02615             signal_index = smeta->indexOfSignal(signal);
02616             if (signal_index < smeta->methodOffset())
02617                 continue;
02618             signal_found = true;
02619         }
02620 
02621         if (!method) {
02622             res |= QMetaObject::disconnect(sender, signal_index, receiver, -1);
02623         } else {
02624             const QMetaObject *rmeta = receiver->metaObject();
02625             do {
02626                 int method_index = rmeta->indexOfMethod(method);
02627                 if (method_index >= 0)
02628                     while (method_index < rmeta->methodOffset())
02629                             rmeta = rmeta->superClass();
02630                 if (method_index < 0)
02631                     break;
02632                 res |= QMetaObject::disconnect(sender, signal_index, receiver, method_index);
02633                 method_found = true;
02634             } while ((rmeta = rmeta->superClass()));
02635         }
02636     } while (signal && (smeta = smeta->superClass()));
02637 
02638     if (signal && !signal_found) {
02639         err_method_notfound(QSIGNAL_CODE, sender, signal, "disconnect");
02640         err_info_about_objects("disconnect", sender, receiver);
02641     } else if (method && !method_found) {
02642         err_method_notfound(membcode, receiver, method, "disconnect");
02643         err_info_about_objects("disconnect", sender, receiver);
02644     }
02645     if (res)
02646         const_cast<QObject*>(sender)->disconnectNotify(signal ? (signal - 1) : 0);
02647     return res;
02648 }
02649 
02650 
02702 void QObject::connectNotify(const char *)
02703 {
02704 }
02705 
02722 void QObject::disconnectNotify(const char *)
02723 {
02724 }
02725 
02731 bool QMetaObject::connect(const QObject *sender, int signal_index,
02732                           const QObject *receiver, int method_index, int type, int *types)
02733 {
02734     QConnectionList *list = ::connectionList();
02735     if (!list)
02736         return false;
02737     QWriteLocker locker(&list->lock);
02738     list->addConnection(const_cast<QObject *>(sender), signal_index,
02739                         const_cast<QObject *>(receiver), method_index, type, types);
02740     return true;
02741 }
02742 
02743 
02746 bool QMetaObject::disconnect(const QObject *sender, int signal_index,
02747                              const QObject *receiver, int method_index)
02748 {
02749     if (!sender)
02750         return false;
02751     QConnectionList *list = ::connectionList();
02752     if (!list)
02753         return false;
02754     QWriteLocker locker(&list->lock);
02755     return list->removeConnection(const_cast<QObject*>(sender), signal_index,
02756                                   const_cast<QObject*>(receiver), method_index);
02757 }
02758 
02779 void QMetaObject::connectSlotsByName(QObject *o)
02780 {
02781     if (!o)
02782         return;
02783     const QMetaObject *mo = o->metaObject();
02784     Q_ASSERT(mo);
02785     const QObjectList list = qFindChildren<QObject *>(o, QString());
02786     for (int i = 0; i < mo->methodCount(); ++i) {
02787         const char *slot = mo->method(i).signature();
02788         Q_ASSERT(slot);
02789         if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
02790             continue;
02791         bool foundIt = false;
02792         for(int j = 0; j < list.count(); ++j) {
02793             const QObject *co = list.at(j);
02794             QByteArray objName = co->objectName().toAscii();
02795             int len = objName.length();
02796             if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
02797                 continue;
02798             const QMetaObject *smo = co->metaObject();
02799             int sigIndex = smo->indexOfMethod(slot + len + 4);
02800             if (sigIndex < 0) { // search for compatible signals
02801                 int slotlen = qstrlen(slot + len + 4) - 1;
02802                 for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
02803                     if (smo->method(k).methodType() != QMetaMethod::Signal)
02804                         continue;
02805 
02806                     if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
02807                         sigIndex = k;
02808                         break;
02809                     }
02810                 }
02811             }
02812             if (sigIndex < 0)
02813                 continue;
02814             if (QMetaObject::connect(co, sigIndex, o, i)) {
02815                 foundIt = true;
02816                 break;
02817             }
02818         }
02819         if (foundIt) {
02820             // we found our slot, now skip all overloads
02821             while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
02822                   ++i;
02823         } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
02824             qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
02825         }
02826     }
02827 }
02828 
02829 static void queued_activate(QObject *sender, const QConnection &c, void **argv, int idFrom, int idTo)
02830 {
02831     if (!c.types || c.types != &DIRECT_CONNECTION_ONLY) {
02832         QMetaMethod m = sender->metaObject()->method(c.signal);
02833         QConnection &x = const_cast<QConnection &>(c);
02834         int *tmp = ::queuedConnectionTypes(m.parameterTypes());
02835         if (!tmp) // cannot queue arguments
02836             tmp = &DIRECT_CONNECTION_ONLY;
02837         if (!q_atomic_test_and_set_ptr(&x.types, 0, tmp)) {
02838             if (tmp != &DIRECT_CONNECTION_ONLY)
02839                 qFree(tmp);
02840         }
02841     }
02842     if (c.types == &DIRECT_CONNECTION_ONLY) // cannot activate
02843         return;
02844     int nargs = 1; // include return type
02845     while (c.types[nargs-1]) { ++nargs; }
02846     int *types = (int *) qMalloc(nargs*sizeof(int));
02847     void **args = (void **) qMalloc(nargs*sizeof(void *));
02848     types[0] = 0; // return type
02849     args[0] = 0; // return value
02850     for (int n = 1; n < nargs; ++n)
02851         args[n] = QMetaType::construct((types[n] = c.types[n-1]), argv[n]);
02852     QCoreApplication::postEvent(c.receiver, new QMetaCallEvent(c.method,
02853                                                                sender,
02854                                                                idFrom,
02855                                                                idTo,
02856                                                                nargs,
02857                                                                types,
02858                                                                args));
02859 }
02860 
02863 void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
02864 {
02865     if (sender->d_func()->blockSig)
02866         return;
02867 
02868     QConnectionList * const list = ::connectionList();
02869     if (!list)
02870         return;
02871 
02872     void *empty_argv[] = { 0 };
02873     if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
02874         qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index,
02875                                                          argv ? argv : empty_argv);
02876     }
02877 
02878     QReadLocker locker(&list->lock);
02879 
02880     QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(sender);
02881     const QConnectionList::Hash::const_iterator start = it;
02882     const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();
02883 
02884     if (start == end) {
02885         locker.unlock();
02886         if (qt_signal_spy_callback_set.signal_end_callback != 0)
02887             qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
02888         return;
02889     }
02890 
02891     QThreadData *currentThreadData = QThreadData::current();
02892 
02893     // QVarLengthArray doesn't use the same growth strategy as the rest of the Tulip classes, so we need to
02894     // determine the exact number of connections
02895     int i = 0;
02896     for (it = start; it != end && it.key() == sender; ++it) {
02897         ++i;
02898     }
02899     QVarLengthArray<int> connections(i);
02900     for (i = 0, it = start; it != end && it.key() == sender; ++i, ++it) {
02901         connections.data()[i] = it.value();
02902         ++list->connections[it.value()].refCount;
02903     }
02904 
02905     for (i = 0; i < connections.size(); ++i) {
02906         const int at = connections.constData()[connections.size() - (i + 1)];
02907         QConnectionList * const list = ::connectionList();
02908         QConnection *c = &list->connections[at];
02909         --c->refCount;
02910         if (!c->receiver || ((c->signal < from_signal_index || c->signal > to_signal_index) &&
02911                             c->signal != -1))
02912             continue;
02913 
02914         // determine if this connection should be sent immediately or
02915         // put into the event queue
02916         if ((c->type == Qt::AutoConnection
02917              && (currentThreadData != sender->d_func()->threadData
02918                  || c->receiver->d_func()->threadData != sender->d_func()->threadData))
02919             || (c->type == Qt::QueuedConnection)) {
02920             ::queued_activate(sender, *c, argv, from_signal_index, to_signal_index);
02921             continue;
02922         }
02923 
02924         const int method = c->method;
02925         QObject * const previousSender = c->receiver->d_func()->currentSender;
02926         int previousFrom = c->receiver->d_func()->currentSenderSignalIdStart;
02927         int previousTo = c->receiver->d_func()->currentSenderSignalIdEnd;
02928         c->receiver->d_func()->currentSender = sender;
02929         c->receiver->d_func()->currentSenderSignalIdStart = from_signal_index;
02930         c->receiver->d_func()->currentSenderSignalIdEnd = to_signal_index;
02931         locker.unlock();
02932 
02933         if (qt_signal_spy_callback_set.slot_begin_callback != 0)
02934             qt_signal_spy_callback_set.slot_begin_callback(c->receiver, method, argv ? argv : empty_argv);
02935 
02936 #if defined(QT_NO_EXCEPTIONS)
02937         c->receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
02938 #else
02939         try {
02940             c->receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
02941         } catch (...) {
02942             if (c->receiver) {
02943                 c->receiver->d_func()->currentSender = previousSender;
02944                 c->receiver->d_func()->currentSenderSignalIdStart = previousFrom;
02945                 c->receiver->d_func()->currentSenderSignalIdEnd = previousTo;
02946             }
02947             throw;
02948         }
02949 #endif
02950         c = &list->connections[at];
02951 
02952         if (qt_signal_spy_callback_set.slot_end_callback != 0)
02953             qt_signal_spy_callback_set.slot_end_callback(c->receiver, method);
02954 
02955         locker.relock();
02956         if (c->receiver) {
02957             c->receiver->d_func()->currentSender = previousSender;
02958             c->receiver->d_func()->currentSenderSignalIdStart = previousFrom;
02959             c->receiver->d_func()->currentSenderSignalIdEnd = previousTo;
02960         }
02961     }
02962 
02963     locker.unlock();
02964 
02965     if (qt_signal_spy_callback_set.signal_end_callback != 0)
02966         qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
02967 }
02968 
02969 
02972 void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
02973 {
02974     activate(sender, signal_index, signal_index, argv);
02975 }
02976 
02979 void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
02980                            void **argv)
02981 {
02982     int offset = m->methodOffset();
02983     activate(sender, offset + local_signal_index, offset + local_signal_index, argv);
02984 }
02985 
02988 void QMetaObject::activate(QObject *sender, const QMetaObject *m,
02989                            int from_local_signal_index, int to_local_signal_index, void **argv)
02990 {
02991     int offset = m->methodOffset();
02992     activate(sender, offset + from_local_signal_index, offset + to_local_signal_index, argv);
02993 }
02994 
02995 
02996 /*****************************************************************************
02997   Properties
02998  *****************************************************************************/
02999 
03000 #ifndef QT_NO_PROPERTIES
03001 
03020 bool QObject::setProperty(const char *name, const QVariant &value)
03021 {
03022     Q_D(QObject);
03023     const QMetaObject* meta = metaObject();
03024     if (!name || !meta)
03025         return false;
03026 
03027     int id = meta->indexOfProperty(name);
03028     if (id < 0) {
03029         if (!d->extraData)
03030             d->extraData = new QObjectPrivate::ExtraData;
03031 
03032         const int idx = d->extraData->propertyNames.indexOf(name);
03033 
03034         if (value.isNull()) {
03035             if (idx == -1)
03036                 return false;
03037             d->extraData->propertyNames.removeAt(idx);
03038             d->extraData->propertyValues.removeAt(idx);
03039         } else {
03040             if (idx == -1) {
03041                 d->extraData->propertyNames.append(name);
03042                 d->extraData->propertyValues.append(value);
03043             } else {
03044                 d->extraData->propertyValues[idx] = value;
03045             }
03046         }
03047 
03048         QDynamicPropertyChangeEvent ev(name);
03049         QCoreApplication::sendEvent(this, &ev);
03050 
03051         return false;
03052     }
03053     QMetaProperty p = meta->property(id);
03054 #ifndef QT_NO_DEBUG
03055     if (!p.isWritable())
03056         qWarning("%s::setProperty: Property \"%s\" invalid,"
03057                  " read-only or does not exist", metaObject()->className(), name);
03058 #endif
03059     return p.write(this, value);
03060 }
03061 
03072 QVariant QObject::property(const char *name) const
03073 {
03074     Q_D(const QObject);
03075     const QMetaObject* meta = metaObject();
03076     if (!name || !meta)
03077         return QVariant();
03078 
03079     int id = meta->indexOfProperty(name);
03080     if (id < 0) {
03081         if (!d->extraData)
03082             return QVariant();
03083         const int i = d->extraData->propertyNames.indexOf(name);
03084         return d->extraData->propertyValues.value(i);
03085     }
03086     QMetaProperty p = meta->property(id);
03087 #ifndef QT_NO_DEBUG
03088     if (!p.isReadable())
03089         qWarning("%s::property: Property \"%s\" invalid or does not exist",
03090                  metaObject()->className(), name);
03091 #endif
03092     return p.read(this);
03093 }
03094 
03101 QList<QByteArray> QObject::dynamicPropertyNames() const
03102 {
03103     Q_D(const QObject);
03104     if (d->extraData)
03105         return d->extraData->propertyNames;
03106     return QList<QByteArray>();
03107 }
03108 
03109 #endif // QT_NO_PROPERTIES
03110 
03111 
03112 /*****************************************************************************
03113   QObject debugging output routines.
03114  *****************************************************************************/
03115 
03116 static void dumpRecursive(int level, QObject *object)
03117 {
03118 #if defined(QT_DEBUG)
03119     if (object) {
03120         QByteArray buf;
03121         buf.fill('\t', level/2);
03122         if (level % 2)
03123             buf += "    ";
03124         QString name = object->objectName();
03125         QString flags = QLatin1String("");
03126 #if 0
03127         if (qApp->focusWidget() == object)
03128             flags += 'F';
03129         if (object->isWidgetType()) {
03130             QWidget * w = (QWidget *)object;
03131             if (w->isVisible()) {
03132                 QString t("<%1,%2,%3,%4>");
03133                 flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height());
03134             } else {
03135                 flags += 'I';
03136             }
03137         }
03138 #endif
03139         qDebug("%s%s::%s %s", (const char*)buf, object->metaObject()->className(), name.toLocal8Bit().data(),
03140                flags.toLatin1().data());
03141         QObjectList children = object->children();
03142         if (!children.isEmpty()) {
03143             for (int i = 0; i < children.size(); ++i)
03144                 dumpRecursive(level+1, children.at(i));
03145         }
03146     }
03147 #else
03148     Q_UNUSED(level)
03149         Q_UNUSED(object)
03150 #endif
03151 }
03152 
03163 void QObject::dumpObjectTree()
03164 {
03165     dumpRecursive(0, this);
03166 }
03167 
03179 void QObject::dumpObjectInfo()
03180 {
03181 #if defined(QT_DEBUG)
03182     qDebug("OBJECT %s::%s", metaObject()->className(),
03183            objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
03184     //#### signals and slots info missing
03185 #endif
03186 }
03187 
03188 #ifndef QT_NO_USERDATA
03189 
03191 uint QObject::registerUserData()
03192 {
03193     static int user_data_registration = 0;
03194     return user_data_registration++;
03195 }
03196 
03199 QObjectUserData::~QObjectUserData()
03200 {
03201 }
03202 
03205 void QObject::setUserData(uint id, QObjectUserData* data)
03206 {
03207     Q_D(QObject);
03208     if (!d->extraData)
03209         d->extraData = new QObjectPrivate::ExtraData;
03210 
03211     if (d->extraData->userData.size() <= (int) id)
03212         d->extraData->userData.resize((int) id + 1);
03213     d->extraData->userData[id] = data;
03214 }
03215 
03218 QObjectUserData* QObject::userData(uint id) const
03219 {
03220     Q_D(const QObject);
03221     if (!d->extraData)
03222         return 0;
03223     if ((int)id < d->extraData->userData.size())
03224         return d->extraData->userData.at(id);
03225     return 0;
03226 }
03227 
03228 #endif // QT_NO_USERDATA
03229 
03230 
03231 #ifndef QT_NO_DEBUG_STREAM
03232 QDebug operator<<(QDebug dbg, const QObject *o) {
03233 #ifndef Q_BROKEN_DEBUG_STREAM
03234     if (!o)
03235         return dbg << "QObject(0x0) ";
03236     dbg.nospace() << o->metaObject()->className() << "(" << (void *)o;
03237     if (!o->objectName().isEmpty())
03238         dbg << ", name = " << o->objectName();
03239     dbg << ')';
03240     return dbg.space();
03241 #else
03242     qWarning("This compiler doesn't support streaming QObject to QDebug");
03243     return dbg;
03244     Q_UNUSED(o);
03245 #endif
03246 }
03247 #endif
03248 
03461 #include "moc_qobject.cpp"

Generated on Thu Mar 15 11:53:33 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1