?? qobject.cpp
字號:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtCore module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qobject.h"#include "qobject_p.h"#include "qabstracteventdispatcher.h"#include "qcoreapplication.h"#include "qcoreapplication_p.h"#include "qvariant.h"#include "qmetaobject.h"#include <qregexp.h>#include <qthread.h>#include <private/qthread_p.h>#include <qdebug.h>#include <qhash.h>#include <qpair.h>#include <qvarlengtharray.h>#include <qset.h>#include <new>#include <ctype.h>#include <limits.h>static int DIRECT_CONNECTION_ONLY = 0;Q_GLOBAL_STATIC(QReadWriteLock, qt_object_read_write_lock)QReadWriteLock *QObjectPrivate::readWriteLock() { return qt_object_read_write_lock(); }static int *queuedConnectionTypes(const QList<QByteArray> &typeNames){ int *types = static_cast<int *>(qMalloc((typeNames.count() + 1) * sizeof(int))); for (int i = 0; i < typeNames.count(); ++i) { const QByteArray typeName = typeNames.at(i); if (typeName.endsWith('*')) types[i] = QMetaType::VoidStar; else types[i] = QMetaType::type(typeName); if (!types[i]) { qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" "(Make sure '%s' is registed using qRegisterMetaType().)", typeName.constData(), typeName.constData()); qFree(types); return 0; } } types[typeNames.count()] = 0; return types;}struct QConnection { QObject *sender; int signal; QObject *receiver; int method; uint refCount:30; uint type:2; // 0 == auto, 1 == direct, 2 == queued int *types;};Q_DECLARE_TYPEINFO(QConnection, Q_MOVABLE_TYPE);class QConnectionList{public: QReadWriteLock lock; typedef QMultiHash<const QObject *, int> Hash; Hash sendersHash, receiversHash; QList<int> unusedConnections; typedef QList<QConnection> List; List connections; void remove(QObject *object); void addConnection(QObject *sender, int signal, QObject *receiver, int method, int type = 0, int *types = 0); bool removeConnection(QObject *sender, int signal, QObject *receiver, int method);};Q_GLOBAL_STATIC(QConnectionList, connectionList)/*! \internal Removes \a object from the connection list completely, i.e. all connections containing \a object are removed.*/void QConnectionList::remove(QObject *object){ for (int i = 0; i < 2; ++i) { Hash &hash1 = i == 0 ? sendersHash : receiversHash; Hash &hash2 = i == 0 ? receiversHash : sendersHash; Hash::iterator it = hash1.find(object); const Hash::iterator end = hash1.end(); while (it != end && it.key() == object) { const int at = it.value(); QConnection &c = connections[at]; if (c.sender) { if (c.types && c.types != &DIRECT_CONNECTION_ONLY) { qFree(c.types); c.types = 0; } it = hash1.erase(it); const QObject * const partner = i == 0 ? c.receiver : c.sender; Hash::iterator x = hash2.find(partner); const Hash::iterator xend = hash2.end(); while (x != xend && x.key() == partner) { if (x.value() == at) { x = hash2.erase(x); break; } else { ++x; } } uint refCount = c.refCount; memset(&c, 0, sizeof(c)); c.refCount = refCount; Q_ASSERT(!unusedConnections.contains(at)); unusedConnections.prepend(at); } else { ++it; } } }}/*! \internal Adds the specified connection.*/void QConnectionList::addConnection(QObject *sender, int signal, QObject *receiver, int method, int type, int *types){ QConnection c = { sender, signal, receiver, method, 0, 0, types }; c.type = type; // don't warn on VC++6 int at = -1; for (int i = 0; i < unusedConnections.size(); ++i) { if (!connections.at(unusedConnections.at(i)).refCount) { // reuse an unused connection at = unusedConnections.takeAt(i); connections[at] = c; break; } } if (at == -1) { // append new connection at = connections.size(); connections << c; } sendersHash.insert(sender, at); receiversHash.insert(receiver, at);}/*! \internal Removes the specified connection. See QObject::disconnect() for more information about valid arguments. */bool QConnectionList::removeConnection(QObject *sender, int signal, QObject *receiver, int method){ bool success = false; Hash::iterator it = sendersHash.find(sender); while (it != sendersHash.end() && it.key() == sender) { const int at = it.value(); QConnection &c = connections[at]; if (c.receiver && (signal < 0 || signal == c.signal) && (receiver == 0 || (c.receiver == receiver && (method < 0 || method == c.method)))) { if (c.types) { if (c.types != &DIRECT_CONNECTION_ONLY) qFree(c.types); c.types = 0; } it = sendersHash.erase(it); Hash::iterator x = receiversHash.find(c.receiver); const Hash::iterator xend = receiversHash.end(); while (x != xend && x.key() == c.receiver) { if (x.value() == at) { x = receiversHash.erase(x); break; } else { ++x; } } uint refCount = c.refCount; memset(&c, 0, sizeof(c)); c.refCount = refCount; unusedConnections << at; success = true; } else { ++it; } } return success;}/* QObjectSet sets the minimum capacity to 4099 (the first prime number after 4096), so that we can speed up QObject destruction. */class QObjectSet : public QSet<QObject *>{public: QObjectSet() { reserve(4099); }};Q_GLOBAL_STATIC(QObjectSet, allObjects)extern "C" Q_CORE_EXPORT void qt_addObject(QObject *object){ QWriteLocker locker(QObjectPrivate::readWriteLock()); QObjectSet *set = allObjects(); if (set) set->insert(object);}extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *object){ QObjectSet *set = allObjects(); if (set) set->remove(object);}#ifdef Q_CC_MSVC#pragma warning(push)#pragma warning(disable:4190)#endifextern "C" Q_CORE_EXPORT QList<QObject *> qt_allTopLevelWidgets(){ QList<QObject *> list; QReadLocker locker(QObjectPrivate::readWriteLock()); const QObjectSet *set = allObjects(); if (!set) return list; for (QSet<QObject *>::const_iterator it = set->constBegin(); it != set->constEnd(); ++it) { if ((*it)->isWidgetType() && !(*it)->parent()) list << *it; } return list;}#ifdef Q_CC_MSVC#pragma warning(pop)#endifbool QObjectPrivate::isValidObject(QObject *object){ QObjectSet *set = allObjects(); return set ? set->contains(object) : false;}QObjectPrivate::QObjectPrivate(int version) : threadData(0), currentSender(0), currentSenderSignalIdStart(-1), currentSenderSignalIdEnd(-1){ if (version != QObjectPrivateVersion) qFatal("Cannot mix incompatible Qt libraries"); // QObjectData initialization q_ptr = 0; parent = 0; // no parent yet. It is set by setParent() isWidget = false; // assume not a widget object pendTimer = false; // no timers yet blockSig = false; // not blocking signals wasDeleted = false; // double-delete catcher sendChildEvents = true; // if we should send ChildInsert and ChildRemove events to parent receiveChildEvents = true; postedEvents = 0;#ifdef QT3_SUPPORT postedChildInsertedEvents = 0;#endif extraData = 0;}QObjectPrivate::~QObjectPrivate(){#ifndef QT_NO_USERDATA if (extraData) qDeleteAll(extraData->userData); delete extraData;#endif}bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const{ Q_Q(const QObject); int signal_index = q->metaObject()->indexOfSignal(signal); if (signal_index < 0) return false; QConnectionList *list = ::connectionList(); QReadLocker locker(&list->lock); QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(q); while (it != list->sendersHash.constEnd() && it.key() == q) { const QConnection &c = list->connections.at(it.value()); if (c.signal == signal_index && c.receiver == receiver) return true; ++it; } return false;}QObjectList QObjectPrivate::receiverList(const char *signal) const{ Q_Q(const QObject); QObjectList receivers; int signal_index = q->metaObject()->indexOfSignal(signal); if (signal_index < 0) return receivers; QConnectionList *list = ::connectionList(); QReadLocker locker(&list->lock); QConnectionList::Hash::const_iterator it = list->sendersHash.constFind(q); while (it != list->sendersHash.constEnd() && it.key() == q) { const QConnection &c = list->connections.at(it.value()); if (c.signal == signal_index) receivers << c.receiver; ++it; } return receivers;}QObjectList QObjectPrivate::senderList() const{ Q_Q(const QObject); QObjectList senders; QConnectionList *list = ::connectionList(); QReadLocker locker(&list->lock); QConnectionList::Hash::const_iterator it = list->receiversHash.constFind(q); while (it != list->receiversHash.constEnd() && it.key() == q) { const QConnection &c = list->connections.at(it.value()); senders << c.sender; ++it; } return senders;}typedef QMultiHash<QObject *, QObject **> GuardHash;Q_GLOBAL_STATIC(GuardHash, guardHash)Q_GLOBAL_STATIC(QReadWriteLock, guardHashLock)/*!\internal */void QMetaObject::addGuard(QObject **ptr){ if (!*ptr) return; GuardHash *hash = guardHash(); if (!hash) { *ptr = 0; return; } QWriteLocker locker(guardHashLock()); hash->insert(*ptr, ptr);}/*!\internal */void QMetaObject::removeGuard(QObject **ptr){ if (!*ptr) return; GuardHash *hash = guardHash(); if (!hash) return; QWriteLocker locker(guardHashLock()); GuardHash::iterator it = hash->find(*ptr); const GuardHash::iterator end = hash->end(); for (; it.key() == *ptr && it != end; ++it) { if (it.value() == ptr) { (void) hash->erase(it); break; } }}/*!\internal */void QMetaObject::changeGuard(QObject **ptr, QObject *o){ GuardHash *hash = guardHash(); if (!hash) { *ptr = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -