00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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;
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;
00163 int at = -1;
00164 for (int i = 0; i < unusedConnections.size(); ++i) {
00165 if (!connections.at(unusedConnections.at(i)).refCount) {
00166
00167 at = unusedConnections.takeAt(i);
00168 connections[at] = c;
00169 break;
00170 }
00171 }
00172 if (at == -1) {
00173
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
00230
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
00295 q_ptr = 0;
00296 parent = 0;
00297 isWidget = false;
00298 pendTimer = false;
00299 blockSig = false;
00300 wasDeleted = false;
00301 sendChildEvents = true;
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
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
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;
00708
00709 if (!d->isWidget) {
00710
00711
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
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
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 if (d->postedEvents > 0)
00750 QCoreApplication::removePostedEvents(this);
00751 }
00752
00753 if (d->parent)
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
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 * )
01119 {
01120 }
01121
01122
01132 void QObject::customEvent(QEvent * )
01133 {
01134 }
01135
01136
01137
01197 bool QObject::eventFilter(QObject * , QEvent * )
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
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
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
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
01317 currentData->ref();
01318
01319
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
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
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
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
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
01389
01390
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;
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)
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) {
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
01818
01819
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
01840
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
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
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
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)
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
02201 if (it == end)
02202 return 0;
02203
02204
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++;
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;
02402 int signal_index = smeta->indexOfSignal(signal);
02403 if (signal_index < 0) {
02404
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;
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
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++;
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++;
02604 }
02605
02606
02607
02608
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) {
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
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)
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)
02843 return;
02844 int nargs = 1;
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;
02849 args[0] = 0;
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
02894
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
02915
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
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
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
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"