diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 329 |
1 files changed, 226 insertions, 103 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index fb3e4e396b..49a9beb298 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -184,6 +184,7 @@ void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **) = 0; +int (*QAbstractDeclarativeData::receivers)(QAbstractDeclarativeData *, const QObject *, int) = 0; QObjectData::~QObjectData() {} @@ -568,9 +569,9 @@ void QMetaCallEvent::placeMetaCall(QObject *object) \l uic generates code that invokes this function to enable auto-connection to be performed between widgets on forms created - with \QD. More information about using auto-connection with \QD is + with \e{Qt Designer}. More information about using auto-connection with \e{Qt Designer} is given in the \l{Using a Designer UI File in Your Application} section of - the \QD manual. + the \e{Qt Designer} manual. \section1 Dynamic Properties @@ -606,7 +607,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) Returns 0 if there is no such child. - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 0 + \snippet code/src_corelib_kernel_qobject.cpp 0 */ void *qt_find_obj_child(QObject *parent, const char *type, const QString &name) @@ -651,8 +652,8 @@ static bool check_parent_thread(QObject *parent, Constructs an object with parent object \a parent. The parent of an object may be viewed as the object's owner. For - instance, a \l{QDialog}{dialog box} is the parent of the \gui OK - and \gui Cancel buttons it contains. + instance, a \l{QDialog}{dialog box} is the parent of the \uicontrol{OK} + and \uicontrol{Cancel} buttons it contains. The destructor of a parent object destroys all child objects. @@ -881,7 +882,7 @@ QObjectPrivate::Connection::~Connection() Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 1 + \snippet code/src_corelib_kernel_qobject.cpp 1 \sa staticMetaObject */ @@ -905,7 +906,7 @@ QObjectPrivate::Connection::~Connection() Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 2 + \snippet code/src_corelib_kernel_qobject.cpp 2 \sa metaObject() */ @@ -924,7 +925,7 @@ QObjectPrivate::Connection::~Connection() Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 3 + \snippet code/src_corelib_kernel_qobject.cpp 3 The qobject_cast() function behaves similarly to the standard C++ \c dynamic_cast(), with the advantages that it doesn't require @@ -950,7 +951,7 @@ QObjectPrivate::Connection::~Connection() Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 4 + \snippet code/src_corelib_kernel_qobject.cpp 4 If you need to determine whether an object is an instance of a particular class for the purpose of casting it, consider using qobject_cast<Type *>(object) @@ -967,7 +968,7 @@ QObjectPrivate::Connection::~Connection() You can find an object by name (and type) using findChild(). You can find a set of objects with findChildren(). - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 5 + \snippet code/src_corelib_kernel_qobject.cpp 5 By default, this property contains an empty string. @@ -988,7 +989,7 @@ void QObject::setObjectName(const QString &name) Q_D(QObject); if (d->objectName != name) { d->objectName = name; - if (d->declarativeData) + if (d->declarativeData && d->declarativeData->objectNameChanged) d->declarativeData->objectNameChanged(d->declarativeData, this); emit objectNameChanged(d->objectName); } @@ -1155,7 +1156,7 @@ void QObject::customEvent(QEvent * /* event */) true; otherwise return false. Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 6 + \snippet code/src_corelib_kernel_qobject.cpp 6 Notice in the example above that unhandled events are passed to the base class's eventFilter() function, since the base class @@ -1225,7 +1226,7 @@ QThread *QObject::thread() const QApplication::thread() to retrieve the thread in which the application lives. For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 7 + \snippet code/src_corelib_kernel_qobject.cpp 7 If \a targetThread is zero, all event processing for this object and its children stops. @@ -1390,7 +1391,7 @@ void QObjectPrivate::_q_reregisterTimers(void *pointer) Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 8 + \snippet code/src_corelib_kernel_qobject.cpp 8 Note that QTimer's accuracy depends on the underlying operating system and hardware. The \a timerType argument allows you to customize the accuracy of @@ -1472,7 +1473,7 @@ void QObject::killTimer(int id) The QObjectList class is defined in the \c{<QObject>} header file as the following: - \quotefromfile src/corelib/kernel/qobject.h + \quotefromfile kernel/qobject.h \skipto /typedef .*QObjectList/ \printuntil QObjectList @@ -1507,21 +1508,21 @@ void QObject::killTimer(int id) named \c{"button1"}, even if the button isn't a direct child of the parent: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 10 + \snippet code/src_corelib_kernel_qobject.cpp 10 This example returns a \l{QListWidget} child of \c{parentWidget}: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 11 + \snippet code/src_corelib_kernel_qobject.cpp 11 This example returns a child \l{QPushButton} of \c{parentWidget} (its direct parent) named \c{"button1"}: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 41 + \snippet code/src_corelib_kernel_qobject.cpp 41 This example returns a \l{QListWidget} child of \c{parentWidget}, its direct parent: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 42 + \snippet code/src_corelib_kernel_qobject.cpp 42 \sa findChildren() */ @@ -1538,15 +1539,15 @@ void QObject::killTimer(int id) The following example shows how to find a list of child \l{QWidget}s of the specified \c{parentWidget} named \c{widgetname}: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 12 + \snippet code/src_corelib_kernel_qobject.cpp 12 This example returns all \c{QPushButton}s that are children of \c{parentWidget}: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 13 + \snippet code/src_corelib_kernel_qobject.cpp 13 This example returns all \c{QPushButton}s that are immediate children of \c{parentWidget}: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 43 + \snippet code/src_corelib_kernel_qobject.cpp 43 \sa findChild() */ @@ -1653,10 +1654,11 @@ void qt_qFindChildren_helper(const QObject *parent, const QRegExp &re, if (!parent || !list) return; const QObjectList &children = parent->children(); + QRegExp reCopy = re; QObject *obj; for (int i = 0; i < children.size(); ++i) { obj = children.at(i); - if (mo.cast(obj) && re.indexIn(obj->objectName()) != -1) + if (mo.cast(obj) && reCopy.indexIn(obj->objectName()) != -1) list->append(obj); if (options & Qt::FindChildrenRecursively) @@ -1791,7 +1793,7 @@ void QObjectPrivate::setParent_helper(QObject *o) \fn void QObject::installEventFilter(QObject *filterObj) Installs an event filter \a filterObj on this object. For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 14 + \snippet code/src_corelib_kernel_qobject.cpp 14 An event filter is an object that receives all events that are sent to this object. The filter can either stop the event or @@ -1806,11 +1808,11 @@ void QObjectPrivate::setParent_helper(QObject *o) Here's a \c KeyPressEater class that eats the key presses of its monitored objects: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 15 + \snippet code/src_corelib_kernel_qobject.cpp 15 And here's how to install it on two widgets: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 16 + \snippet code/src_corelib_kernel_qobject.cpp 16 The QShortcut class, for example, uses this technique to intercept shortcut key presses. @@ -1925,7 +1927,7 @@ void QObject::deleteLater() Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 17 + \snippet code/src_corelib_kernel_qobject.cpp 17 \dots See \l{Writing Source Code for Translation} for a detailed description of @@ -1959,7 +1961,7 @@ void QObject::deleteLater() escape sequences for specifying non-ASCII characters in string literals to trUtf8(). For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 20 + \snippet code/src_corelib_kernel_qobject.cpp 20 \sa tr(), QApplication::translate(), {Internationalization with Qt} */ @@ -2153,15 +2155,14 @@ int QObject::senderSignalIndex() const When calling this function, you can use the \c SIGNAL() macro to pass a specific signal: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 21 - - As the code snippet above illustrates, you can use this function - to avoid emitting a signal that nobody listens to. + \snippet code/src_corelib_kernel_qobject.cpp 21 \warning This function violates the object-oriented principle of modularity. However, it might be useful when you need to perform expensive initialization only if something is connected to a signal. + + \sa isSignalConnected() */ int QObject::receivers(const char *signal) const @@ -2181,10 +2182,17 @@ int QObject::receivers(const char *signal) const #ifndef QT_NO_DEBUG err_method_notfound(this, signal-1, "receivers"); #endif - return false; + return 0; } - Q_D(const QObject); + if (d->declarativeData && QAbstractDeclarativeData::receivers) { + receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this, + metaObject()->indexOfMethod(signal)); + } + + if (!d->isSignalConnected(signal_index)) + return receivers; + QMutexLocker locker(signalSlotLock(this)); if (d->connectionLists) { if (signal_index < d->connectionLists->count()) { @@ -2201,6 +2209,60 @@ int QObject::receivers(const char *signal) const } /*! + \since 5.0 + Returns true if the \a signal is connected to at least one receiver, + otherwise returns false. + + \a signal must be a signal member of this object, otherwise the behaviour + is undefined. + + \snippet code/src_corelib_kernel_qobject.cpp 21 + + As the code snippet above illustrates, you can use this function + to avoid emitting a signal that nobody listens to. + + \warning This function violates the object-oriented principle of + modularity. However, it might be useful when you need to perform + expensive initialization only if something is connected to a + signal. +*/ +bool QObject::isSignalConnected(const QMetaMethod &signal) const +{ + Q_D(const QObject); + if (!signal.mobj) + return false; + + Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal, + "QObject::isSignalConnected" , "the parametter must be a signal member of the object"); + uint signalIndex = (signal.handle - QMetaObjectPrivate::get(signal.mobj)->methodData)/5; + + if (signal.mobj->d.data[signal.handle + 4] & MethodCloned) + signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex); + + int signalOffset; + int methodOffset; + computeOffsets(signal.mobj, &signalOffset, &methodOffset); + signalIndex += signalOffset; + + if (signalIndex < sizeof(d->connectedSignals) * 8) + return d->isSignalConnected(signalIndex); + + QMutexLocker locker(signalSlotLock(this)); + if (d->connectionLists) { + if (signalIndex < uint(d->connectionLists->count())) { + const QObjectPrivate::Connection *c = + d->connectionLists->at(signalIndex).first; + while (c) { + if (c->receiver) + return true; + c = c->nextConnectionList; + } + } + } + return false; +} + +/*! \internal This helper function calculates signal and method index for the given @@ -2278,18 +2340,18 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM You must use the \c SIGNAL() and \c SLOT() macros when specifying the \a signal and the \a method, for example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 22 + \snippet code/src_corelib_kernel_qobject.cpp 22 This example ensures that the label always displays the current scroll bar value. Note that the signal and slots parameters must not contain any variable names, only the type. E.g. the following would not work and return false: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 23 + \snippet code/src_corelib_kernel_qobject.cpp 23 A signal can also be connected to another signal: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 24 + \snippet code/src_corelib_kernel_qobject.cpp 24 In this example, the \c MyWidget constructor relays a signal from a private member variable, and makes it available under a name @@ -2326,7 +2388,7 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM scenes. If you try to use a queued connection and get the error message - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25 + \snippet code/src_corelib_kernel_qobject.cpp 25 call qRegisterMetaType() to register the data type before you establish the connection. @@ -2376,7 +2438,6 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); int signalOffset, methodOffset; computeOffsets(smeta, &signalOffset, &methodOffset); - int signal_absolute_index = signal_index + methodOffset; signal_index += signalOffset; QByteArray tmp_method_name; @@ -2445,12 +2506,12 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign } #ifndef QT_NO_DEBUG - QMetaMethod smethod = smeta->method(signal_absolute_index); + QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index); QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset()); check_and_warn_compat(smeta, smethod, rmeta, rmethod); #endif QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect( - sender, signal_index, receiver, method_index_relative, rmeta ,type, types)); + sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types)); if (handle) const_cast<QObject*>(sender)->connectNotify(signal - 1); return handle; @@ -2538,7 +2599,7 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho check_and_warn_compat(smeta, signal, rmeta, method); #endif QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect( - sender, signal_index, receiver, method_index, 0, type, types)); + sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, 0, type, types)); if (handle) const_cast<QObject*>(sender)->connectNotify(signalSignature.constData()); return handle; @@ -2575,27 +2636,27 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho \list 1 \li Disconnect everything connected to an object's signals: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 26 + \snippet code/src_corelib_kernel_qobject.cpp 26 equivalent to the non-static overloaded function - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 27 + \snippet code/src_corelib_kernel_qobject.cpp 27 \li Disconnect everything connected to a specific signal: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 28 + \snippet code/src_corelib_kernel_qobject.cpp 28 equivalent to the non-static overloaded function - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 29 + \snippet code/src_corelib_kernel_qobject.cpp 29 \li Disconnect a specific receiver: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 30 + \snippet code/src_corelib_kernel_qobject.cpp 30 equivalent to the non-static overloaded function - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 31 + \snippet code/src_corelib_kernel_qobject.cpp 31 \endlist @@ -2697,7 +2758,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal, } if (!method) { - res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1, 0); + res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, 0); } else { const QMetaObject *rmeta = receiver->metaObject(); do { @@ -2708,7 +2769,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal, rmeta = rmeta->superClass(); if (method_index < 0) break; - res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index, 0); + res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0); method_found = true; } while ((rmeta = rmeta->superClass())); } @@ -2721,8 +2782,11 @@ bool QObject::disconnect(const QObject *sender, const char *signal, err_method_notfound(receiver, method_arg, "disconnect"); err_info_about_objects("disconnect", sender, receiver); } - if (res) + if (res) { + if (!signal) + const_cast<QObject*>(sender)->disconnectNotify(QMetaMethod()); const_cast<QObject*>(sender)->disconnectNotify(signal ? (signal - 1) : 0); + } return res; } @@ -2807,9 +2871,16 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, return false; } - if (!QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index, 0)) + if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, 0)) return false; + if (!signal.isValid()) { + // The signal is a wildcard, meaning all signals were disconnected. + // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify() + // per connection in this case. Call it once now, with an invalid + // QMetaMethod as argument, as documented. + const_cast<QObject*>(sender)->disconnectNotify(signal); + } const_cast<QObject*>(sender)->disconnectNotify(method.mobj ? signalSignature.constData() : 0); return true; } @@ -2840,18 +2911,30 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, /*! \fn void QObject::connectNotify(const char *signal) + \obsolete +*/ +void QObject::connectNotify(const char *) +{ +} + +/*! + \fn void QObject::disconnectNotify(const char *signal) + \obsolete +*/ +void QObject::disconnectNotify(const char *) +{ +} + +/*! + \since 5.0 This virtual function is called when something has been connected to \a signal in this object. - If you want to compare \a signal with a specific signal, use - QLatin1String and the \c SIGNAL() macro as follows: - - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 32 + If you want to compare \a signal with a specific signal, you can + use QMetaMethod::fromSignal() as follows: - If the signal contains multiple parameters or parameters that - contain spaces, call QMetaObject::normalizedSignature() on - the result of the \c SIGNAL() macro. + \snippet code/src_corelib_kernel_qobject.cpp 32 \warning This function violates the object-oriented principle of modularity. However, it might be useful when you need to perform @@ -2861,12 +2944,13 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, \sa connect(), disconnectNotify() */ -void QObject::connectNotify(const char *) +void QObject::connectNotify(const QMetaMethod &signal) { + Q_UNUSED(signal); } /*! - \fn void QObject::disconnectNotify(const char *signal) + \since 5.0 This virtual function is called when something has been disconnected from \a signal in this object. @@ -2874,6 +2958,11 @@ void QObject::connectNotify(const char *) See connectNotify() for an example of how to compare \a signal with a specific signal. + If all signals were disconnected from this object (e.g., the + signal argument to disconnect() was 0), disconnectNotify() + is only called once, and the \a signal will be an invalid + QMetaMethod (QMetaMethod::isValid() returns false). + \warning This function violates the object-oriented principle of modularity. However, it might be useful for optimizing access to expensive resources. @@ -2881,17 +2970,19 @@ void QObject::connectNotify(const char *) \sa disconnect(), connectNotify() */ -void QObject::disconnectNotify(const char *) +void QObject::disconnectNotify(const QMetaMethod &signal) { + Q_UNUSED(signal); } /* \internal convert a signal index from the method range to the signal range */ -static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_index) +static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index) { if (signal_index < 0) return signal_index; + const QMetaObject *metaObject = *base; while (metaObject && metaObject->methodOffset() > signal_index) metaObject = metaObject->superClass(); @@ -2902,6 +2993,7 @@ static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_in signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset; else signal_index = signal_index - methodOffset + signalOffset; + *base = metaObject; } return signal_index; } @@ -2916,8 +3008,9 @@ static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_in QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type, int *types) { - signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); - return Connection(QMetaObjectPrivate::connect(sender, signal_index, + const QMetaObject *smeta = sender->metaObject(); + signal_index = methodIndexToSignalIndex(&smeta, signal_index); + return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta, receiver, method_index, 0, //FIXME, we could speed this connection up by computing the relative index type, types)); @@ -2930,7 +3023,8 @@ QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_i the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection */ -QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, int signal_index, +QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, + int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index, const QMetaObject *rmeta, int type, int *types) { @@ -2940,8 +3034,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, i int method_offset = rmeta ? rmeta->methodOffset() : 0; Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6); QObjectPrivate::StaticMetaCallFunction callFunction = - (rmeta && rmeta->d.extradata) - ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0; + rmeta ? rmeta->d.static_metacall : 0; QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); @@ -2975,6 +3068,12 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, i c->callFunction = callFunction; QObjectPrivate::get(s)->addConnection(signal_index, c.data()); + + locker.unlock(); + QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index); + if (smethod.isValid()) + s->connectNotify(smethod); + return c.take(); } @@ -2983,8 +3082,9 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, i bool QMetaObject::disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index) { - signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); - return QMetaObjectPrivate::disconnect(sender, signal_index, + const QMetaObject *smeta = sender->metaObject(); + signal_index = methodIndexToSignalIndex(&smeta, signal_index); + return QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0); } @@ -2997,8 +3097,9 @@ one of these connections will be removed. bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, const QObject *receiver, int method_index) { - signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); - return QMetaObjectPrivate::disconnect(sender, signal_index, + const QMetaObject *smeta = sender->metaObject(); + signal_index = methodIndexToSignalIndex(&smeta, signal_index); + return QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0, QMetaObjectPrivate::DisconnectOne); } @@ -3047,7 +3148,8 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, /*! \internal Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex */ -bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, +bool QMetaObjectPrivate::disconnect(const QObject *sender, + int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index, void **slot, DisconnectType disconnectType) { @@ -3070,9 +3172,9 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, bool success = false; if (signal_index < 0) { // remove from all connection lists - for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { + for (int sig_index = -1; sig_index < connectionLists->count(); ++sig_index) { QObjectPrivate::Connection *c = - (*connectionLists)[signal_index].first; + (*connectionLists)[sig_index].first; if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) { success = true; connectionLists->dirty = true; @@ -3092,6 +3194,13 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, if (connectionLists->orphaned && !connectionLists->inUse) delete connectionLists; + locker.unlock(); + if (success) { + QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index); + if (smethod.isValid()) + s->disconnectNotify(smethod); + } + return success; } @@ -3101,13 +3210,13 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, Searches recursively for all child objects of the given \a object, and connects matching signals from them to slots of \a object that follow the following form: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 33 + \snippet code/src_corelib_kernel_qobject.cpp 33 Let's assume our object has a child object of type QPushButton with the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the button's \c{clicked()} signal would be: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 34 + \snippet code/src_corelib_kernel_qobject.cpp 34 \sa QObject::setObjectName() */ @@ -3131,7 +3240,8 @@ void QMetaObject::connectSlotsByName(QObject *o) int len = objName.length(); if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_') continue; - int sigIndex = co->d_func()->signalIndex(slot + len + 4); + const QMetaObject *smeta; + int sigIndex = co->d_func()->signalIndex(slot + len + 4, &smeta); if (sigIndex < 0) { // search for compatible signals const QMetaObject *smo = co->metaObject(); int slotlen = qstrlen(slot + len + 4) - 1; @@ -3141,8 +3251,9 @@ void QMetaObject::connectSlotsByName(QObject *o) continue; if (!qstrncmp(method.methodSignature().constData(), slot + len + 4, slotlen)) { + smeta = method.enclosingMetaObject(); int signalOffset, methodOffset; - computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset); + computeOffsets(smeta, &signalOffset, &methodOffset); sigIndex = k + - methodOffset + signalOffset; break; } @@ -3150,7 +3261,8 @@ void QMetaObject::connectSlotsByName(QObject *o) } if (sigIndex < 0) continue; - if (Connection(QMetaObjectPrivate::connect(co, sigIndex, o, i))) { + + if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) { foundIt = true; break; } @@ -3381,8 +3493,11 @@ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots. + + If \a meta is not 0, it is set to the meta-object where the signal was found. */ -int QObjectPrivate::signalIndex(const char *signalName) const +int QObjectPrivate::signalIndex(const char *signalName, + const QMetaObject **meta) const { Q_Q(const QObject); const QMetaObject *base = q->metaObject(); @@ -3396,6 +3511,8 @@ int QObjectPrivate::signalIndex(const char *signalName) const relative_index = QMetaObjectPrivate::originalClone(base, relative_index); int signalOffset, methodOffset; computeOffsets(base, &signalOffset, &methodOffset); + if (meta) + *meta = base; return relative_index + signalOffset; } @@ -3722,7 +3839,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 35 + \snippet code/src_corelib_kernel_qobject.cpp 35 \sa QMetaObject::classInfo() */ @@ -3736,9 +3853,9 @@ QDebug operator<<(QDebug dbg, const QObject *o) { Example: - \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 1 + \snippet tools/plugandpaintplugins/basictools/basictoolsplugin.h 1 \dots - \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 3 + \snippet tools/plugandpaintplugins/basictools/basictoolsplugin.h 3 See the \l{tools/plugandpaintplugins/basictools}{Plug & Paint Basic Tools} example for details. @@ -3755,7 +3872,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { they have additional features accessible through the \l {Meta-Object System}. - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 36 + \snippet code/src_corelib_kernel_qobject.cpp 36 The property name and type and the \c READ function are required. The type can be any type supported by QVariant, or it can be a @@ -3765,7 +3882,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 37 + \snippet code/src_corelib_kernel_qobject.cpp 37 For more details about how to use this macro, and a more detailed example of its use, see the discussion on \l {Qt's Property System}. @@ -3782,7 +3899,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 38 + \snippet code/src_corelib_kernel_qobject.cpp 38 If you want to register an enum that is declared in another class, the enum must be fully qualified with the name of the class @@ -3804,12 +3921,12 @@ QDebug operator<<(QDebug dbg, const QObject *o) { For example, in QLibrary, the \l{QLibrary::LoadHints}{LoadHints} flag is declared in the following way: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 39a + \snippet code/src_corelib_kernel_qobject.cpp 39a The declaration of the flags themselves is performed in the public section of the QLibrary class itself, using the \l Q_DECLARE_FLAGS() macro: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 39b + \snippet code/src_corelib_kernel_qobject.cpp 39b \note This macro takes care of registering individual flag values with the meta-object system, so it is unnecessary to use Q_ENUMS() @@ -3828,10 +3945,10 @@ QDebug operator<<(QDebug dbg, const QObject *o) { For example: - \snippet doc/src/snippets/signalsandslots/signalsandslots.h 1 + \snippet signalsandslots/signalsandslots.h 1 \codeline - \snippet doc/src/snippets/signalsandslots/signalsandslots.h 2 - \snippet doc/src/snippets/signalsandslots/signalsandslots.h 3 + \snippet signalsandslots/signalsandslots.h 2 + \snippet signalsandslots/signalsandslots.h 3 \note This macro requires the class to be a subclass of QObject. Use Q_GADGET instead of Q_OBJECT to enable the meta object system's support @@ -3927,7 +4044,7 @@ QDebug operator<<(QDebug dbg, const QObject *o) { be invoked via the meta-object system. The macro is written before the return type, as shown in the following example: - \snippet snippets/qmetaobject-invokable/window.h Window class with invokable method + \snippet qmetaobject-invokable/window.h Window class with invokable method The \c invokableMethod() function is marked up using Q_INVOKABLE, causing it to be registered with the meta-object system and enabling it to be @@ -3968,7 +4085,7 @@ void qDeleteInEventHandler(QObject *o) Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 44 + \snippet code/src_corelib_kernel_qobject.cpp 44 This example ensures that the label always displays the current line edit text. @@ -4003,7 +4120,7 @@ void qDeleteInEventHandler(QObject *o) scenes. If you try to use a queued connection and get the error message - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25 + \snippet code/src_corelib_kernel_qobject.cpp 25 make sure to declare the argument type with Q_DECLARE_METATYPE */ @@ -4029,11 +4146,11 @@ void qDeleteInEventHandler(QObject *o) Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 45 + \snippet code/src_corelib_kernel_qobject.cpp 45 If your compiler support C++11 lambda expressions, you can use them: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 46 + \snippet code/src_corelib_kernel_qobject.cpp 46 The connection will automatically disconnect if the sender is destroyed. */ @@ -4120,9 +4237,13 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa QMetaObject::Connection ret(c.take()); locker.unlock(); + QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index); + Q_ASSERT(method.isValid()); + s->connectNotify(method); + // reconstruct the signature to call connectNotify const char *sig; - QByteArray tmp_sig = senderMetaObject->method(signal_index - signalOffset + methodOffset).methodSignature(); + QByteArray tmp_sig = method.methodSignature(); sig = tmp_sig.constData(); QVarLengthArray<char> signalSignature(qstrlen(sig) + 2); signalSignature.data()[0] = char(QSIGNAL_CODE + '0'); @@ -4159,6 +4280,8 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) if (c->next) c->next->prev = c->prev; c->receiver = 0; + // disconnectNotify() not called (the signal index is unknown). + return true; } @@ -4178,19 +4301,19 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) \list 1 \li Disconnect everything connected to an object's signals: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 26 + \snippet code/src_corelib_kernel_qobject.cpp 26 \li Disconnect everything connected to a specific signal: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 47 + \snippet code/src_corelib_kernel_qobject.cpp 47 \li Disconnect a specific receiver: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 30 + \snippet code/src_corelib_kernel_qobject.cpp 30 \li Disconnect a connection from one specific signal to a specific slot: - \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 48 + \snippet code/src_corelib_kernel_qobject.cpp 48 \endlist @@ -4242,7 +4365,7 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject signal_index += signalOffset; } - return QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1, slot); + return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot); } /*! \class QMetaObject::Connection |