1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "qobject.h" |
43 | #include "qobject_p.h" |
44 | #include "qmetaobject_p.h" |
45 | |
46 | #include "qabstracteventdispatcher.h" |
47 | #include "qcoreapplication.h" |
48 | #include "qcoreapplication_p.h" |
49 | #include "qvariant.h" |
50 | #include "qmetaobject.h" |
51 | #include <qregexp.h> |
52 | #include <qthread.h> |
53 | #include <private/qthread_p.h> |
54 | #include <qdebug.h> |
55 | #include <qhash.h> |
56 | #include <qpair.h> |
57 | #include <qset.h> |
58 | #include <qsemaphore.h> |
59 | #include <qsharedpointer.h> |
60 | |
61 | #include <private/qorderedmutexlocker_p.h> |
62 | #include <private/qmutexpool_p.h> |
63 | |
64 | #include <new> |
65 | |
66 | #include <ctype.h> |
67 | #include <limits.h> |
68 | |
69 | QT_BEGIN_NAMESPACE |
70 | |
71 | static int DIRECT_CONNECTION_ONLY = 0; |
72 | |
73 | static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) |
74 | { |
75 | int *types = new int [typeNames.count() + 1]; |
76 | Q_CHECK_PTR(types); |
77 | for (int i = 0; i < typeNames.count(); ++i) { |
78 | const QByteArray typeName = typeNames.at(i); |
79 | if (typeName.endsWith('*')) |
80 | types[i] = QMetaType::VoidStar; |
81 | else |
82 | types[i] = QMetaType::type(typeName); |
83 | |
84 | if (!types[i]) { |
85 | qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" |
86 | "(Make sure '%s' is registered using qRegisterMetaType().)" , |
87 | typeName.constData(), typeName.constData()); |
88 | delete [] types; |
89 | return 0; |
90 | } |
91 | } |
92 | types[typeNames.count()] = 0; |
93 | |
94 | return types; |
95 | } |
96 | |
97 | static QBasicAtomicPointer<QMutexPool> signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0); |
98 | static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); |
99 | |
100 | /** \internal |
101 | * mutex to be locked when accessing the connectionlists or the senders list |
102 | */ |
103 | static inline QMutex *signalSlotLock(const QObject *o) |
104 | { |
105 | if (!signalSlotMutexes) { |
106 | QMutexPool *mp = new QMutexPool; |
107 | if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { |
108 | delete mp; |
109 | } |
110 | } |
111 | return signalSlotMutexes->get(o); |
112 | } |
113 | |
114 | extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) |
115 | { |
116 | objectCount.ref(); |
117 | } |
118 | |
119 | extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) |
120 | { |
121 | if(!objectCount.deref()) { |
122 | QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); |
123 | delete old; |
124 | } |
125 | } |
126 | |
127 | void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; |
128 | void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; |
129 | void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0; |
130 | |
131 | QObjectData::~QObjectData() {} |
132 | |
133 | QObjectPrivate::QObjectPrivate(int version) |
134 | : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0) |
135 | { |
136 | if (version != QObjectPrivateVersion) |
137 | qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)" , |
138 | version, QObjectPrivateVersion); |
139 | |
140 | // QObjectData initialization |
141 | q_ptr = 0; |
142 | parent = 0; // no parent yet. It is set by setParent() |
143 | isWidget = false; // assume not a widget object |
144 | pendTimer = false; // no timers yet |
145 | blockSig = false; // not blocking signals |
146 | wasDeleted = false; // double-delete catcher |
147 | sendChildEvents = true; // if we should send ChildInsert and ChildRemove events to parent |
148 | receiveChildEvents = true; |
149 | postedEvents = 0; |
150 | extraData = 0; |
151 | connectedSignals[0] = connectedSignals[1] = 0; |
152 | inThreadChangeEvent = false; |
153 | #ifdef QT_JAMBI_BUILD |
154 | inEventHandler = false; |
155 | deleteWatch = 0; |
156 | #endif |
157 | metaObject = 0; |
158 | hasGuards = false; |
159 | } |
160 | |
161 | QObjectPrivate::~QObjectPrivate() |
162 | { |
163 | if (pendTimer) { |
164 | // unregister pending timers |
165 | if (threadData && threadData->eventDispatcher) |
166 | threadData->eventDispatcher->unregisterTimers(q_ptr); |
167 | } |
168 | |
169 | if (postedEvents) |
170 | QCoreApplication::removePostedEvents(q_ptr, 0); |
171 | |
172 | if (threadData) |
173 | threadData->deref(); |
174 | |
175 | delete static_cast<QAbstractDynamicMetaObject*>(metaObject); |
176 | #ifdef QT_JAMBI_BUILD |
177 | if (deleteWatch) |
178 | *deleteWatch = 1; |
179 | #endif |
180 | #ifndef QT_NO_USERDATA |
181 | if (extraData) |
182 | qDeleteAll(extraData->userData); |
183 | delete extraData; |
184 | #endif |
185 | } |
186 | |
187 | |
188 | #ifdef QT_JAMBI_BUILD |
189 | int *QObjectPrivate::setDeleteWatch(QObjectPrivate *d, int *w) { |
190 | int *old = d->deleteWatch; |
191 | d->deleteWatch = w; |
192 | return old; |
193 | } |
194 | |
195 | |
196 | void QObjectPrivate::resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch) { |
197 | if (!deleteWatch) |
198 | d->deleteWatch = oldWatch; |
199 | |
200 | if (oldWatch) |
201 | *oldWatch = deleteWatch; |
202 | } |
203 | #endif |
204 | |
205 | #ifdef QT3_SUPPORT |
206 | void QObjectPrivate::sendPendingChildInsertedEvents() |
207 | { |
208 | Q_Q(QObject); |
209 | for (int i = 0; i < pendingChildInsertedEvents.size(); ++i) { |
210 | QObject *c = pendingChildInsertedEvents.at(i).data(); |
211 | if (!c || c->parent() != q) |
212 | continue; |
213 | QChildEvent childEvent(QEvent::ChildInserted, c); |
214 | QCoreApplication::sendEvent(q, &childEvent); |
215 | } |
216 | pendingChildInsertedEvents.clear(); |
217 | } |
218 | |
219 | #endif |
220 | |
221 | |
222 | /*!\internal |
223 | For a given metaobject, compute the signal offset, and the method offset (including signals) |
224 | */ |
225 | static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset) |
226 | { |
227 | *signalOffset = *methodOffset = 0; |
228 | const QMetaObject *m = metaobject->d.superdata; |
229 | while (m) { |
230 | const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m); |
231 | *methodOffset += d->methodCount; |
232 | *signalOffset += (d->revision >= 4) ? d->signalCount : d->methodCount; |
233 | /*Before Qt 4.6 (revision 4), the signalCount information was not generated by moc. |
234 | so for compatibility we consider all the method as slot for old moc output*/ |
235 | m = m->d.superdata; |
236 | } |
237 | } |
238 | |
239 | /* |
240 | This vector contains the all connections from an object. |
241 | |
242 | Each object may have one vector containing the lists of |
243 | connections for a given signal. The index in the vector correspond |
244 | to the signal index. The signal index is the one returned by |
245 | QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal). |
246 | Negative index means connections to all signals. |
247 | |
248 | This vector is protected by the object mutex (signalSlotMutexes()) |
249 | |
250 | Each Connection is also part of a 'senders' linked list. The mutex |
251 | of the receiver must be locked when touching the pointers of this |
252 | linked list. |
253 | */ |
254 | class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList> |
255 | { |
256 | public: |
257 | bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse |
258 | bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet |
259 | int inUse; //number of functions that are currently accessing this object or its connections |
260 | QObjectPrivate::ConnectionList allsignals; |
261 | |
262 | QObjectConnectionListVector() |
263 | : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0) |
264 | { } |
265 | |
266 | QObjectPrivate::ConnectionList &operator[](int at) |
267 | { |
268 | if (at < 0) |
269 | return allsignals; |
270 | return QVector<QObjectPrivate::ConnectionList>::operator[](at); |
271 | } |
272 | }; |
273 | |
274 | // Used by QAccessibleWidget |
275 | bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const |
276 | { |
277 | Q_Q(const QObject); |
278 | int signal_index = signalIndex(signal); |
279 | if (signal_index < 0) |
280 | return false; |
281 | QMutexLocker locker(signalSlotLock(q)); |
282 | if (connectionLists) { |
283 | if (signal_index < connectionLists->count()) { |
284 | const QObjectPrivate::Connection *c = |
285 | connectionLists->at(signal_index).first; |
286 | |
287 | while (c) { |
288 | if (c->receiver == receiver) |
289 | return true; |
290 | c = c->nextConnectionList; |
291 | } |
292 | } |
293 | } |
294 | return false; |
295 | } |
296 | |
297 | // Used by QAccessibleWidget |
298 | QObjectList QObjectPrivate::receiverList(const char *signal) const |
299 | { |
300 | Q_Q(const QObject); |
301 | QObjectList returnValue; |
302 | int signal_index = signalIndex(signal); |
303 | if (signal_index < 0) |
304 | return returnValue; |
305 | QMutexLocker locker(signalSlotLock(q)); |
306 | if (connectionLists) { |
307 | if (signal_index < connectionLists->count()) { |
308 | const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first; |
309 | |
310 | while (c) { |
311 | if (c->receiver) |
312 | returnValue << c->receiver; |
313 | c = c->nextConnectionList; |
314 | } |
315 | } |
316 | } |
317 | return returnValue; |
318 | } |
319 | |
320 | // Used by QAccessibleWidget |
321 | QObjectList QObjectPrivate::senderList() const |
322 | { |
323 | QObjectList returnValue; |
324 | QMutexLocker locker(signalSlotLock(q_func())); |
325 | for (Connection *c = senders; c; c = c->next) |
326 | returnValue << c->sender; |
327 | return returnValue; |
328 | } |
329 | |
330 | void QObjectPrivate::addConnection(int signal, Connection *c) |
331 | { |
332 | if (!connectionLists) |
333 | connectionLists = new QObjectConnectionListVector(); |
334 | if (signal >= connectionLists->count()) |
335 | connectionLists->resize(signal + 1); |
336 | |
337 | ConnectionList &connectionList = (*connectionLists)[signal]; |
338 | if (connectionList.last) { |
339 | connectionList.last->nextConnectionList = c; |
340 | } else { |
341 | connectionList.first = c; |
342 | } |
343 | connectionList.last = c; |
344 | |
345 | cleanConnectionLists(); |
346 | } |
347 | |
348 | void QObjectPrivate::cleanConnectionLists() |
349 | { |
350 | if (connectionLists->dirty && !connectionLists->inUse) { |
351 | // remove broken connections |
352 | for (int signal = -1; signal < connectionLists->count(); ++signal) { |
353 | QObjectPrivate::ConnectionList &connectionList = |
354 | (*connectionLists)[signal]; |
355 | |
356 | // Set to the last entry in the connection list that was *not* |
357 | // deleted. This is needed to update the list's last pointer |
358 | // at the end of the cleanup. |
359 | QObjectPrivate::Connection *last = 0; |
360 | |
361 | QObjectPrivate::Connection **prev = &connectionList.first; |
362 | QObjectPrivate::Connection *c = *prev; |
363 | while (c) { |
364 | if (c->receiver) { |
365 | last = c; |
366 | prev = &c->nextConnectionList; |
367 | c = *prev; |
368 | } else { |
369 | QObjectPrivate::Connection *next = c->nextConnectionList; |
370 | *prev = next; |
371 | delete c; |
372 | c = next; |
373 | } |
374 | } |
375 | |
376 | // Correct the connection list's last pointer. |
377 | // As conectionList.last could equal last, this could be a noop |
378 | connectionList.last = last; |
379 | } |
380 | connectionLists->dirty = false; |
381 | } |
382 | } |
383 | |
384 | typedef QMultiHash<QObject *, QObject **> GuardHash; |
385 | Q_GLOBAL_STATIC(GuardHash, guardHash) |
386 | Q_GLOBAL_STATIC(QMutex, guardHashLock) |
387 | |
388 | /*!\internal |
389 | */ |
390 | void QMetaObject::addGuard(QObject **ptr) |
391 | { |
392 | if (!*ptr) |
393 | return; |
394 | GuardHash *hash = guardHash(); |
395 | if (!hash) { |
396 | *ptr = 0; |
397 | return; |
398 | } |
399 | QMutexLocker locker(guardHashLock()); |
400 | QObjectPrivate::get(*ptr)->hasGuards = true; |
401 | hash->insert(*ptr, ptr); |
402 | } |
403 | |
404 | /*!\internal |
405 | */ |
406 | void QMetaObject::removeGuard(QObject **ptr) |
407 | { |
408 | if (!*ptr) |
409 | return; |
410 | GuardHash *hash = guardHash(); |
411 | /* check that the hash is empty - otherwise we might detach |
412 | the shared_null hash, which will alloc, which is not nice */ |
413 | if (!hash || hash->isEmpty()) |
414 | return; |
415 | QMutexLocker locker(guardHashLock()); |
416 | if (!*ptr) //check again, under the lock |
417 | return; |
418 | GuardHash::iterator it = hash->find(*ptr); |
419 | const GuardHash::iterator end = hash->end(); |
420 | bool more = false; //if the QObject has more pointer attached to it. |
421 | for (; it.key() == *ptr && it != end; ++it) { |
422 | if (it.value() == ptr) { |
423 | it = hash->erase(it); |
424 | if (!more) more = (it != end && it.key() == *ptr); |
425 | break; |
426 | } |
427 | more = true; |
428 | } |
429 | if (!more) |
430 | QObjectPrivate::get(*ptr)->hasGuards = false; |
431 | } |
432 | |
433 | /*!\internal |
434 | */ |
435 | void QMetaObject::changeGuard(QObject **ptr, QObject *o) |
436 | { |
437 | GuardHash *hash = guardHash(); |
438 | if (!hash) { |
439 | *ptr = 0; |
440 | return; |
441 | } |
442 | QMutexLocker locker(guardHashLock()); |
443 | if (o) { |
444 | hash->insert(o, ptr); |
445 | QObjectPrivate::get(o)->hasGuards = true; |
446 | } |
447 | if (*ptr) { |
448 | bool more = false; //if the QObject has more pointer attached to it. |
449 | GuardHash::iterator it = hash->find(*ptr); |
450 | const GuardHash::iterator end = hash->end(); |
451 | for (; it.key() == *ptr && it != end; ++it) { |
452 | if (it.value() == ptr) { |
453 | it = hash->erase(it); |
454 | if (!more) more = (it != end && it.key() == *ptr); |
455 | break; |
456 | } |
457 | more = true; |
458 | } |
459 | if (!more) |
460 | QObjectPrivate::get(*ptr)->hasGuards = false; |
461 | } |
462 | *ptr = o; |
463 | } |
464 | |
465 | /*! \internal |
466 | */ |
467 | void QObjectPrivate::clearGuards(QObject *object) |
468 | { |
469 | GuardHash *hash = 0; |
470 | QMutex *mutex = 0; |
471 | QT_TRY { |
472 | hash = guardHash(); |
473 | mutex = guardHashLock(); |
474 | } QT_CATCH(const std::bad_alloc &) { |
475 | // do nothing in case of OOM - code below is safe |
476 | } |
477 | |
478 | /* check that the hash is empty - otherwise we might detach |
479 | the shared_null hash, which will alloc, which is not nice */ |
480 | if (hash && !hash->isEmpty()) { |
481 | QMutexLocker locker(mutex); |
482 | GuardHash::iterator it = hash->find(object); |
483 | const GuardHash::iterator end = hash->end(); |
484 | while (it.key() == object && it != end) { |
485 | *it.value() = 0; |
486 | it = hash->erase(it); |
487 | } |
488 | } |
489 | } |
490 | |
491 | /*! \internal |
492 | */ |
493 | QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, |
494 | const QObject *sender, int signalId, |
495 | int nargs, int *types, void **args, QSemaphore *semaphore) |
496 | : QEvent(MetaCall), sender_(sender), signalId_(signalId), |
497 | nargs_(nargs), types_(types), args_(args), semaphore_(semaphore), |
498 | callFunction_(callFunction), method_offset_(method_offset), method_relative_(method_relative) |
499 | { } |
500 | |
501 | /*! \internal |
502 | */ |
503 | QMetaCallEvent::~QMetaCallEvent() |
504 | { |
505 | if (types_) { |
506 | for (int i = 0; i < nargs_; ++i) { |
507 | if (types_[i] && args_[i]) |
508 | QMetaType::destroy(types_[i], args_[i]); |
509 | } |
510 | qFree(types_); |
511 | qFree(args_); |
512 | } |
513 | #ifndef QT_NO_THREAD |
514 | if (semaphore_) |
515 | semaphore_->release(); |
516 | #endif |
517 | } |
518 | |
519 | /*! \internal |
520 | */ |
521 | void QMetaCallEvent::placeMetaCall(QObject *object) |
522 | { |
523 | if (callFunction_) { |
524 | callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_); |
525 | } else { |
526 | QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_); |
527 | } |
528 | } |
529 | |
530 | /*! |
531 | \class QObject |
532 | \brief The QObject class is the base class of all Qt objects. |
533 | |
534 | \ingroup objectmodel |
535 | |
536 | \reentrant |
537 | |
538 | QObject is the heart of the Qt \l{Object Model}. The central |
539 | feature in this model is a very powerful mechanism for seamless |
540 | object communication called \l{signals and slots}. You can |
541 | connect a signal to a slot with connect() and destroy the |
542 | connection with disconnect(). To avoid never ending notification |
543 | loops you can temporarily block signals with blockSignals(). The |
544 | protected functions connectNotify() and disconnectNotify() make |
545 | it possible to track connections. |
546 | |
547 | QObjects organize themselves in \l {Object Trees & Ownership} |
548 | {object trees}. When you create a QObject with another object as |
549 | parent, the object will automatically add itself to the parent's |
550 | children() list. The parent takes ownership of the object; i.e., |
551 | it will automatically delete its children in its destructor. You |
552 | can look for an object by name and optionally type using |
553 | findChild() or findChildren(). |
554 | |
555 | Every object has an objectName() and its class name can be found |
556 | via the corresponding metaObject() (see QMetaObject::className()). |
557 | You can determine whether the object's class inherits another |
558 | class in the QObject inheritance hierarchy by using the |
559 | inherits() function. |
560 | |
561 | When an object is deleted, it emits a destroyed() signal. You can |
562 | catch this signal to avoid dangling references to QObjects. |
563 | |
564 | QObjects can receive events through event() and filter the events |
565 | of other objects. See installEventFilter() and eventFilter() for |
566 | details. A convenience handler, childEvent(), can be reimplemented |
567 | to catch child events. |
568 | |
569 | Last but not least, QObject provides the basic timer support in |
570 | Qt; see QTimer for high-level support for timers. |
571 | |
572 | Notice that the Q_OBJECT macro is mandatory for any object that |
573 | implements signals, slots or properties. You also need to run the |
574 | \l{moc}{Meta Object Compiler} on the source file. We strongly |
575 | recommend the use of this macro in all subclasses of QObject |
576 | regardless of whether or not they actually use signals, slots and |
577 | properties, since failure to do so may lead certain functions to |
578 | exhibit strange behavior. |
579 | |
580 | All Qt widgets inherit QObject. The convenience function |
581 | isWidgetType() returns whether an object is actually a widget. It |
582 | is much faster than |
583 | \l{qobject_cast()}{qobject_cast}<QWidget *>(\e{obj}) or |
584 | \e{obj}->\l{inherits()}{inherits}("QWidget"). |
585 | |
586 | Some QObject functions, e.g. children(), return a QObjectList. |
587 | QObjectList is a typedef for QList<QObject *>. |
588 | |
589 | \section1 Thread Affinity |
590 | |
591 | A QObject instance is said to have a \e{thread affinity}, or that |
592 | it \e{lives} in a certain thread. When a QObject receives a |
593 | \l{Qt::QueuedConnection}{queued signal} or a \l{The Event |
594 | System#Sending Events}{posted event}, the slot or event handler |
595 | will run in the thread that the object lives in. |
596 | |
597 | \note If a QObject has no thread affinity (that is, if thread() |
598 | returns zero), or if it lives in a thread that has no running event |
599 | loop, then it cannot receive queued signals or posted events. |
600 | |
601 | By default, a QObject lives in the thread in which it is created. |
602 | An object's thread affinity can be queried using thread() and |
603 | changed using moveToThread(). |
604 | |
605 | All QObjects must live in the same thread as their parent. Consequently: |
606 | |
607 | \list |
608 | \li setParent() will fail if the two QObjects involved live in |
609 | different threads. |
610 | \li When a QObject is moved to another thread, all its children |
611 | will be automatically moved too. |
612 | \li moveToThread() will fail if the QObject has a parent. |
613 | \li If \l{QObject}s are created within QThread::run(), they cannot |
614 | become children of the QThread object because the QThread does |
615 | not live in the thread that calls QThread::run(). |
616 | \endlist |
617 | |
618 | \note A QObject's member variables \e{do not} automatically become |
619 | its children. The parent-child relationship must be set by either |
620 | passing a pointer to the child's \l{QObject()}{constructor}, or by |
621 | calling setParent(). Without this step, the object's member variables |
622 | will remain in the old thread when moveToThread() is called. |
623 | |
624 | \target No copy constructor |
625 | \section1 No copy constructor or assignment operator |
626 | |
627 | QObject has neither a copy constructor nor an assignment operator. |
628 | This is by design. Actually, they are declared, but in a |
629 | \c{private} section with the macro Q_DISABLE_COPY(). In fact, all |
630 | Qt classes derived from QObject (direct or indirect) use this |
631 | macro to declare their copy constructor and assignment operator to |
632 | be private. The reasoning is found in the discussion on |
633 | \l{Identity vs Value} {Identity vs Value} on the Qt \l{Object |
634 | Model} page. |
635 | |
636 | The main consequence is that you should use pointers to QObject |
637 | (or to your QObject subclass) where you might otherwise be tempted |
638 | to use your QObject subclass as a value. For example, without a |
639 | copy constructor, you can't use a subclass of QObject as the value |
640 | to be stored in one of the container classes. You must store |
641 | pointers. |
642 | |
643 | \section1 Auto-Connection |
644 | |
645 | Qt's meta-object system provides a mechanism to automatically connect |
646 | signals and slots between QObject subclasses and their children. As long |
647 | as objects are defined with suitable object names, and slots follow a |
648 | simple naming convention, this connection can be performed at run-time |
649 | by the QMetaObject::connectSlotsByName() function. |
650 | |
651 | \l uic generates code that invokes this function to enable |
652 | auto-connection to be performed between widgets on forms created |
653 | with \QD. More information about using auto-connection with \QD is |
654 | given in the \l{Using a Designer UI File in Your Application} section of |
655 | the \QD manual. |
656 | |
657 | \section1 Dynamic Properties |
658 | |
659 | From Qt 4.2, dynamic properties can be added to and removed from QObject |
660 | instances at run-time. Dynamic properties do not need to be declared at |
661 | compile-time, yet they provide the same advantages as static properties |
662 | and are manipulated using the same API - using property() to read them |
663 | and setProperty() to write them. |
664 | |
665 | From Qt 4.3, dynamic properties are supported by |
666 | \l{Qt Designer's Widget Editing Mode#The Property Editor}{Qt Designer}, |
667 | and both standard Qt widgets and user-created forms can be given dynamic |
668 | properties. |
669 | |
670 | \section1 Internationalization (i18n) |
671 | |
672 | All QObject subclasses support Qt's translation features, making it possible |
673 | to translate an application's user interface into different languages. |
674 | |
675 | To make user-visible text translatable, it must be wrapped in calls to |
676 | the tr() function. This is explained in detail in the |
677 | \l{Writing Source Code for Translation} document. |
678 | |
679 | \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY() |
680 | \sa {Object Trees & Ownership} |
681 | */ |
682 | |
683 | /*! |
684 | \relates QObject |
685 | |
686 | Returns a pointer to the object named \a name that inherits \a |
687 | type and with a given \a parent. |
688 | |
689 | Returns 0 if there is no such child. |
690 | |
691 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 0 |
692 | */ |
693 | |
694 | void *qt_find_obj_child(QObject *parent, const char *type, const QString &name) |
695 | { |
696 | QObjectList list = parent->children(); |
697 | if (list.size() == 0) return 0; |
698 | for (int i = 0; i < list.size(); ++i) { |
699 | QObject *obj = list.at(i); |
700 | if (name == obj->objectName() && obj->inherits(type)) |
701 | return obj; |
702 | } |
703 | return 0; |
704 | } |
705 | |
706 | |
707 | /***************************************************************************** |
708 | QObject member functions |
709 | *****************************************************************************/ |
710 | |
711 | // check the constructor's parent thread argument |
712 | static bool check_parent_thread(QObject *parent, |
713 | QThreadData *parentThreadData, |
714 | QThreadData *currentThreadData) |
715 | { |
716 | if (parent && parentThreadData != currentThreadData) { |
717 | QThread *parentThread = parentThreadData->thread; |
718 | QThread *currentThread = currentThreadData->thread; |
719 | qWarning("QObject: Cannot create children for a parent that is in a different thread.\n" |
720 | "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)" , |
721 | parent->metaObject()->className(), |
722 | parent, |
723 | parentThread ? parentThread->metaObject()->className() : "QThread" , |
724 | parentThread, |
725 | currentThread ? currentThread->metaObject()->className() : "QThread" , |
726 | currentThread); |
727 | return false; |
728 | } |
729 | return true; |
730 | } |
731 | |
732 | /*! |
733 | Constructs an object with parent object \a parent. |
734 | |
735 | The parent of an object may be viewed as the object's owner. For |
736 | instance, a \l{QDialog}{dialog box} is the parent of the \gui OK |
737 | and \gui Cancel buttons it contains. |
738 | |
739 | The destructor of a parent object destroys all child objects. |
740 | |
741 | Setting \a parent to 0 constructs an object with no parent. If the |
742 | object is a widget, it will become a top-level window. |
743 | |
744 | \sa parent(), findChild(), findChildren() |
745 | */ |
746 | |
747 | QObject::QObject(QObject *parent) |
748 | : d_ptr(new QObjectPrivate) |
749 | { |
750 | Q_D(QObject); |
751 | d_ptr->q_ptr = this; |
752 | d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); |
753 | d->threadData->ref(); |
754 | if (parent) { |
755 | QT_TRY { |
756 | if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) |
757 | parent = 0; |
758 | setParent(parent); |
759 | } QT_CATCH(...) { |
760 | d->threadData->deref(); |
761 | QT_RETHROW; |
762 | } |
763 | } |
764 | qt_addObject(this); |
765 | } |
766 | |
767 | #ifdef QT3_SUPPORT |
768 | /*! |
769 | \overload QObject() |
770 | \obsolete |
771 | |
772 | Creates a new QObject with the given \a parent and object \a name. |
773 | */ |
774 | QObject::QObject(QObject *parent, const char *name) |
775 | : d_ptr(new QObjectPrivate) |
776 | { |
777 | Q_D(QObject); |
778 | qt_addObject(d_ptr->q_ptr = this); |
779 | d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); |
780 | d->threadData->ref(); |
781 | if (parent) { |
782 | if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) |
783 | parent = 0; |
784 | setParent(parent); |
785 | } |
786 | setObjectName(QString::fromAscii(name)); |
787 | } |
788 | #endif |
789 | |
790 | /*! \internal |
791 | */ |
792 | QObject::QObject(QObjectPrivate &dd, QObject *parent) |
793 | : d_ptr(&dd) |
794 | { |
795 | Q_D(QObject); |
796 | d_ptr->q_ptr = this; |
797 | d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current(); |
798 | d->threadData->ref(); |
799 | if (parent) { |
800 | QT_TRY { |
801 | if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)) |
802 | parent = 0; |
803 | if (d->isWidget) { |
804 | if (parent) { |
805 | d->parent = parent; |
806 | d->parent->d_func()->children.append(this); |
807 | } |
808 | // no events sent here, this is done at the end of the QWidget constructor |
809 | } else { |
810 | setParent(parent); |
811 | } |
812 | } QT_CATCH(...) { |
813 | d->threadData->deref(); |
814 | QT_RETHROW; |
815 | } |
816 | } |
817 | qt_addObject(this); |
818 | } |
819 | |
820 | /*! |
821 | Destroys the object, deleting all its child objects. |
822 | |
823 | All signals to and from the object are automatically disconnected, and |
824 | any pending posted events for the object are removed from the event |
825 | queue. However, it is often safer to use deleteLater() rather than |
826 | deleting a QObject subclass directly. |
827 | |
828 | \warning All child objects are deleted. If any of these objects |
829 | are on the stack or global, sooner or later your program will |
830 | crash. We do not recommend holding pointers to child objects from |
831 | outside the parent. If you still do, the destroyed() signal gives |
832 | you an opportunity to detect when an object is destroyed. |
833 | |
834 | \warning Deleting a QObject while pending events are waiting to |
835 | be delivered can cause a crash. You must not delete the QObject |
836 | directly if it exists in a different thread than the one currently |
837 | executing. Use deleteLater() instead, which will cause the event |
838 | loop to delete the object after all pending events have been |
839 | delivered to it. |
840 | |
841 | \sa deleteLater() |
842 | */ |
843 | |
844 | QObject::~QObject() |
845 | { |
846 | Q_D(QObject); |
847 | d->wasDeleted = true; |
848 | d->blockSig = 0; // unblock signals so we always emit destroyed() |
849 | |
850 | if (d->hasGuards && !d->isWidget) { |
851 | // set all QPointers for this object to zero - note that |
852 | // ~QWidget() does this for us, so we don't have to do it twice |
853 | QObjectPrivate::clearGuards(this); |
854 | } |
855 | |
856 | if (d->sharedRefcount) { |
857 | if (d->sharedRefcount->strongref > 0) { |
858 | qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash." ); |
859 | // but continue deleting, it's too late to stop anyway |
860 | } |
861 | |
862 | // indicate to all QWeakPointers that this QObject has now been deleted |
863 | d->sharedRefcount->strongref = 0; |
864 | if (!d->sharedRefcount->weakref.deref()) |
865 | delete d->sharedRefcount; |
866 | } |
867 | |
868 | |
869 | if (d->isSignalConnected(0)) { |
870 | QT_TRY { |
871 | emit destroyed(this); |
872 | } QT_CATCH(...) { |
873 | // all the signal/slots connections are still in place - if we don't |
874 | // quit now, we will crash pretty soon. |
875 | qWarning("Detected an unexpected exception in ~QObject while emitting destroyed()." ); |
876 | QT_RETHROW; |
877 | } |
878 | } |
879 | |
880 | if (d->declarativeData) |
881 | QAbstractDeclarativeData::destroyed(d->declarativeData, this); |
882 | |
883 | // set ref to zero to indicate that this object has been deleted |
884 | if (d->currentSender != 0) |
885 | d->currentSender->ref = 0; |
886 | d->currentSender = 0; |
887 | |
888 | if (d->connectionLists || d->senders) { |
889 | QMutex *signalSlotMutex = signalSlotLock(this); |
890 | QMutexLocker locker(signalSlotMutex); |
891 | |
892 | // disconnect all receivers |
893 | if (d->connectionLists) { |
894 | ++d->connectionLists->inUse; |
895 | int connectionListsCount = d->connectionLists->count(); |
896 | for (int signal = -1; signal < connectionListsCount; ++signal) { |
897 | QObjectPrivate::ConnectionList &connectionList = |
898 | (*d->connectionLists)[signal]; |
899 | |
900 | while (QObjectPrivate::Connection *c = connectionList.first) { |
901 | if (!c->receiver) { |
902 | connectionList.first = c->nextConnectionList; |
903 | delete c; |
904 | continue; |
905 | } |
906 | |
907 | QMutex *m = signalSlotLock(c->receiver); |
908 | bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); |
909 | |
910 | if (c->receiver) { |
911 | *c->prev = c->next; |
912 | if (c->next) c->next->prev = c->prev; |
913 | } |
914 | if (needToUnlock) |
915 | m->unlockInline(); |
916 | |
917 | connectionList.first = c->nextConnectionList; |
918 | delete c; |
919 | } |
920 | } |
921 | |
922 | if (!--d->connectionLists->inUse) { |
923 | delete d->connectionLists; |
924 | } else { |
925 | d->connectionLists->orphaned = true; |
926 | } |
927 | d->connectionLists = 0; |
928 | } |
929 | |
930 | // disconnect all senders |
931 | QObjectPrivate::Connection *node = d->senders; |
932 | while (node) { |
933 | QObject *sender = node->sender; |
934 | QMutex *m = signalSlotLock(sender); |
935 | node->prev = &node; |
936 | bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); |
937 | //the node has maybe been removed while the mutex was unlocked in relock? |
938 | if (!node || node->sender != sender) { |
939 | m->unlockInline(); |
940 | continue; |
941 | } |
942 | node->receiver = 0; |
943 | QObjectConnectionListVector *senderLists = sender->d_func()->connectionLists; |
944 | if (senderLists) |
945 | senderLists->dirty = true; |
946 | |
947 | node = node->next; |
948 | if (needToUnlock) |
949 | m->unlockInline(); |
950 | } |
951 | } |
952 | |
953 | if (!d->children.isEmpty()) |
954 | d->deleteChildren(); |
955 | |
956 | qt_removeObject(this); |
957 | |
958 | if (d->parent) // remove it from parent object |
959 | d->setParent_helper(0); |
960 | |
961 | #ifdef QT_JAMBI_BUILD |
962 | if (d->inEventHandler) { |
963 | qWarning("QObject: Do not delete object, '%s', during its event handler!" , |
964 | objectName().isNull() ? "unnamed" : qPrintable(objectName())); |
965 | } |
966 | #endif |
967 | } |
968 | |
969 | QObjectPrivate::Connection::~Connection() |
970 | { |
971 | if (argumentTypes != &DIRECT_CONNECTION_ONLY) |
972 | delete [] static_cast<int *>(argumentTypes); |
973 | } |
974 | |
975 | |
976 | /*! |
977 | \fn QMetaObject *QObject::metaObject() const |
978 | |
979 | Returns a pointer to the meta-object of this object. |
980 | |
981 | A meta-object contains information about a class that inherits |
982 | QObject, e.g. class name, superclass name, properties, signals and |
983 | slots. Every QObject subclass that contains the Q_OBJECT macro will have a |
984 | meta-object. |
985 | |
986 | The meta-object information is required by the signal/slot |
987 | connection mechanism and the property system. The inherits() |
988 | function also makes use of the meta-object. |
989 | |
990 | If you have no pointer to an actual object instance but still |
991 | want to access the meta-object of a class, you can use \l |
992 | staticMetaObject. |
993 | |
994 | Example: |
995 | |
996 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 1 |
997 | |
998 | \sa staticMetaObject |
999 | */ |
1000 | |
1001 | /*! |
1002 | \variable QObject::staticMetaObject |
1003 | |
1004 | This variable stores the meta-object for the class. |
1005 | |
1006 | A meta-object contains information about a class that inherits |
1007 | QObject, e.g. class name, superclass name, properties, signals and |
1008 | slots. Every class that contains the Q_OBJECT macro will also have |
1009 | a meta-object. |
1010 | |
1011 | The meta-object information is required by the signal/slot |
1012 | connection mechanism and the property system. The inherits() |
1013 | function also makes use of the meta-object. |
1014 | |
1015 | If you have a pointer to an object, you can use metaObject() to |
1016 | retrieve the meta-object associated with that object. |
1017 | |
1018 | Example: |
1019 | |
1020 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 2 |
1021 | |
1022 | \sa metaObject() |
1023 | */ |
1024 | |
1025 | /*! \fn T *qobject_cast<T *>(QObject *object) |
1026 | \relates QObject |
1027 | |
1028 | Returns the given \a object cast to type T if the object is of type |
1029 | T (or of a subclass); otherwise returns 0. If \a object is 0 then |
1030 | it will also return 0. |
1031 | |
1032 | The class T must inherit (directly or indirectly) QObject and be |
1033 | declared with the \l Q_OBJECT macro. |
1034 | |
1035 | A class is considered to inherit itself. |
1036 | |
1037 | Example: |
1038 | |
1039 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 3 |
1040 | |
1041 | The qobject_cast() function behaves similarly to the standard C++ |
1042 | \c dynamic_cast(), with the advantages that it doesn't require |
1043 | RTTI support and it works across dynamic library boundaries. |
1044 | |
1045 | qobject_cast() can also be used in conjunction with interfaces; |
1046 | see the \l{tools/plugandpaint}{Plug & Paint} example for details. |
1047 | |
1048 | \warning If T isn't declared with the Q_OBJECT macro, this |
1049 | function's return value is undefined. |
1050 | |
1051 | \sa QObject::inherits() |
1052 | */ |
1053 | |
1054 | /*! |
1055 | \fn bool QObject::inherits(const char *className) const |
1056 | |
1057 | Returns true if this object is an instance of a class that |
1058 | inherits \a className or a QObject subclass that inherits \a |
1059 | className; otherwise returns false. |
1060 | |
1061 | A class is considered to inherit itself. |
1062 | |
1063 | Example: |
1064 | |
1065 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 4 |
1066 | |
1067 | If you need to determine whether an object is an instance of a particular |
1068 | class for the purpose of casting it, consider using qobject_cast<Type *>(object) |
1069 | instead. |
1070 | |
1071 | \sa metaObject(), qobject_cast() |
1072 | */ |
1073 | |
1074 | /*! |
1075 | \property QObject::objectName |
1076 | |
1077 | \brief the name of this object |
1078 | |
1079 | You can find an object by name (and type) using findChild(). You can |
1080 | find a set of objects with findChildren(). |
1081 | |
1082 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 5 |
1083 | |
1084 | By default, this property contains an empty string. |
1085 | |
1086 | \sa metaObject(), QMetaObject::className() |
1087 | */ |
1088 | |
1089 | QString QObject::objectName() const |
1090 | { |
1091 | Q_D(const QObject); |
1092 | return d->objectName; |
1093 | } |
1094 | |
1095 | /* |
1096 | Sets the object's name to \a name. |
1097 | */ |
1098 | void QObject::setObjectName(const QString &name) |
1099 | { |
1100 | Q_D(QObject); |
1101 | bool objectNameChanged = d->declarativeData && d->objectName != name; |
1102 | |
1103 | d->objectName = name; |
1104 | |
1105 | if (objectNameChanged) |
1106 | d->declarativeData->objectNameChanged(d->declarativeData, this); |
1107 | } |
1108 | |
1109 | |
1110 | #ifdef QT3_SUPPORT |
1111 | /*! \internal |
1112 | QObject::child is compat but needs to call itself recursively, |
1113 | that's why we need this helper. |
1114 | */ |
1115 | static QObject *qChildHelper(const char *objName, const char *inheritsClass, |
1116 | bool recursiveSearch, const QObjectList &children) |
1117 | { |
1118 | if (children.isEmpty()) |
1119 | return 0; |
1120 | |
1121 | bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget" ) == 0); |
1122 | const QLatin1String oName(objName); |
1123 | for (int i = 0; i < children.size(); ++i) { |
1124 | QObject *obj = children.at(i); |
1125 | if (onlyWidgets) { |
1126 | if (obj->isWidgetType() && (!objName || obj->objectName() == oName)) |
1127 | return obj; |
1128 | } else if ((!inheritsClass || obj->inherits(inheritsClass)) |
1129 | && (!objName || obj->objectName() == oName)) |
1130 | return obj; |
1131 | if (recursiveSearch && (obj = qChildHelper(objName, inheritsClass, |
1132 | recursiveSearch, obj->children()))) |
1133 | return obj; |
1134 | } |
1135 | return 0; |
1136 | } |
1137 | |
1138 | |
1139 | /*! |
1140 | Searches the children and optionally grandchildren of this object, |
1141 | and returns a child that is called \a objName that inherits \a |
1142 | inheritsClass. If \a inheritsClass is 0 (the default), any class |
1143 | matches. |
1144 | |
1145 | If \a recursiveSearch is true (the default), child() performs a |
1146 | depth-first search of the object's children. |
1147 | |
1148 | If there is no such object, this function returns 0. If there are |
1149 | more than one, the first one found is returned. |
1150 | */ |
1151 | QObject* QObject::child(const char *objName, const char *inheritsClass, |
1152 | bool recursiveSearch) const |
1153 | { |
1154 | Q_D(const QObject); |
1155 | return qChildHelper(objName, inheritsClass, recursiveSearch, d->children); |
1156 | } |
1157 | #endif |
1158 | |
1159 | /*! |
1160 | \fn bool QObject::isWidgetType() const |
1161 | |
1162 | Returns true if the object is a widget; otherwise returns false. |
1163 | |
1164 | Calling this function is equivalent to calling |
1165 | inherits("QWidget"), except that it is much faster. |
1166 | */ |
1167 | |
1168 | |
1169 | /*! |
1170 | This virtual function receives events to an object and should |
1171 | return true if the event \a e was recognized and processed. |
1172 | |
1173 | The event() function can be reimplemented to customize the |
1174 | behavior of an object. |
1175 | |
1176 | \sa installEventFilter(), timerEvent(), QApplication::sendEvent(), |
1177 | QApplication::postEvent(), QWidget::event() |
1178 | */ |
1179 | |
1180 | bool QObject::event(QEvent *e) |
1181 | { |
1182 | switch (e->type()) { |
1183 | case QEvent::Timer: |
1184 | timerEvent((QTimerEvent*)e); |
1185 | break; |
1186 | |
1187 | #ifdef QT3_SUPPORT |
1188 | case QEvent::ChildInsertedRequest: |
1189 | d_func()->sendPendingChildInsertedEvents(); |
1190 | break; |
1191 | #endif |
1192 | |
1193 | case QEvent::ChildAdded: |
1194 | case QEvent::ChildPolished: |
1195 | #ifdef QT3_SUPPORT |
1196 | case QEvent::ChildInserted: |
1197 | #endif |
1198 | case QEvent::ChildRemoved: |
1199 | childEvent((QChildEvent*)e); |
1200 | break; |
1201 | |
1202 | case QEvent::DeferredDelete: |
1203 | qDeleteInEventHandler(this); |
1204 | break; |
1205 | |
1206 | case QEvent::MetaCall: |
1207 | { |
1208 | #ifdef QT_JAMBI_BUILD |
1209 | d_func()->inEventHandler = false; |
1210 | #endif |
1211 | QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e); |
1212 | QObjectPrivate::Sender currentSender; |
1213 | currentSender.sender = const_cast<QObject*>(mce->sender()); |
1214 | currentSender.signal = mce->signalId(); |
1215 | currentSender.ref = 1; |
1216 | QObjectPrivate::Sender * const previousSender = |
1217 | QObjectPrivate::setCurrentSender(this, ¤tSender); |
1218 | #if defined(QT_NO_EXCEPTIONS) |
1219 | mce->placeMetaCall(this); |
1220 | #else |
1221 | QT_TRY { |
1222 | mce->placeMetaCall(this); |
1223 | } QT_CATCH(...) { |
1224 | QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); |
1225 | QT_RETHROW; |
1226 | } |
1227 | #endif |
1228 | QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); |
1229 | break; |
1230 | } |
1231 | |
1232 | case QEvent::ThreadChange: { |
1233 | Q_D(QObject); |
1234 | QThreadData *threadData = d->threadData; |
1235 | QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; |
1236 | if (eventDispatcher) { |
1237 | QList<QPair<int, int> > timers = eventDispatcher->registeredTimers(this); |
1238 | if (!timers.isEmpty()) { |
1239 | // set inThreadChangeEvent to true to tell the dispatcher not to release out timer ids |
1240 | // back to the pool (since the timer ids are moving to a new thread). |
1241 | d->inThreadChangeEvent = true; |
1242 | eventDispatcher->unregisterTimers(this); |
1243 | d->inThreadChangeEvent = false; |
1244 | QMetaObject::invokeMethod(this, "_q_reregisterTimers" , Qt::QueuedConnection, |
1245 | Q_ARG(void*, (new QList<QPair<int, int> >(timers)))); |
1246 | } |
1247 | } |
1248 | break; |
1249 | } |
1250 | |
1251 | default: |
1252 | if (e->type() >= QEvent::User) { |
1253 | customEvent(e); |
1254 | break; |
1255 | } |
1256 | return false; |
1257 | } |
1258 | return true; |
1259 | } |
1260 | |
1261 | /*! |
1262 | \fn void QObject::timerEvent(QTimerEvent *event) |
1263 | |
1264 | This event handler can be reimplemented in a subclass to receive |
1265 | timer events for the object. |
1266 | |
1267 | QTimer provides a higher-level interface to the timer |
1268 | functionality, and also more general information about timers. The |
1269 | timer event is passed in the \a event parameter. |
1270 | |
1271 | \sa startTimer(), killTimer(), event() |
1272 | */ |
1273 | |
1274 | void QObject::timerEvent(QTimerEvent *) |
1275 | { |
1276 | } |
1277 | |
1278 | |
1279 | /*! |
1280 | This event handler can be reimplemented in a subclass to receive |
1281 | child events. The event is passed in the \a event parameter. |
1282 | |
1283 | QEvent::ChildAdded and QEvent::ChildRemoved events are sent to |
1284 | objects when children are added or removed. In both cases you can |
1285 | only rely on the child being a QObject, or if isWidgetType() |
1286 | returns true, a QWidget. (This is because, in the |
1287 | \l{QEvent::ChildAdded}{ChildAdded} case, the child is not yet |
1288 | fully constructed, and in the \l{QEvent::ChildRemoved}{ChildRemoved} |
1289 | case it might have been destructed already). |
1290 | |
1291 | QEvent::ChildPolished events are sent to widgets when children |
1292 | are polished, or when polished children are added. If you receive |
1293 | a child polished event, the child's construction is usually |
1294 | completed. However, this is not guaranteed, and multiple polish |
1295 | events may be delivered during the execution of a widget's |
1296 | constructor. |
1297 | |
1298 | For every child widget, you receive one |
1299 | \l{QEvent::ChildAdded}{ChildAdded} event, zero or more |
1300 | \l{QEvent::ChildPolished}{ChildPolished} events, and one |
1301 | \l{QEvent::ChildRemoved}{ChildRemoved} event. |
1302 | |
1303 | The \l{QEvent::ChildPolished}{ChildPolished} event is omitted if |
1304 | a child is removed immediately after it is added. If a child is |
1305 | polished several times during construction and destruction, you |
1306 | may receive several child polished events for the same child, |
1307 | each time with a different virtual table. |
1308 | |
1309 | \sa event() |
1310 | */ |
1311 | |
1312 | void QObject::childEvent(QChildEvent * /* event */) |
1313 | { |
1314 | } |
1315 | |
1316 | |
1317 | /*! |
1318 | This event handler can be reimplemented in a subclass to receive |
1319 | custom events. Custom events are user-defined events with a type |
1320 | value at least as large as the QEvent::User item of the |
1321 | QEvent::Type enum, and is typically a QEvent subclass. The event |
1322 | is passed in the \a event parameter. |
1323 | |
1324 | \sa event(), QEvent |
1325 | */ |
1326 | void QObject::customEvent(QEvent * /* event */) |
1327 | { |
1328 | } |
1329 | |
1330 | |
1331 | |
1332 | /*! |
1333 | Filters events if this object has been installed as an event |
1334 | filter for the \a watched object. |
1335 | |
1336 | In your reimplementation of this function, if you want to filter |
1337 | the \a event out, i.e. stop it being handled further, return |
1338 | true; otherwise return false. |
1339 | |
1340 | Example: |
1341 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 6 |
1342 | |
1343 | Notice in the example above that unhandled events are passed to |
1344 | the base class's eventFilter() function, since the base class |
1345 | might have reimplemented eventFilter() for its own internal |
1346 | purposes. |
1347 | |
1348 | \warning If you delete the receiver object in this function, be |
1349 | sure to return true. Otherwise, Qt will forward the event to the |
1350 | deleted object and the program might crash. |
1351 | |
1352 | \sa installEventFilter() |
1353 | */ |
1354 | |
1355 | bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */) |
1356 | { |
1357 | return false; |
1358 | } |
1359 | |
1360 | /*! |
1361 | \fn bool QObject::signalsBlocked() const |
1362 | |
1363 | Returns true if signals are blocked; otherwise returns false. |
1364 | |
1365 | Signals are not blocked by default. |
1366 | |
1367 | \sa blockSignals() |
1368 | */ |
1369 | |
1370 | /*! |
1371 | If \a block is true, signals emitted by this object are blocked |
1372 | (i.e., emitting a signal will not invoke anything connected to it). |
1373 | If \a block is false, no such blocking will occur. |
1374 | |
1375 | The return value is the previous value of signalsBlocked(). |
1376 | |
1377 | Note that the destroyed() signal will be emitted even if the signals |
1378 | for this object have been blocked. |
1379 | |
1380 | \sa signalsBlocked() |
1381 | */ |
1382 | |
1383 | bool QObject::blockSignals(bool block) |
1384 | { |
1385 | Q_D(QObject); |
1386 | bool previous = d->blockSig; |
1387 | d->blockSig = block; |
1388 | return previous; |
1389 | } |
1390 | |
1391 | /*! |
1392 | Returns the thread in which the object lives. |
1393 | |
1394 | \sa moveToThread() |
1395 | */ |
1396 | QThread *QObject::thread() const |
1397 | { |
1398 | return d_func()->threadData->thread; |
1399 | } |
1400 | |
1401 | /*! |
1402 | Changes the thread affinity for this object and its children. The |
1403 | object cannot be moved if it has a parent. Event processing will |
1404 | continue in the \a targetThread. |
1405 | |
1406 | To move an object to the main thread, use QApplication::instance() |
1407 | to retrieve a pointer to the current application, and then use |
1408 | QApplication::thread() to retrieve the thread in which the |
1409 | application lives. For example: |
1410 | |
1411 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 7 |
1412 | |
1413 | If \a targetThread is zero, all event processing for this object |
1414 | and its children stops. |
1415 | |
1416 | Note that all active timers for the object will be reset. The |
1417 | timers are first stopped in the current thread and restarted (with |
1418 | the same interval) in the \a targetThread. As a result, constantly |
1419 | moving an object between threads can postpone timer events |
1420 | indefinitely. |
1421 | |
1422 | A QEvent::ThreadChange event is sent to this object just before |
1423 | the thread affinity is changed. You can handle this event to |
1424 | perform any special processing. Note that any new events that are |
1425 | posted to this object will be handled in the \a targetThread. |
1426 | |
1427 | \warning This function is \e not thread-safe; the current thread |
1428 | must be same as the current thread affinity. In other words, this |
1429 | function can only "push" an object from the current thread to |
1430 | another thread, it cannot "pull" an object from any arbitrary |
1431 | thread to the current thread. |
1432 | |
1433 | \sa thread() |
1434 | */ |
1435 | void QObject::moveToThread(QThread *targetThread) |
1436 | { |
1437 | Q_D(QObject); |
1438 | |
1439 | if (d->threadData->thread == targetThread) { |
1440 | // object is already in this thread |
1441 | return; |
1442 | } |
1443 | |
1444 | if (d->parent != 0) { |
1445 | qWarning("QObject::moveToThread: Cannot move objects with a parent" ); |
1446 | return; |
1447 | } |
1448 | if (d->isWidget) { |
1449 | qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread" ); |
1450 | return; |
1451 | } |
1452 | |
1453 | QThreadData *currentData = QThreadData::current(); |
1454 | QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : new QThreadData(0); |
1455 | if (d->threadData->thread == 0 && currentData == targetData) { |
1456 | // one exception to the rule: we allow moving objects with no thread affinity to the current thread |
1457 | currentData = d->threadData; |
1458 | } else if (d->threadData != currentData) { |
1459 | qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" |
1460 | "Cannot move to target thread (%p)\n" , |
1461 | currentData->thread, d->threadData->thread, targetData->thread); |
1462 | |
1463 | #ifdef Q_WS_MAC |
1464 | qWarning("On Mac OS X, you might be loading two sets of Qt binaries into the same process. " |
1465 | "Check that all plugins are compiled against the right Qt binaries. Export " |
1466 | "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded." ); |
1467 | #endif |
1468 | |
1469 | return; |
1470 | } |
1471 | |
1472 | // prepare to move |
1473 | d->moveToThread_helper(); |
1474 | |
1475 | QOrderedMutexLocker locker(¤tData->postEventList.mutex, |
1476 | &targetData->postEventList.mutex); |
1477 | |
1478 | // keep currentData alive (since we've got it locked) |
1479 | currentData->ref(); |
1480 | |
1481 | // move the object |
1482 | d_func()->setThreadData_helper(currentData, targetData); |
1483 | |
1484 | locker.unlock(); |
1485 | |
1486 | // now currentData can commit suicide if it wants to |
1487 | currentData->deref(); |
1488 | } |
1489 | |
1490 | void QObjectPrivate::moveToThread_helper() |
1491 | { |
1492 | Q_Q(QObject); |
1493 | QEvent e(QEvent::ThreadChange); |
1494 | QCoreApplication::sendEvent(q, &e); |
1495 | for (int i = 0; i < children.size(); ++i) { |
1496 | QObject *child = children.at(i); |
1497 | child->d_func()->moveToThread_helper(); |
1498 | } |
1499 | } |
1500 | |
1501 | void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData) |
1502 | { |
1503 | Q_Q(QObject); |
1504 | |
1505 | // move posted events |
1506 | int eventsMoved = 0; |
1507 | for (int i = 0; i < currentData->postEventList.size(); ++i) { |
1508 | const QPostEvent &pe = currentData->postEventList.at(i); |
1509 | if (!pe.event) |
1510 | continue; |
1511 | if (pe.receiver == q) { |
1512 | // move this post event to the targetList |
1513 | targetData->postEventList.addEvent(pe); |
1514 | const_cast<QPostEvent &>(pe).event = 0; |
1515 | ++eventsMoved; |
1516 | } |
1517 | } |
1518 | if (eventsMoved > 0 && targetData->eventDispatcher) { |
1519 | targetData->canWait = false; |
1520 | targetData->eventDispatcher->wakeUp(); |
1521 | } |
1522 | |
1523 | // the current emitting thread shouldn't restore currentSender after calling moveToThread() |
1524 | if (currentSender) |
1525 | currentSender->ref = 0; |
1526 | currentSender = 0; |
1527 | |
1528 | #ifdef QT_JAMBI_BUILD |
1529 | // the current event thread also shouldn't restore the delete watch |
1530 | inEventHandler = false; |
1531 | |
1532 | if (deleteWatch) |
1533 | *deleteWatch = 1; |
1534 | deleteWatch = 0; |
1535 | #endif |
1536 | |
1537 | // set new thread data |
1538 | targetData->ref(); |
1539 | threadData->deref(); |
1540 | threadData = targetData; |
1541 | |
1542 | for (int i = 0; i < children.size(); ++i) { |
1543 | QObject *child = children.at(i); |
1544 | child->d_func()->setThreadData_helper(currentData, targetData); |
1545 | } |
1546 | } |
1547 | |
1548 | void QObjectPrivate::_q_reregisterTimers(void *pointer) |
1549 | { |
1550 | Q_Q(QObject); |
1551 | QList<QPair<int, int> > *timerList = reinterpret_cast<QList<QPair<int, int> > *>(pointer); |
1552 | QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher; |
1553 | for (int i = 0; i < timerList->size(); ++i) { |
1554 | const QPair<int, int> &pair = timerList->at(i); |
1555 | eventDispatcher->registerTimer(pair.first, pair.second, q); |
1556 | } |
1557 | delete timerList; |
1558 | } |
1559 | |
1560 | |
1561 | // |
1562 | // The timer flag hasTimer is set when startTimer is called. |
1563 | // It is not reset when killing the timer because more than |
1564 | // one timer might be active. |
1565 | // |
1566 | |
1567 | /*! |
1568 | Starts a timer and returns a timer identifier, or returns zero if |
1569 | it could not start a timer. |
1570 | |
1571 | A timer event will occur every \a interval milliseconds until |
1572 | killTimer() is called. If \a interval is 0, then the timer event |
1573 | occurs once every time there are no more window system events to |
1574 | process. |
1575 | |
1576 | The virtual timerEvent() function is called with the QTimerEvent |
1577 | event parameter class when a timer event occurs. Reimplement this |
1578 | function to get timer events. |
1579 | |
1580 | If multiple timers are running, the QTimerEvent::timerId() can be |
1581 | used to find out which timer was activated. |
1582 | |
1583 | Example: |
1584 | |
1585 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 8 |
1586 | |
1587 | Note that QTimer's accuracy depends on the underlying operating |
1588 | system and hardware. Most platforms support an accuracy of 20 |
1589 | milliseconds; some provide more. If Qt is unable to deliver the |
1590 | requested number of timer events, it will silently discard some. |
1591 | |
1592 | The QTimer class provides a high-level programming interface with |
1593 | single-shot timers and timer signals instead of events. There is |
1594 | also a QBasicTimer class that is more lightweight than QTimer and |
1595 | less clumsy than using timer IDs directly. |
1596 | |
1597 | \sa timerEvent(), killTimer(), QTimer::singleShot() |
1598 | */ |
1599 | |
1600 | int QObject::startTimer(int interval) |
1601 | { |
1602 | Q_D(QObject); |
1603 | |
1604 | if (interval < 0) { |
1605 | qWarning("QObject::startTimer: QTimer cannot have a negative interval" ); |
1606 | return 0; |
1607 | } |
1608 | |
1609 | d->pendTimer = true; // set timer flag |
1610 | |
1611 | if (!d->threadData->eventDispatcher) { |
1612 | qWarning("QObject::startTimer: QTimer can only be used with threads started with QThread" ); |
1613 | return 0; |
1614 | } |
1615 | return d->threadData->eventDispatcher->registerTimer(interval, this); |
1616 | } |
1617 | |
1618 | /*! |
1619 | Kills the timer with timer identifier, \a id. |
1620 | |
1621 | The timer identifier is returned by startTimer() when a timer |
1622 | event is started. |
1623 | |
1624 | \sa timerEvent(), startTimer() |
1625 | */ |
1626 | |
1627 | void QObject::killTimer(int id) |
1628 | { |
1629 | Q_D(QObject); |
1630 | if (d->threadData->eventDispatcher) |
1631 | d->threadData->eventDispatcher->unregisterTimer(id); |
1632 | } |
1633 | |
1634 | |
1635 | /*! |
1636 | \fn QObject *QObject::parent() const |
1637 | |
1638 | Returns a pointer to the parent object. |
1639 | |
1640 | \sa children() |
1641 | */ |
1642 | |
1643 | /*! |
1644 | \fn const QObjectList &QObject::children() const |
1645 | |
1646 | Returns a list of child objects. |
1647 | The QObjectList class is defined in the \c{<QObject>} header |
1648 | file as the following: |
1649 | |
1650 | \quotefromfile src/corelib/kernel/qobject.h |
1651 | \skipto /typedef .*QObjectList/ |
1652 | \printuntil QObjectList |
1653 | |
1654 | The first child added is the \l{QList::first()}{first} object in |
1655 | the list and the last child added is the \l{QList::last()}{last} |
1656 | object in the list, i.e. new children are appended at the end. |
1657 | |
1658 | Note that the list order changes when QWidget children are |
1659 | \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A |
1660 | widget that is raised becomes the last object in the list, and a |
1661 | widget that is lowered becomes the first object in the list. |
1662 | |
1663 | \sa findChild(), findChildren(), parent(), setParent() |
1664 | */ |
1665 | |
1666 | #ifdef QT3_SUPPORT |
1667 | static void objSearch(QObjectList &result, |
1668 | const QObjectList &list, |
1669 | const char *inheritsClass, |
1670 | bool onlyWidgets, |
1671 | const char *objName, |
1672 | QRegExp *rx, |
1673 | bool recurse) |
1674 | { |
1675 | for (int i = 0; i < list.size(); ++i) { |
1676 | QObject *obj = list.at(i); |
1677 | if (!obj) |
1678 | continue; |
1679 | bool ok = true; |
1680 | if (onlyWidgets) |
1681 | ok = obj->isWidgetType(); |
1682 | else if (inheritsClass && !obj->inherits(inheritsClass)) |
1683 | ok = false; |
1684 | if (ok) { |
1685 | if (objName) |
1686 | ok = (obj->objectName() == QLatin1String(objName)); |
1687 | #ifndef QT_NO_REGEXP |
1688 | else if (rx) |
1689 | ok = (rx->indexIn(obj->objectName()) != -1); |
1690 | #endif |
1691 | } |
1692 | if (ok) // match! |
1693 | result.append(obj); |
1694 | if (recurse) { |
1695 | QObjectList clist = obj->children(); |
1696 | if (!clist.isEmpty()) |
1697 | objSearch(result, clist, inheritsClass, |
1698 | onlyWidgets, objName, rx, recurse); |
1699 | } |
1700 | } |
1701 | } |
1702 | |
1703 | /*! |
1704 | \internal |
1705 | |
1706 | Searches the children and optionally grandchildren of this object, |
1707 | and returns a list of those objects that are named or that match |
1708 | \a objName and inherit \a inheritsClass. If \a inheritsClass is 0 |
1709 | (the default), all classes match. If \a objName is 0 (the |
1710 | default), all object names match. |
1711 | |
1712 | If \a regexpMatch is true (the default), \a objName is a regular |
1713 | expression that the objects's names must match. The syntax is that |
1714 | of a QRegExp. If \a regexpMatch is false, \a objName is a string |
1715 | and object names must match it exactly. |
1716 | |
1717 | Note that \a inheritsClass uses single inheritance from QObject, |
1718 | the way inherits() does. According to inherits(), QWidget |
1719 | inherits QObject but not QPaintDevice. This does not quite match |
1720 | reality, but is the best that can be done on the wide variety of |
1721 | compilers Qt supports. |
1722 | |
1723 | Finally, if \a recursiveSearch is true (the default), queryList() |
1724 | searches \e{n}th-generation as well as first-generation children. |
1725 | |
1726 | If all this seems a bit complex for your needs, the simpler |
1727 | child() function may be what you want. |
1728 | |
1729 | This somewhat contrived example disables all the buttons in this |
1730 | window: |
1731 | |
1732 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 9 |
1733 | |
1734 | \warning Delete the list as soon you have finished using it. The |
1735 | list contains pointers that may become invalid at almost any time |
1736 | without notice (as soon as the user closes a window you may have |
1737 | dangling pointers, for example). |
1738 | |
1739 | \sa child() children(), parent(), inherits(), objectName(), QRegExp |
1740 | */ |
1741 | |
1742 | QObjectList QObject::queryList(const char *inheritsClass, |
1743 | const char *objName, |
1744 | bool regexpMatch, |
1745 | bool recursiveSearch) const |
1746 | { |
1747 | Q_D(const QObject); |
1748 | QObjectList list; |
1749 | bool onlyWidgets = (inheritsClass && qstrcmp(inheritsClass, "QWidget" ) == 0); |
1750 | #ifndef QT_NO_REGEXP |
1751 | if (regexpMatch && objName) { // regexp matching |
1752 | QRegExp rx(QString::fromLatin1(objName)); |
1753 | objSearch(list, d->children, inheritsClass, onlyWidgets, 0, &rx, recursiveSearch); |
1754 | } else |
1755 | #endif |
1756 | { |
1757 | objSearch(list, d->children, inheritsClass, onlyWidgets, objName, 0, recursiveSearch); |
1758 | } |
1759 | return list; |
1760 | } |
1761 | #endif |
1762 | |
1763 | /*! |
1764 | \fn T *QObject::findChild(const QString &name) const |
1765 | |
1766 | Returns the child of this object that can be cast into type T and |
1767 | that is called \a name, or 0 if there is no such object. |
1768 | Omitting the \a name argument causes all object names to be matched. |
1769 | The search is performed recursively. |
1770 | |
1771 | If there is more than one child matching the search, the most |
1772 | direct ancestor is returned. If there are several direct |
1773 | ancestors, it is undefined which one will be returned. In that |
1774 | case, findChildren() should be used. |
1775 | |
1776 | This example returns a child \l{QPushButton} of \c{parentWidget} |
1777 | named \c{"button1"}: |
1778 | |
1779 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 10 |
1780 | |
1781 | This example returns a \l{QListWidget} child of \c{parentWidget}: |
1782 | |
1783 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 11 |
1784 | |
1785 | \sa findChildren() |
1786 | */ |
1787 | |
1788 | /*! |
1789 | \fn QList<T> QObject::findChildren(const QString &name) const |
1790 | |
1791 | Returns all children of this object with the given \a name that can be |
1792 | cast to type T, or an empty list if there are no such objects. |
1793 | Omitting the \a name argument causes all object names to be matched. |
1794 | The search is performed recursively. |
1795 | |
1796 | The following example shows how to find a list of child \l{QWidget}s of |
1797 | the specified \c{parentWidget} named \c{widgetname}: |
1798 | |
1799 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 12 |
1800 | |
1801 | This example returns all \c{QPushButton}s that are children of \c{parentWidget}: |
1802 | |
1803 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 13 |
1804 | |
1805 | \sa findChild() |
1806 | */ |
1807 | |
1808 | /*! |
1809 | \fn QList<T> QObject::findChildren(const QRegExp ®Exp) const |
1810 | \overload findChildren() |
1811 | |
1812 | Returns the children of this object that can be cast to type T |
1813 | and that have names matching the regular expression \a regExp, |
1814 | or an empty list if there are no such objects. |
1815 | The search is performed recursively. |
1816 | */ |
1817 | |
1818 | /*! |
1819 | \fn T qFindChild(const QObject *obj, const QString &name) |
1820 | \relates QObject |
1821 | \overload qFindChildren() |
1822 | \obsolete |
1823 | |
1824 | This function is equivalent to |
1825 | \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name). |
1826 | |
1827 | \note This function was provided as a workaround for MSVC 6 |
1828 | which did not support member template functions. It is advised |
1829 | to use the other form in new code. |
1830 | |
1831 | \sa QObject::findChild() |
1832 | */ |
1833 | |
1834 | /*! |
1835 | \fn QList<T> qFindChildren(const QObject *obj, const QString &name) |
1836 | \relates QObject |
1837 | \overload qFindChildren() |
1838 | \obsolete |
1839 | |
1840 | This function is equivalent to |
1841 | \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name). |
1842 | |
1843 | \note This function was provided as a workaround for MSVC 6 |
1844 | which did not support member template functions. It is advised |
1845 | to use the other form in new code. |
1846 | |
1847 | \sa QObject::findChildren() |
1848 | */ |
1849 | |
1850 | /*! |
1851 | \fn QList<T> qFindChildren(const QObject *obj, const QRegExp ®Exp) |
1852 | \relates QObject |
1853 | \overload qFindChildren() |
1854 | |
1855 | This function is equivalent to |
1856 | \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a regExp). |
1857 | |
1858 | \note This function was provided as a workaround for MSVC 6 |
1859 | which did not support member template functions. It is advised |
1860 | to use the other form in new code. |
1861 | |
1862 | \sa QObject::findChildren() |
1863 | */ |
1864 | |
1865 | /*! |
1866 | \internal |
1867 | */ |
1868 | void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re, |
1869 | const QMetaObject &mo, QList<void*> *list) |
1870 | { |
1871 | if (!parent || !list) |
1872 | return; |
1873 | const QObjectList &children = parent->children(); |
1874 | QObject *obj; |
1875 | for (int i = 0; i < children.size(); ++i) { |
1876 | obj = children.at(i); |
1877 | if (mo.cast(obj)) { |
1878 | if (re) { |
1879 | if (re->indexIn(obj->objectName()) != -1) |
1880 | list->append(obj); |
1881 | } else { |
1882 | if (name.isNull() || obj->objectName() == name) |
1883 | list->append(obj); |
1884 | } |
1885 | } |
1886 | qt_qFindChildren_helper(obj, name, re, mo, list); |
1887 | } |
1888 | } |
1889 | |
1890 | /*! \internal |
1891 | */ |
1892 | QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo) |
1893 | { |
1894 | if (!parent) |
1895 | return 0; |
1896 | const QObjectList &children = parent->children(); |
1897 | QObject *obj; |
1898 | int i; |
1899 | for (i = 0; i < children.size(); ++i) { |
1900 | obj = children.at(i); |
1901 | if (mo.cast(obj) && (name.isNull() || obj->objectName() == name)) |
1902 | return obj; |
1903 | } |
1904 | for (i = 0; i < children.size(); ++i) { |
1905 | obj = qt_qFindChild_helper(children.at(i), name, mo); |
1906 | if (obj) |
1907 | return obj; |
1908 | } |
1909 | return 0; |
1910 | } |
1911 | |
1912 | /*! |
1913 | Makes the object a child of \a parent. |
1914 | |
1915 | \sa QWidget::setParent() |
1916 | */ |
1917 | |
1918 | void QObject::setParent(QObject *parent) |
1919 | { |
1920 | Q_D(QObject); |
1921 | Q_ASSERT(!d->isWidget); |
1922 | d->setParent_helper(parent); |
1923 | } |
1924 | |
1925 | void QObjectPrivate::deleteChildren() |
1926 | { |
1927 | const bool reallyWasDeleted = wasDeleted; |
1928 | wasDeleted = true; |
1929 | // delete children objects |
1930 | // don't use qDeleteAll as the destructor of the child might |
1931 | // delete siblings |
1932 | for (int i = 0; i < children.count(); ++i) { |
1933 | currentChildBeingDeleted = children.at(i); |
1934 | children[i] = 0; |
1935 | delete currentChildBeingDeleted; |
1936 | } |
1937 | children.clear(); |
1938 | currentChildBeingDeleted = 0; |
1939 | wasDeleted = reallyWasDeleted; |
1940 | } |
1941 | |
1942 | void QObjectPrivate::setParent_helper(QObject *o) |
1943 | { |
1944 | Q_Q(QObject); |
1945 | if (o == parent) |
1946 | return; |
1947 | if (parent) { |
1948 | QObjectPrivate *parentD = parent->d_func(); |
1949 | if (parentD->wasDeleted && wasDeleted |
1950 | && parentD->currentChildBeingDeleted == q) { |
1951 | // don't do anything since QObjectPrivate::deleteChildren() already |
1952 | // cleared our entry in parentD->children. |
1953 | } else { |
1954 | const int index = parentD->children.indexOf(q); |
1955 | if (parentD->wasDeleted) { |
1956 | parentD->children[index] = 0; |
1957 | } else { |
1958 | parentD->children.removeAt(index); |
1959 | if (sendChildEvents && parentD->receiveChildEvents) { |
1960 | QChildEvent e(QEvent::ChildRemoved, q); |
1961 | QCoreApplication::sendEvent(parent, &e); |
1962 | } |
1963 | } |
1964 | } |
1965 | } |
1966 | parent = o; |
1967 | if (parent) { |
1968 | // object hierarchies are constrained to a single thread |
1969 | if (threadData != parent->d_func()->threadData) { |
1970 | qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread" ); |
1971 | parent = 0; |
1972 | return; |
1973 | } |
1974 | parent->d_func()->children.append(q); |
1975 | if(sendChildEvents && parent->d_func()->receiveChildEvents) { |
1976 | if (!isWidget) { |
1977 | QChildEvent e(QEvent::ChildAdded, q); |
1978 | QCoreApplication::sendEvent(parent, &e); |
1979 | #ifdef QT3_SUPPORT |
1980 | if (QCoreApplicationPrivate::useQt3Support) { |
1981 | if (parent->d_func()->pendingChildInsertedEvents.isEmpty()) { |
1982 | QCoreApplication::postEvent(parent, |
1983 | new QEvent(QEvent::ChildInsertedRequest), |
1984 | Qt::HighEventPriority); |
1985 | } |
1986 | parent->d_func()->pendingChildInsertedEvents.append(q); |
1987 | } |
1988 | #endif |
1989 | } |
1990 | } |
1991 | } |
1992 | if (!wasDeleted && declarativeData) |
1993 | QAbstractDeclarativeData::parentChanged(declarativeData, q, o); |
1994 | } |
1995 | |
1996 | /*! |
1997 | \fn void QObject::installEventFilter(QObject *filterObj) |
1998 | |
1999 | Installs an event filter \a filterObj on this object. For example: |
2000 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 14 |
2001 | |
2002 | An event filter is an object that receives all events that are |
2003 | sent to this object. The filter can either stop the event or |
2004 | forward it to this object. The event filter \a filterObj receives |
2005 | events via its eventFilter() function. The eventFilter() function |
2006 | must return true if the event should be filtered, (i.e. stopped); |
2007 | otherwise it must return false. |
2008 | |
2009 | If multiple event filters are installed on a single object, the |
2010 | filter that was installed last is activated first. |
2011 | |
2012 | Here's a \c KeyPressEater class that eats the key presses of its |
2013 | monitored objects: |
2014 | |
2015 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 15 |
2016 | |
2017 | And here's how to install it on two widgets: |
2018 | |
2019 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 16 |
2020 | |
2021 | The QShortcut class, for example, uses this technique to intercept |
2022 | shortcut key presses. |
2023 | |
2024 | \warning If you delete the receiver object in your eventFilter() |
2025 | function, be sure to return true. If you return false, Qt sends |
2026 | the event to the deleted object and the program will crash. |
2027 | |
2028 | Note that the filtering object must be in the same thread as this |
2029 | object. If \a filterObj is in a different thread, this function does |
2030 | nothing. If either \a filterObj or this object are moved to a different |
2031 | thread after calling this function, the event filter will not be |
2032 | called until both objects have the same thread affinity again (it |
2033 | is \e not removed). |
2034 | |
2035 | \sa removeEventFilter(), eventFilter(), event() |
2036 | */ |
2037 | |
2038 | void QObject::installEventFilter(QObject *obj) |
2039 | { |
2040 | Q_D(QObject); |
2041 | if (!obj) |
2042 | return; |
2043 | if (d->threadData != obj->d_func()->threadData) { |
2044 | qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread." ); |
2045 | return; |
2046 | } |
2047 | |
2048 | // clean up unused items in the list |
2049 | d->eventFilters.removeAll((QObject*)0); |
2050 | d->eventFilters.removeAll(obj); |
2051 | d->eventFilters.prepend(obj); |
2052 | } |
2053 | |
2054 | /*! |
2055 | Removes an event filter object \a obj from this object. The |
2056 | request is ignored if such an event filter has not been installed. |
2057 | |
2058 | All event filters for this object are automatically removed when |
2059 | this object is destroyed. |
2060 | |
2061 | It is always safe to remove an event filter, even during event |
2062 | filter activation (i.e. from the eventFilter() function). |
2063 | |
2064 | \sa installEventFilter(), eventFilter(), event() |
2065 | */ |
2066 | |
2067 | void QObject::removeEventFilter(QObject *obj) |
2068 | { |
2069 | Q_D(QObject); |
2070 | for (int i = 0; i < d->eventFilters.count(); ++i) { |
2071 | if (d->eventFilters.at(i) == obj) |
2072 | d->eventFilters[i] = 0; |
2073 | } |
2074 | } |
2075 | |
2076 | |
2077 | /*! |
2078 | \fn QObject::destroyed(QObject *obj) |
2079 | |
2080 | This signal is emitted immediately before the object \a obj is |
2081 | destroyed, and can not be blocked. |
2082 | |
2083 | All the objects's children are destroyed immediately after this |
2084 | signal is emitted. |
2085 | |
2086 | \sa deleteLater(), QPointer |
2087 | */ |
2088 | |
2089 | /*! |
2090 | Schedules this object for deletion. |
2091 | |
2092 | The object will be deleted when control returns to the event |
2093 | loop. If the event loop is not running when this function is |
2094 | called (e.g. deleteLater() is called on an object before |
2095 | QCoreApplication::exec()), the object will be deleted once the |
2096 | event loop is started. If deleteLater() is called after the main event loop |
2097 | has stopped, the object will not be deleted. |
2098 | Since Qt 4.8, if deleteLater() is called on an object that lives in a |
2099 | thread with no running event loop, the object will be destroyed when the |
2100 | thread finishes. |
2101 | |
2102 | Note that entering and leaving a new event loop (e.g., by opening a modal |
2103 | dialog) will \e not perform the deferred deletion; for the object to be |
2104 | deleted, the control must return to the event loop from which |
2105 | deleteLater() was called. |
2106 | |
2107 | \bold{Note:} It is safe to call this function more than once; when the |
2108 | first deferred deletion event is delivered, any pending events for the |
2109 | object are removed from the event queue. |
2110 | |
2111 | \sa destroyed(), QPointer |
2112 | */ |
2113 | void QObject::deleteLater() |
2114 | { |
2115 | QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); |
2116 | } |
2117 | |
2118 | /*! |
2119 | \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n) |
2120 | \reentrant |
2121 | |
2122 | Returns a translated version of \a sourceText, optionally based on a |
2123 | \a disambiguation string and value of \a n for strings containing plurals; |
2124 | otherwise returns \a sourceText itself if no appropriate translated string |
2125 | is available. |
2126 | |
2127 | Example: |
2128 | \snippet mainwindows/sdi/mainwindow.cpp implicit tr context |
2129 | \dots |
2130 | |
2131 | If the same \a sourceText is used in different roles within the |
2132 | same context, an additional identifying string may be passed in |
2133 | \a disambiguation (0 by default). In Qt 4.4 and earlier, this was |
2134 | the preferred way to pass comments to translators. |
2135 | |
2136 | Example: |
2137 | |
2138 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 17 |
2139 | \dots |
2140 | |
2141 | See \l{Writing Source Code for Translation} for a detailed description of |
2142 | Qt's translation mechanisms in general, and the |
2143 | \l{Writing Source Code for Translation#Disambiguation}{Disambiguation} |
2144 | section for information on disambiguation. |
2145 | |
2146 | \warning This method is reentrant only if all translators are |
2147 | installed \e before calling this method. Installing or removing |
2148 | translators while performing translations is not supported. Doing |
2149 | so will probably result in crashes or other undesirable behavior. |
2150 | |
2151 | \sa trUtf8(), QApplication::translate(), QTextCodec::setCodecForTr(), {Internationalization with Qt} |
2152 | */ |
2153 | |
2154 | /*! |
2155 | \fn QString QObject::trUtf8(const char *sourceText, const char *disambiguation, int n) |
2156 | \reentrant |
2157 | |
2158 | Returns a translated version of \a sourceText, or |
2159 | QString::fromUtf8(\a sourceText) if there is no appropriate |
2160 | version. It is otherwise identical to tr(\a sourceText, \a |
2161 | disambiguation, \a n). |
2162 | |
2163 | Note that using the Utf8 variants of the translation functions |
2164 | is not required if \c CODECFORTR is already set to UTF-8 in the |
2165 | qmake project file and QTextCodec::setCodecForTr("UTF-8") is |
2166 | used. |
2167 | |
2168 | \warning This method is reentrant only if all translators are |
2169 | installed \e before calling this method. Installing or removing |
2170 | translators while performing translations is not supported. Doing |
2171 | so will probably result in crashes or other undesirable behavior. |
2172 | |
2173 | \warning For portability reasons, we recommend that you use |
2174 | escape sequences for specifying non-ASCII characters in string |
2175 | literals to trUtf8(). For example: |
2176 | |
2177 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 20 |
2178 | |
2179 | \sa tr(), QApplication::translate(), {Internationalization with Qt} |
2180 | */ |
2181 | |
2182 | |
2183 | |
2184 | |
2185 | /***************************************************************************** |
2186 | Signals and slots |
2187 | *****************************************************************************/ |
2188 | |
2189 | |
2190 | const char *qFlagLocation(const char *method) |
2191 | { |
2192 | QThreadData::current()->flaggedSignatures.store(method); |
2193 | return method; |
2194 | } |
2195 | |
2196 | static int (const char *member) |
2197 | { |
2198 | // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE |
2199 | return (((int)(*member) - '0') & 0x3); |
2200 | } |
2201 | |
2202 | static const char * (const char *member) |
2203 | { |
2204 | if (QThreadData::current()->flaggedSignatures.contains(member)) { |
2205 | // signature includes location information after the first null-terminator |
2206 | const char *location = member + qstrlen(member) + 1; |
2207 | if (*location != '\0') |
2208 | return location; |
2209 | } |
2210 | return 0; |
2211 | } |
2212 | |
2213 | static bool check_signal_macro(const QObject *sender, const char *signal, |
2214 | const char *func, const char *op) |
2215 | { |
2216 | int sigcode = extract_code(signal); |
2217 | if (sigcode != QSIGNAL_CODE) { |
2218 | if (sigcode == QSLOT_CODE) |
2219 | qWarning("Object::%s: Attempt to %s non-signal %s::%s" , |
2220 | func, op, sender->metaObject()->className(), signal+1); |
2221 | else |
2222 | qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s" , |
2223 | func, op, sender->metaObject()->className(), signal); |
2224 | return false; |
2225 | } |
2226 | return true; |
2227 | } |
2228 | |
2229 | static bool check_method_code(int code, const QObject *object, |
2230 | const char *method, const char *func) |
2231 | { |
2232 | if (code != QSLOT_CODE && code != QSIGNAL_CODE) { |
2233 | qWarning("Object::%s: Use the SLOT or SIGNAL macro to " |
2234 | "%s %s::%s" , func, func, object->metaObject()->className(), method); |
2235 | return false; |
2236 | } |
2237 | return true; |
2238 | } |
2239 | |
2240 | static void err_method_notfound(const QObject *object, |
2241 | const char *method, const char *func) |
2242 | { |
2243 | const char *type = "method" ; |
2244 | switch (extract_code(method)) { |
2245 | case QSLOT_CODE: type = "slot" ; break; |
2246 | case QSIGNAL_CODE: type = "signal" ; break; |
2247 | } |
2248 | const char *loc = extract_location(method); |
2249 | if (strchr(method,')') == 0) // common typing mistake |
2250 | qWarning("Object::%s: Parentheses expected, %s %s::%s%s%s" , |
2251 | func, type, object->metaObject()->className(), method+1, |
2252 | loc ? " in " : "" , loc ? loc : "" ); |
2253 | else |
2254 | qWarning("Object::%s: No such %s %s::%s%s%s" , |
2255 | func, type, object->metaObject()->className(), method+1, |
2256 | loc ? " in " : "" , loc ? loc : "" ); |
2257 | |
2258 | } |
2259 | |
2260 | |
2261 | static void err_info_about_objects(const char * func, |
2262 | const QObject * sender, |
2263 | const QObject * receiver) |
2264 | { |
2265 | QString a = sender ? sender->objectName() : QString(); |
2266 | QString b = receiver ? receiver->objectName() : QString(); |
2267 | if (!a.isEmpty()) |
2268 | qWarning("Object::%s: (sender name: '%s')" , func, a.toLocal8Bit().data()); |
2269 | if (!b.isEmpty()) |
2270 | qWarning("Object::%s: (receiver name: '%s')" , func, b.toLocal8Bit().data()); |
2271 | } |
2272 | |
2273 | /*! |
2274 | Returns a pointer to the object that sent the signal, if called in |
2275 | a slot activated by a signal; otherwise it returns 0. The pointer |
2276 | is valid only during the execution of the slot that calls this |
2277 | function from this object's thread context. |
2278 | |
2279 | The pointer returned by this function becomes invalid if the |
2280 | sender is destroyed, or if the slot is disconnected from the |
2281 | sender's signal. |
2282 | |
2283 | \warning This function violates the object-oriented principle of |
2284 | modularity. However, getting access to the sender might be useful |
2285 | when many signals are connected to a single slot. |
2286 | |
2287 | \warning As mentioned above, the return value of this function is |
2288 | not valid when the slot is called via a Qt::DirectConnection from |
2289 | a thread different from this object's thread. Do not use this |
2290 | function in this type of scenario. |
2291 | |
2292 | \sa senderSignalIndex(), QSignalMapper |
2293 | */ |
2294 | |
2295 | QObject *QObject::sender() const |
2296 | { |
2297 | Q_D(const QObject); |
2298 | |
2299 | QMutexLocker locker(signalSlotLock(this)); |
2300 | if (!d->currentSender) |
2301 | return 0; |
2302 | |
2303 | for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) { |
2304 | if (c->sender == d->currentSender->sender) |
2305 | return d->currentSender->sender; |
2306 | } |
2307 | |
2308 | return 0; |
2309 | } |
2310 | |
2311 | /*! |
2312 | \since 4.8 |
2313 | |
2314 | Returns the meta-method index of the signal that called the currently |
2315 | executing slot, which is a member of the class returned by sender(). |
2316 | If called outside of a slot activated by a signal, -1 is returned. |
2317 | |
2318 | For signals with default parameters, this function will always return |
2319 | the index with all parameters, regardless of which was used with |
2320 | connect(). For example, the signal \c {destroyed(QObject *obj = 0)} |
2321 | will have two different indexes (with and without the parameter), but |
2322 | this function will always return the index with a parameter. This does |
2323 | not apply when overloading signals with different parameters. |
2324 | |
2325 | \warning This function violates the object-oriented principle of |
2326 | modularity. However, getting access to the signal index might be useful |
2327 | when many signals are connected to a single slot. |
2328 | |
2329 | \warning The return value of this function is not valid when the slot |
2330 | is called via a Qt::DirectConnection from a thread different from this |
2331 | object's thread. Do not use this function in this type of scenario. |
2332 | |
2333 | \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method() |
2334 | */ |
2335 | |
2336 | int QObject::senderSignalIndex() const |
2337 | { |
2338 | Q_D(const QObject); |
2339 | |
2340 | QMutexLocker locker(signalSlotLock(this)); |
2341 | if (!d->currentSender) |
2342 | return -1; |
2343 | |
2344 | for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) { |
2345 | if (c->sender == d->currentSender->sender) |
2346 | return d->currentSender->signal; |
2347 | } |
2348 | |
2349 | return -1; |
2350 | } |
2351 | |
2352 | /*! |
2353 | Returns the number of receivers connected to the \a signal. |
2354 | |
2355 | Since both slots and signals can be used as receivers for signals, |
2356 | and the same connections can be made many times, the number of |
2357 | receivers is the same as the number of connections made from this |
2358 | signal. |
2359 | |
2360 | When calling this function, you can use the \c SIGNAL() macro to |
2361 | pass a specific signal: |
2362 | |
2363 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 21 |
2364 | |
2365 | As the code snippet above illustrates, you can use this function |
2366 | to avoid emitting a signal that nobody listens to. |
2367 | |
2368 | \warning This function violates the object-oriented principle of |
2369 | modularity. However, it might be useful when you need to perform |
2370 | expensive initialization only if something is connected to a |
2371 | signal. |
2372 | */ |
2373 | |
2374 | int QObject::receivers(const char *signal) const |
2375 | { |
2376 | Q_D(const QObject); |
2377 | int receivers = 0; |
2378 | if (signal) { |
2379 | QByteArray signal_name = QMetaObject::normalizedSignature(signal); |
2380 | signal = signal_name; |
2381 | #ifndef QT_NO_DEBUG |
2382 | if (!check_signal_macro(this, signal, "receivers" , "bind" )) |
2383 | return 0; |
2384 | #endif |
2385 | signal++; // skip code |
2386 | int signal_index = d->signalIndex(signal); |
2387 | if (signal_index < 0) { |
2388 | #ifndef QT_NO_DEBUG |
2389 | err_method_notfound(this, signal-1, "receivers" ); |
2390 | #endif |
2391 | return false; |
2392 | } |
2393 | |
2394 | Q_D(const QObject); |
2395 | QMutexLocker locker(signalSlotLock(this)); |
2396 | if (d->connectionLists) { |
2397 | if (signal_index < d->connectionLists->count()) { |
2398 | const QObjectPrivate::Connection *c = |
2399 | d->connectionLists->at(signal_index).first; |
2400 | while (c) { |
2401 | receivers += c->receiver ? 1 : 0; |
2402 | c = c->nextConnectionList; |
2403 | } |
2404 | } |
2405 | } |
2406 | } |
2407 | return receivers; |
2408 | } |
2409 | |
2410 | /*! |
2411 | \internal |
2412 | |
2413 | This helper function calculates signal and method index for the given |
2414 | member in the specified class. |
2415 | |
2416 | \list |
2417 | \o If member.mobj is 0 then both signalIndex and methodIndex are set to -1. |
2418 | |
2419 | \o If specified member is not a member of obj instance class (or one of |
2420 | its parent classes) then both signalIndex and methodIndex are set to -1. |
2421 | \endlist |
2422 | |
2423 | This function is used by QObject::connect and QObject::disconnect which |
2424 | are working with QMetaMethod. |
2425 | |
2426 | \a signalIndex is set to the signal index of member. If the member |
2427 | specified is not signal this variable is set to -1. |
2428 | |
2429 | \a methodIndex is set to the method index of the member. If the |
2430 | member is not a method of the object specified by the \a obj argument this |
2431 | variable is set to -1. |
2432 | */ |
2433 | void QMetaObjectPrivate::memberIndexes(const QObject *obj, |
2434 | const QMetaMethod &member, |
2435 | int *signalIndex, int *methodIndex) |
2436 | { |
2437 | *signalIndex = -1; |
2438 | *methodIndex = -1; |
2439 | if (!obj || !member.mobj) |
2440 | return; |
2441 | const QMetaObject *m = obj->metaObject(); |
2442 | // Check that member is member of obj class |
2443 | while (m != 0 && m != member.mobj) |
2444 | m = m->d.superdata; |
2445 | if (!m) |
2446 | return; |
2447 | *signalIndex = *methodIndex = (member.handle - get(member.mobj)->methodData)/5; |
2448 | |
2449 | int signalOffset; |
2450 | int methodOffset; |
2451 | computeOffsets(m, &signalOffset, &methodOffset); |
2452 | |
2453 | *methodIndex += methodOffset; |
2454 | if (member.methodType() == QMetaMethod::Signal) { |
2455 | *signalIndex = originalClone(m, *signalIndex); |
2456 | *signalIndex += signalOffset; |
2457 | } else { |
2458 | *signalIndex = -1; |
2459 | } |
2460 | } |
2461 | |
2462 | static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal, |
2463 | const QMetaObject *receiver, const QMetaMethod &method) |
2464 | { |
2465 | if (signal.attributes() & QMetaMethod::Compatibility) { |
2466 | if (!(method.attributes() & QMetaMethod::Compatibility)) |
2467 | qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)" , |
2468 | sender->className(), signal.signature()); |
2469 | } else if ((method.attributes() & QMetaMethod::Compatibility) && |
2470 | method.methodType() == QMetaMethod::Signal) { |
2471 | qWarning("QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)" , |
2472 | sender->className(), signal.signature(), |
2473 | receiver->className(), method.signature()); |
2474 | } |
2475 | } |
2476 | |
2477 | /*! |
2478 | \threadsafe |
2479 | |
2480 | Creates a connection of the given \a type from the \a signal in |
2481 | the \a sender object to the \a method in the \a receiver object. |
2482 | Returns true if the connection succeeds; otherwise returns false. |
2483 | |
2484 | You must use the \c SIGNAL() and \c SLOT() macros when specifying |
2485 | the \a signal and the \a method, for example: |
2486 | |
2487 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 22 |
2488 | |
2489 | This example ensures that the label always displays the current |
2490 | scroll bar value. Note that the signal and slots parameters must not |
2491 | contain any variable names, only the type. E.g. the following would |
2492 | not work and return false: |
2493 | |
2494 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 23 |
2495 | |
2496 | A signal can also be connected to another signal: |
2497 | |
2498 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 24 |
2499 | |
2500 | In this example, the \c MyWidget constructor relays a signal from |
2501 | a private member variable, and makes it available under a name |
2502 | that relates to \c MyWidget. |
2503 | |
2504 | A signal can be connected to many slots and signals. Many signals |
2505 | can be connected to one slot. |
2506 | |
2507 | If a signal is connected to several slots, the slots are activated |
2508 | in the same order as the order the connection was made, when the |
2509 | signal is emitted. |
2510 | |
2511 | The function returns true if it successfully connects the signal |
2512 | to the slot. It will return false if it cannot create the |
2513 | connection, for example, if QObject is unable to verify the |
2514 | existence of either \a signal or \a method, or if their signatures |
2515 | aren't compatible. |
2516 | |
2517 | By default, a signal is emitted for every connection you make; |
2518 | two signals are emitted for duplicate connections. You can break |
2519 | all of these connections with a single disconnect() call. |
2520 | If you pass the Qt::UniqueConnection \a type, the connection will only |
2521 | be made if it is not a duplicate. If there is already a duplicate |
2522 | (exact same signal to the exact same slot on the same objects), |
2523 | the connection will fail and connect will return false. |
2524 | |
2525 | The optional \a type parameter describes the type of connection |
2526 | to establish. In particular, it determines whether a particular |
2527 | signal is delivered to a slot immediately or queued for delivery |
2528 | at a later time. If the signal is queued, the parameters must be |
2529 | of types that are known to Qt's meta-object system, because Qt |
2530 | needs to copy the arguments to store them in an event behind the |
2531 | scenes. If you try to use a queued connection and get the error |
2532 | message |
2533 | |
2534 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25 |
2535 | |
2536 | call qRegisterMetaType() to register the data type before you |
2537 | establish the connection. |
2538 | |
2539 | \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE() |
2540 | */ |
2541 | |
2542 | bool QObject::connect(const QObject *sender, const char *signal, |
2543 | const QObject *receiver, const char *method, |
2544 | Qt::ConnectionType type) |
2545 | { |
2546 | { |
2547 | const void *cbdata[] = { sender, signal, receiver, method, &type }; |
2548 | if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata)) |
2549 | return true; |
2550 | } |
2551 | |
2552 | #ifndef QT_NO_DEBUG |
2553 | bool warnCompat = true; |
2554 | #endif |
2555 | if (type == Qt::AutoCompatConnection) { |
2556 | type = Qt::AutoConnection; |
2557 | #ifndef QT_NO_DEBUG |
2558 | warnCompat = false; |
2559 | #endif |
2560 | } |
2561 | |
2562 | if (sender == 0 || receiver == 0 || signal == 0 || method == 0) { |
2563 | qWarning("QObject::connect: Cannot connect %s::%s to %s::%s" , |
2564 | sender ? sender->metaObject()->className() : "(null)" , |
2565 | (signal && *signal) ? signal+1 : "(null)" , |
2566 | receiver ? receiver->metaObject()->className() : "(null)" , |
2567 | (method && *method) ? method+1 : "(null)" ); |
2568 | return false; |
2569 | } |
2570 | QByteArray tmp_signal_name; |
2571 | |
2572 | if (!check_signal_macro(sender, signal, "connect" , "bind" )) |
2573 | return false; |
2574 | const QMetaObject *smeta = sender->metaObject(); |
2575 | const char *signal_arg = signal; |
2576 | ++signal; //skip code |
2577 | int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
2578 | if (signal_index < 0) { |
2579 | // check for normalized signatures |
2580 | tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); |
2581 | signal = tmp_signal_name.constData() + 1; |
2582 | |
2583 | smeta = sender->metaObject(); |
2584 | signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
2585 | } |
2586 | if (signal_index < 0) { |
2587 | // re-use tmp_signal_name and signal from above |
2588 | |
2589 | smeta = sender->metaObject(); |
2590 | signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); |
2591 | } |
2592 | if (signal_index < 0) { |
2593 | err_method_notfound(sender, signal_arg, "connect" ); |
2594 | err_info_about_objects("connect" , sender, receiver); |
2595 | return false; |
2596 | } |
2597 | signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2598 | int signalOffset, methodOffset; |
2599 | computeOffsets(smeta, &signalOffset, &methodOffset); |
2600 | int signal_absolute_index = signal_index + methodOffset; |
2601 | signal_index += signalOffset; |
2602 | |
2603 | QByteArray tmp_method_name; |
2604 | int membcode = extract_code(method); |
2605 | |
2606 | if (!check_method_code(membcode, receiver, method, "connect" )) |
2607 | return false; |
2608 | const char *method_arg = method; |
2609 | ++method; // skip code |
2610 | |
2611 | const QMetaObject *rmeta = receiver->metaObject(); |
2612 | int method_index_relative = -1; |
2613 | switch (membcode) { |
2614 | case QSLOT_CODE: |
2615 | method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); |
2616 | break; |
2617 | case QSIGNAL_CODE: |
2618 | method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); |
2619 | break; |
2620 | } |
2621 | |
2622 | if (method_index_relative < 0) { |
2623 | // check for normalized methods |
2624 | tmp_method_name = QMetaObject::normalizedSignature(method); |
2625 | method = tmp_method_name.constData(); |
2626 | |
2627 | // rmeta may have been modified above |
2628 | rmeta = receiver->metaObject(); |
2629 | switch (membcode) { |
2630 | case QSLOT_CODE: |
2631 | method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); |
2632 | if (method_index_relative < 0) |
2633 | method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true); |
2634 | break; |
2635 | case QSIGNAL_CODE: |
2636 | method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); |
2637 | if (method_index_relative < 0) |
2638 | method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true); |
2639 | break; |
2640 | } |
2641 | } |
2642 | |
2643 | if (method_index_relative < 0) { |
2644 | err_method_notfound(receiver, method_arg, "connect" ); |
2645 | err_info_about_objects("connect" , sender, receiver); |
2646 | return false; |
2647 | } |
2648 | |
2649 | if (!QMetaObject::checkConnectArgs(signal, method)) { |
2650 | qWarning("QObject::connect: Incompatible sender/receiver arguments" |
2651 | "\n %s::%s --> %s::%s" , |
2652 | sender->metaObject()->className(), signal, |
2653 | receiver->metaObject()->className(), method); |
2654 | return false; |
2655 | } |
2656 | |
2657 | int *types = 0; |
2658 | if ((type == Qt::QueuedConnection) |
2659 | && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes()))) |
2660 | return false; |
2661 | |
2662 | #ifndef QT_NO_DEBUG |
2663 | if (warnCompat) { |
2664 | QMetaMethod smethod = smeta->method(signal_absolute_index); |
2665 | QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset()); |
2666 | check_and_warn_compat(smeta, smethod, rmeta, rmethod); |
2667 | } |
2668 | #endif |
2669 | if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types)) |
2670 | return false; |
2671 | const_cast<QObject*>(sender)->connectNotify(signal - 1); |
2672 | return true; |
2673 | } |
2674 | |
2675 | /*! |
2676 | \since 4.8 |
2677 | |
2678 | Creates a connection of the given \a type from the \a signal in |
2679 | the \a sender object to the \a method in the \a receiver object. |
2680 | Returns true if the connection succeeds; otherwise returns false. |
2681 | |
2682 | This function works in the same way as |
2683 | connect(const QObject *sender, const char *signal, |
2684 | const QObject *receiver, const char *method, |
2685 | Qt::ConnectionType type) |
2686 | but it uses QMetaMethod to specify signal and method. |
2687 | |
2688 | \sa connect(const QObject *sender, const char *signal, |
2689 | const QObject *receiver, const char *method, |
2690 | Qt::ConnectionType type) |
2691 | */ |
2692 | bool QObject::connect(const QObject *sender, const QMetaMethod &signal, |
2693 | const QObject *receiver, const QMetaMethod &method, |
2694 | Qt::ConnectionType type) |
2695 | { |
2696 | #ifndef QT_NO_DEBUG |
2697 | bool warnCompat = true; |
2698 | #endif |
2699 | if (type == Qt::AutoCompatConnection) { |
2700 | type = Qt::AutoConnection; |
2701 | #ifndef QT_NO_DEBUG |
2702 | warnCompat = false; |
2703 | #endif |
2704 | } |
2705 | |
2706 | if (sender == 0 |
2707 | || receiver == 0 |
2708 | || signal.methodType() != QMetaMethod::Signal |
2709 | || method.methodType() == QMetaMethod::Constructor) { |
2710 | qWarning("QObject::connect: Cannot connect %s::%s to %s::%s" , |
2711 | sender ? sender->metaObject()->className() : "(null)" , |
2712 | signal.signature(), |
2713 | receiver ? receiver->metaObject()->className() : "(null)" , |
2714 | method.signature() ); |
2715 | return false; |
2716 | } |
2717 | |
2718 | QVarLengthArray<char> signalSignature; |
2719 | QObjectPrivate::signalSignature(signal, &signalSignature); |
2720 | |
2721 | { |
2722 | QByteArray methodSignature; |
2723 | methodSignature.reserve(qstrlen(method.signature())+1); |
2724 | methodSignature.append((char)(method.methodType() == QMetaMethod::Slot ? QSLOT_CODE |
2725 | : method.methodType() == QMetaMethod::Signal ? QSIGNAL_CODE : 0 + '0')); |
2726 | methodSignature.append(method.signature()); |
2727 | const void *cbdata[] = { sender, signalSignature.constData(), receiver, methodSignature.constData(), &type }; |
2728 | if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata)) |
2729 | return true; |
2730 | } |
2731 | |
2732 | |
2733 | int signal_index; |
2734 | int method_index; |
2735 | { |
2736 | int dummy; |
2737 | QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy); |
2738 | QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index); |
2739 | } |
2740 | |
2741 | const QMetaObject *smeta = sender->metaObject(); |
2742 | const QMetaObject *rmeta = receiver->metaObject(); |
2743 | if (signal_index == -1) { |
2744 | qWarning("QObject::connect: Can't find signal %s on instance of class %s" , |
2745 | signal.signature(), smeta->className()); |
2746 | return false; |
2747 | } |
2748 | if (method_index == -1) { |
2749 | qWarning("QObject::connect: Can't find method %s on instance of class %s" , |
2750 | method.signature(), rmeta->className()); |
2751 | return false; |
2752 | } |
2753 | |
2754 | if (!QMetaObject::checkConnectArgs(signal.signature(), method.signature())) { |
2755 | qWarning("QObject::connect: Incompatible sender/receiver arguments" |
2756 | "\n %s::%s --> %s::%s" , |
2757 | smeta->className(), signal.signature(), |
2758 | rmeta->className(), method.signature()); |
2759 | return false; |
2760 | } |
2761 | |
2762 | int *types = 0; |
2763 | if ((type == Qt::QueuedConnection) |
2764 | && !(types = queuedConnectionTypes(signal.parameterTypes()))) |
2765 | return false; |
2766 | |
2767 | #ifndef QT_NO_DEBUG |
2768 | if (warnCompat) |
2769 | check_and_warn_compat(smeta, signal, rmeta, method); |
2770 | #endif |
2771 | if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, 0, type, types)) |
2772 | return false; |
2773 | |
2774 | const_cast<QObject*>(sender)->connectNotify(signalSignature.constData()); |
2775 | return true; |
2776 | } |
2777 | |
2778 | /*! |
2779 | \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const |
2780 | \overload connect() |
2781 | \threadsafe |
2782 | |
2783 | Connects \a signal from the \a sender object to this object's \a |
2784 | method. |
2785 | |
2786 | Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type). |
2787 | |
2788 | Every connection you make emits a signal, so duplicate connections emit |
2789 | two signals. You can break a connection using disconnect(). |
2790 | |
2791 | \sa disconnect() |
2792 | */ |
2793 | |
2794 | /*! |
2795 | \threadsafe |
2796 | |
2797 | Disconnects \a signal in object \a sender from \a method in object |
2798 | \a receiver. Returns true if the connection is successfully broken; |
2799 | otherwise returns false. |
2800 | |
2801 | A signal-slot connection is removed when either of the objects |
2802 | involved are destroyed. |
2803 | |
2804 | disconnect() is typically used in three ways, as the following |
2805 | examples demonstrate. |
2806 | \list 1 |
2807 | \i Disconnect everything connected to an object's signals: |
2808 | |
2809 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 26 |
2810 | |
2811 | equivalent to the non-static overloaded function |
2812 | |
2813 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 27 |
2814 | |
2815 | \i Disconnect everything connected to a specific signal: |
2816 | |
2817 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 28 |
2818 | |
2819 | equivalent to the non-static overloaded function |
2820 | |
2821 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 29 |
2822 | |
2823 | \i Disconnect a specific receiver: |
2824 | |
2825 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 30 |
2826 | |
2827 | equivalent to the non-static overloaded function |
2828 | |
2829 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 31 |
2830 | |
2831 | \endlist |
2832 | |
2833 | 0 may be used as a wildcard, meaning "any signal", "any receiving |
2834 | object", or "any slot in the receiving object", respectively. |
2835 | |
2836 | The \a sender may never be 0. (You cannot disconnect signals from |
2837 | more than one object in a single call.) |
2838 | |
2839 | If \a signal is 0, it disconnects \a receiver and \a method from |
2840 | any signal. If not, only the specified signal is disconnected. |
2841 | |
2842 | If \a receiver is 0, it disconnects anything connected to \a |
2843 | signal. If not, slots in objects other than \a receiver are not |
2844 | disconnected. |
2845 | |
2846 | If \a method is 0, it disconnects anything that is connected to \a |
2847 | receiver. If not, only slots named \a method will be disconnected, |
2848 | and all other slots are left alone. The \a method must be 0 if \a |
2849 | receiver is left out, so you cannot disconnect a |
2850 | specifically-named slot on all objects. |
2851 | |
2852 | \sa connect() |
2853 | */ |
2854 | bool QObject::disconnect(const QObject *sender, const char *signal, |
2855 | const QObject *receiver, const char *method) |
2856 | { |
2857 | if (sender == 0 || (receiver == 0 && method != 0)) { |
2858 | qWarning("Object::disconnect: Unexpected null parameter" ); |
2859 | return false; |
2860 | } |
2861 | |
2862 | { |
2863 | const void *cbdata[] = { sender, signal, receiver, method }; |
2864 | if (QInternal::activateCallbacks(QInternal::DisconnectCallback, (void **) cbdata)) |
2865 | return true; |
2866 | } |
2867 | |
2868 | const char *signal_arg = signal; |
2869 | QByteArray signal_name; |
2870 | bool signal_found = false; |
2871 | if (signal) { |
2872 | QT_TRY { |
2873 | signal_name = QMetaObject::normalizedSignature(signal); |
2874 | signal = signal_name.constData(); |
2875 | } QT_CATCH (const std::bad_alloc &) { |
2876 | // if the signal is already normalized, we can continue. |
2877 | if (sender->metaObject()->indexOfSignal(signal + 1) == -1) |
2878 | QT_RETHROW; |
2879 | } |
2880 | |
2881 | if (!check_signal_macro(sender, signal, "disconnect" , "unbind" )) |
2882 | return false; |
2883 | signal++; // skip code |
2884 | } |
2885 | |
2886 | QByteArray method_name; |
2887 | const char *method_arg = method; |
2888 | int membcode = -1; |
2889 | bool method_found = false; |
2890 | if (method) { |
2891 | QT_TRY { |
2892 | method_name = QMetaObject::normalizedSignature(method); |
2893 | method = method_name.constData(); |
2894 | } QT_CATCH(const std::bad_alloc &) { |
2895 | // if the method is already normalized, we can continue. |
2896 | if (receiver->metaObject()->indexOfMethod(method + 1) == -1) |
2897 | QT_RETHROW; |
2898 | } |
2899 | |
2900 | membcode = extract_code(method); |
2901 | if (!check_method_code(membcode, receiver, method, "disconnect" )) |
2902 | return false; |
2903 | method++; // skip code |
2904 | } |
2905 | |
2906 | /* We now iterate through all the sender's and receiver's meta |
2907 | * objects in order to also disconnect possibly shadowed signals |
2908 | * and slots with the same signature. |
2909 | */ |
2910 | bool res = false; |
2911 | const QMetaObject *smeta = sender->metaObject(); |
2912 | do { |
2913 | int signal_index = -1; |
2914 | if (signal) { |
2915 | signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
2916 | if (signal_index < 0) |
2917 | signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); |
2918 | if (signal_index < 0) |
2919 | break; |
2920 | signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2921 | int signalOffset, methodOffset; |
2922 | computeOffsets(smeta, &signalOffset, &methodOffset); |
2923 | signal_index += signalOffset; |
2924 | signal_found = true; |
2925 | } |
2926 | |
2927 | if (!method) { |
2928 | res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1); |
2929 | } else { |
2930 | const QMetaObject *rmeta = receiver->metaObject(); |
2931 | do { |
2932 | int method_index = rmeta->indexOfMethod(method); |
2933 | if (method_index >= 0) |
2934 | while (method_index < rmeta->methodOffset()) |
2935 | rmeta = rmeta->superClass(); |
2936 | if (method_index < 0) |
2937 | break; |
2938 | res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index); |
2939 | method_found = true; |
2940 | } while ((rmeta = rmeta->superClass())); |
2941 | } |
2942 | } while (signal && (smeta = smeta->superClass())); |
2943 | |
2944 | if (signal && !signal_found) { |
2945 | err_method_notfound(sender, signal_arg, "disconnect" ); |
2946 | err_info_about_objects("disconnect" , sender, receiver); |
2947 | } else if (method && !method_found) { |
2948 | err_method_notfound(receiver, method_arg, "disconnect" ); |
2949 | err_info_about_objects("disconnect" , sender, receiver); |
2950 | } |
2951 | if (res) |
2952 | const_cast<QObject*>(sender)->disconnectNotify(signal ? (signal - 1) : 0); |
2953 | return res; |
2954 | } |
2955 | |
2956 | /*! |
2957 | \since 4.8 |
2958 | |
2959 | Disconnects \a signal in object \a sender from \a method in object |
2960 | \a receiver. Returns true if the connection is successfully broken; |
2961 | otherwise returns false. |
2962 | |
2963 | This function provides the same possibilities like |
2964 | disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) |
2965 | but uses QMetaMethod to represent the signal and the method to be disconnected. |
2966 | |
2967 | Additionally this function returnsfalse and no signals and slots disconnected |
2968 | if: |
2969 | \list 1 |
2970 | |
2971 | \i \a signal is not a member of sender class or one of its parent classes. |
2972 | |
2973 | \i \a method is not a member of receiver class or one of its parent classes. |
2974 | |
2975 | \i \a signal instance represents not a signal. |
2976 | |
2977 | \endlist |
2978 | |
2979 | QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object". |
2980 | In the same way 0 can be used for \a receiver in the meaning "any receiving object". In this case |
2981 | method should also be QMetaMethod(). \a sender parameter should be never 0. |
2982 | |
2983 | \sa disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) |
2984 | */ |
2985 | bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, |
2986 | const QObject *receiver, const QMetaMethod &method) |
2987 | { |
2988 | if (sender == 0 || (receiver == 0 && method.mobj != 0)) { |
2989 | qWarning("Object::disconnect: Unexpected null parameter" ); |
2990 | return false; |
2991 | } |
2992 | if (signal.mobj) { |
2993 | if(signal.methodType() != QMetaMethod::Signal) { |
2994 | qWarning("Object::%s: Attempt to %s non-signal %s::%s" , |
2995 | "disconnect" ,"unbind" , |
2996 | sender->metaObject()->className(), signal.signature()); |
2997 | return false; |
2998 | } |
2999 | } |
3000 | if (method.mobj) { |
3001 | if(method.methodType() == QMetaMethod::Constructor) { |
3002 | qWarning("QObject::disconect: cannot use constructor as argument %s::%s" , |
3003 | receiver->metaObject()->className(), method.signature()); |
3004 | return false; |
3005 | } |
3006 | } |
3007 | |
3008 | QVarLengthArray<char> signalSignature; |
3009 | if (signal.mobj) |
3010 | QObjectPrivate::signalSignature(signal, &signalSignature); |
3011 | |
3012 | { |
3013 | QByteArray methodSignature; |
3014 | if (method.mobj) { |
3015 | methodSignature.reserve(qstrlen(method.signature())+1); |
3016 | methodSignature.append((char)(method.methodType() == QMetaMethod::Slot ? QSLOT_CODE |
3017 | : method.methodType() == QMetaMethod::Signal ? QSIGNAL_CODE : 0 + '0')); |
3018 | methodSignature.append(method.signature()); |
3019 | } |
3020 | const void *cbdata[] = { sender, signal.mobj ? signalSignature.constData() : 0, |
3021 | receiver, method.mobj ? methodSignature.constData() : 0 }; |
3022 | if (QInternal::activateCallbacks(QInternal::DisconnectCallback, (void **) cbdata)) |
3023 | return true; |
3024 | } |
3025 | |
3026 | int signal_index; |
3027 | int method_index; |
3028 | { |
3029 | int dummy; |
3030 | QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy); |
3031 | QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index); |
3032 | } |
3033 | // If we are here sender is not null. If signal is not null while signal_index |
3034 | // is -1 then this signal is not a member of sender. |
3035 | if (signal.mobj && signal_index == -1) { |
3036 | qWarning("QObject::disconect: signal %s not found on class %s" , |
3037 | signal.signature(), sender->metaObject()->className()); |
3038 | return false; |
3039 | } |
3040 | // If this condition is true then method is not a member of receeiver. |
3041 | if (receiver && method.mobj && method_index == -1) { |
3042 | qWarning("QObject::disconect: method %s not found on class %s" , |
3043 | method.signature(), receiver->metaObject()->className()); |
3044 | return false; |
3045 | } |
3046 | |
3047 | if (!QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index)) |
3048 | return false; |
3049 | |
3050 | const_cast<QObject*>(sender)->disconnectNotify(method.mobj ? signalSignature.constData() : 0); |
3051 | return true; |
3052 | } |
3053 | |
3054 | /*! |
3055 | \threadsafe |
3056 | |
3057 | \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) |
3058 | \overload disconnect() |
3059 | |
3060 | Disconnects \a signal from \a method of \a receiver. |
3061 | |
3062 | A signal-slot connection is removed when either of the objects |
3063 | involved are destroyed. |
3064 | */ |
3065 | |
3066 | /*! |
3067 | \fn bool QObject::disconnect(const QObject *receiver, const char *method) |
3068 | \overload disconnect() |
3069 | |
3070 | Disconnects all signals in this object from \a receiver's \a |
3071 | method. |
3072 | |
3073 | A signal-slot connection is removed when either of the objects |
3074 | involved are destroyed. |
3075 | */ |
3076 | |
3077 | |
3078 | /*! |
3079 | \fn void QObject::connectNotify(const char *signal) |
3080 | |
3081 | This virtual function is called when something has been connected |
3082 | to \a signal in this object. |
3083 | |
3084 | If you want to compare \a signal with a specific signal, use |
3085 | QLatin1String and the \c SIGNAL() macro as follows: |
3086 | |
3087 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 32 |
3088 | |
3089 | If the signal contains multiple parameters or parameters that |
3090 | contain spaces, call QMetaObject::normalizedSignature() on |
3091 | the result of the \c SIGNAL() macro. |
3092 | |
3093 | \warning This function violates the object-oriented principle of |
3094 | modularity. However, it might be useful when you need to perform |
3095 | expensive initialization only if something is connected to a |
3096 | signal. |
3097 | |
3098 | \sa connect(), disconnectNotify() |
3099 | */ |
3100 | |
3101 | void QObject::connectNotify(const char *) |
3102 | { |
3103 | } |
3104 | |
3105 | /*! |
3106 | \fn void QObject::disconnectNotify(const char *signal) |
3107 | |
3108 | This virtual function is called when something has been |
3109 | disconnected from \a signal in this object. |
3110 | |
3111 | See connectNotify() for an example of how to compare |
3112 | \a signal with a specific signal. |
3113 | |
3114 | \warning This function violates the object-oriented principle of |
3115 | modularity. However, it might be useful for optimizing access to |
3116 | expensive resources. |
3117 | |
3118 | \sa disconnect(), connectNotify() |
3119 | */ |
3120 | |
3121 | void QObject::disconnectNotify(const char *) |
3122 | { |
3123 | } |
3124 | |
3125 | /* \internal |
3126 | convert a signal index from the method range to the signal range |
3127 | */ |
3128 | static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_index) |
3129 | { |
3130 | if (signal_index < 0) |
3131 | return signal_index; |
3132 | while (metaObject && metaObject->methodOffset() > signal_index) |
3133 | metaObject = metaObject->superClass(); |
3134 | |
3135 | if (metaObject) { |
3136 | int signalOffset, methodOffset; |
3137 | computeOffsets(metaObject, &signalOffset, &methodOffset); |
3138 | if (signal_index < metaObject->methodCount()) |
3139 | signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset; |
3140 | else |
3141 | signal_index = signal_index - methodOffset + signalOffset; |
3142 | } |
3143 | return signal_index; |
3144 | } |
3145 | |
3146 | /*!\internal |
3147 | \a types is a 0-terminated vector of meta types for queued |
3148 | connections. |
3149 | |
3150 | if \a signal_index is -1, then we effectively connect *all* signals |
3151 | from the sender to the receiver's slot |
3152 | */ |
3153 | bool QMetaObject::connect(const QObject *sender, int signal_index, |
3154 | const QObject *receiver, int method_index, int type, int *types) |
3155 | { |
3156 | signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); |
3157 | return QMetaObjectPrivate::connect(sender, signal_index, |
3158 | receiver, method_index, |
3159 | 0, //FIXME, we could speed this connection up by computing the relative index |
3160 | type, types); |
3161 | } |
3162 | |
3163 | /*! \internal |
3164 | Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex |
3165 | |
3166 | method_index is relative to the rmeta metaobject, if rmeta is null, then it is absolute index |
3167 | */ |
3168 | bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, |
3169 | const QObject *receiver, int method_index, |
3170 | const QMetaObject *rmeta, int type, int *types) |
3171 | { |
3172 | QObject *s = const_cast<QObject *>(sender); |
3173 | QObject *r = const_cast<QObject *>(receiver); |
3174 | |
3175 | int method_offset = rmeta ? rmeta->methodOffset() : 0; |
3176 | QObjectPrivate::StaticMetaCallFunction callFunction = |
3177 | (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata) |
3178 | ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0; |
3179 | |
3180 | QOrderedMutexLocker locker(signalSlotLock(sender), |
3181 | signalSlotLock(receiver)); |
3182 | |
3183 | if (type & Qt::UniqueConnection) { |
3184 | QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; |
3185 | if (connectionLists && connectionLists->count() > signal_index) { |
3186 | const QObjectPrivate::Connection *c2 = |
3187 | (*connectionLists)[signal_index].first; |
3188 | |
3189 | int method_index_absolute = method_index + method_offset; |
3190 | |
3191 | while (c2) { |
3192 | if (c2->receiver == receiver && c2->method() == method_index_absolute) |
3193 | return false; |
3194 | c2 = c2->nextConnectionList; |
3195 | } |
3196 | } |
3197 | type &= Qt::UniqueConnection - 1; |
3198 | } |
3199 | |
3200 | QObjectPrivate::Connection *c = new QObjectPrivate::Connection; |
3201 | c->sender = s; |
3202 | c->receiver = r; |
3203 | c->method_relative = method_index; |
3204 | c->method_offset = method_offset; |
3205 | c->connectionType = type; |
3206 | c->argumentTypes = types; |
3207 | c->nextConnectionList = 0; |
3208 | c->callFunction = callFunction; |
3209 | |
3210 | QT_TRY { |
3211 | QObjectPrivate::get(s)->addConnection(signal_index, c); |
3212 | } QT_CATCH(...) { |
3213 | delete c; |
3214 | QT_RETHROW; |
3215 | } |
3216 | |
3217 | c->prev = &(QObjectPrivate::get(r)->senders); |
3218 | c->next = *c->prev; |
3219 | *c->prev = c; |
3220 | if (c->next) |
3221 | c->next->prev = &c->next; |
3222 | |
3223 | QObjectPrivate *const sender_d = QObjectPrivate::get(s); |
3224 | if (signal_index < 0) { |
3225 | sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0; |
3226 | } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) { |
3227 | sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f)); |
3228 | } |
3229 | |
3230 | return true; |
3231 | } |
3232 | |
3233 | /*!\internal |
3234 | */ |
3235 | bool QMetaObject::disconnect(const QObject *sender, int signal_index, |
3236 | const QObject *receiver, int method_index) |
3237 | { |
3238 | signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); |
3239 | return QMetaObjectPrivate::disconnect(sender, signal_index, |
3240 | receiver, method_index); |
3241 | } |
3242 | |
3243 | /*!\internal |
3244 | |
3245 | Disconnect a single signal connection. If QMetaObject::connect() has been called |
3246 | multiple times for the same sender, signal_index, receiver and method_index only |
3247 | one of these connections will be removed. |
3248 | */ |
3249 | bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, |
3250 | const QObject *receiver, int method_index) |
3251 | { |
3252 | signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); |
3253 | return QMetaObjectPrivate::disconnect(sender, signal_index, |
3254 | receiver, method_index, |
3255 | QMetaObjectPrivate::DisconnectOne); |
3256 | } |
3257 | |
3258 | /*! \internal |
3259 | Helper function to remove the connection from the senders list and setting the receivers to 0 |
3260 | */ |
3261 | bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, |
3262 | const QObject *receiver, int method_index, |
3263 | QMutex *senderMutex, DisconnectType disconnectType) |
3264 | { |
3265 | bool success = false; |
3266 | while (c) { |
3267 | if (c->receiver |
3268 | && (receiver == 0 || (c->receiver == receiver |
3269 | && (method_index < 0 || c->method() == method_index)))) { |
3270 | bool needToUnlock = false; |
3271 | QMutex *receiverMutex = 0; |
3272 | if (!receiver) { |
3273 | receiverMutex = signalSlotLock(c->receiver); |
3274 | // need to relock this receiver and sender in the correct order |
3275 | needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex); |
3276 | } |
3277 | if (c->receiver) { |
3278 | *c->prev = c->next; |
3279 | if (c->next) |
3280 | c->next->prev = c->prev; |
3281 | } |
3282 | |
3283 | if (needToUnlock) |
3284 | receiverMutex->unlockInline(); |
3285 | |
3286 | c->receiver = 0; |
3287 | |
3288 | success = true; |
3289 | |
3290 | if (disconnectType == DisconnectOne) |
3291 | return success; |
3292 | } |
3293 | c = c->nextConnectionList; |
3294 | } |
3295 | return success; |
3296 | } |
3297 | |
3298 | /*! \internal |
3299 | Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex |
3300 | */ |
3301 | bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, |
3302 | const QObject *receiver, int method_index, |
3303 | DisconnectType disconnectType) |
3304 | { |
3305 | if (!sender) |
3306 | return false; |
3307 | |
3308 | QObject *s = const_cast<QObject *>(sender); |
3309 | |
3310 | QMutex *senderMutex = signalSlotLock(sender); |
3311 | QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0; |
3312 | QOrderedMutexLocker locker(senderMutex, receiverMutex); |
3313 | |
3314 | QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; |
3315 | if (!connectionLists) |
3316 | return false; |
3317 | |
3318 | // prevent incoming connections changing the connectionLists while unlocked |
3319 | ++connectionLists->inUse; |
3320 | |
3321 | bool success = false; |
3322 | if (signal_index < 0) { |
3323 | // remove from all connection lists |
3324 | for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { |
3325 | QObjectPrivate::Connection *c = |
3326 | (*connectionLists)[signal_index].first; |
3327 | if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) { |
3328 | success = true; |
3329 | connectionLists->dirty = true; |
3330 | } |
3331 | } |
3332 | } else if (signal_index < connectionLists->count()) { |
3333 | QObjectPrivate::Connection *c = |
3334 | (*connectionLists)[signal_index].first; |
3335 | if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) { |
3336 | success = true; |
3337 | connectionLists->dirty = true; |
3338 | } |
3339 | } |
3340 | |
3341 | --connectionLists->inUse; |
3342 | Q_ASSERT(connectionLists->inUse >= 0); |
3343 | if (connectionLists->orphaned && !connectionLists->inUse) |
3344 | delete connectionLists; |
3345 | |
3346 | return success; |
3347 | } |
3348 | |
3349 | /*! |
3350 | \fn void QMetaObject::connectSlotsByName(QObject *object) |
3351 | |
3352 | Searches recursively for all child objects of the given \a object, and connects |
3353 | matching signals from them to slots of \a object that follow the following form: |
3354 | |
3355 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 33 |
3356 | |
3357 | Let's assume our object has a child object of type QPushButton with |
3358 | the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the |
3359 | button's \c{clicked()} signal would be: |
3360 | |
3361 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 34 |
3362 | |
3363 | \sa QObject::setObjectName() |
3364 | */ |
3365 | void QMetaObject::connectSlotsByName(QObject *o) |
3366 | { |
3367 | if (!o) |
3368 | return; |
3369 | const QMetaObject *mo = o->metaObject(); |
3370 | Q_ASSERT(mo); |
3371 | const QObjectList list = o->findChildren<QObject *>(QString()); |
3372 | for (int i = 0; i < mo->methodCount(); ++i) { |
3373 | const char *slot = mo->method(i).signature(); |
3374 | Q_ASSERT(slot); |
3375 | if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_') |
3376 | continue; |
3377 | bool foundIt = false; |
3378 | for(int j = 0; j < list.count(); ++j) { |
3379 | const QObject *co = list.at(j); |
3380 | QByteArray objName = co->objectName().toAscii(); |
3381 | int len = objName.length(); |
3382 | if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_') |
3383 | continue; |
3384 | int sigIndex = co->d_func()->signalIndex(slot + len + 4); |
3385 | if (sigIndex < 0) { // search for compatible signals |
3386 | const QMetaObject *smo = co->metaObject(); |
3387 | int slotlen = qstrlen(slot + len + 4) - 1; |
3388 | for (int k = 0; k < co->metaObject()->methodCount(); ++k) { |
3389 | QMetaMethod method = smo->method(k); |
3390 | if (method.methodType() != QMetaMethod::Signal) |
3391 | continue; |
3392 | |
3393 | if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) { |
3394 | int signalOffset, methodOffset; |
3395 | computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset); |
3396 | sigIndex = k + - methodOffset + signalOffset; |
3397 | break; |
3398 | } |
3399 | } |
3400 | } |
3401 | if (sigIndex < 0) |
3402 | continue; |
3403 | if (QMetaObjectPrivate::connect(co, sigIndex, o, i)) { |
3404 | foundIt = true; |
3405 | break; |
3406 | } |
3407 | } |
3408 | if (foundIt) { |
3409 | // we found our slot, now skip all overloads |
3410 | while (mo->method(i + 1).attributes() & QMetaMethod::Cloned) |
3411 | ++i; |
3412 | } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) { |
3413 | qWarning("QMetaObject::connectSlotsByName: No matching signal for %s" , slot); |
3414 | } |
3415 | } |
3416 | } |
3417 | |
3418 | static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) |
3419 | { |
3420 | if (!c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { |
3421 | QMetaMethod m = sender->metaObject()->method(signal); |
3422 | int *tmp = queuedConnectionTypes(m.parameterTypes()); |
3423 | if (!tmp) // cannot queue arguments |
3424 | tmp = &DIRECT_CONNECTION_ONLY; |
3425 | if (!c->argumentTypes.testAndSetOrdered(0, tmp)) { |
3426 | if (tmp != &DIRECT_CONNECTION_ONLY) |
3427 | delete [] tmp; |
3428 | } |
3429 | } |
3430 | if (c->argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate |
3431 | return; |
3432 | int nargs = 1; // include return type |
3433 | while (c->argumentTypes[nargs-1]) |
3434 | ++nargs; |
3435 | int *types = (int *) qMalloc(nargs*sizeof(int)); |
3436 | Q_CHECK_PTR(types); |
3437 | void **args = (void **) qMalloc(nargs*sizeof(void *)); |
3438 | Q_CHECK_PTR(args); |
3439 | types[0] = 0; // return type |
3440 | args[0] = 0; // return value |
3441 | for (int n = 1; n < nargs; ++n) |
3442 | args[n] = QMetaType::construct((types[n] = c->argumentTypes[n-1]), argv[n]); |
3443 | QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method_offset, |
3444 | c->method_relative, |
3445 | c->callFunction, |
3446 | sender, signal, nargs, |
3447 | types, args)); |
3448 | } |
3449 | |
3450 | |
3451 | /*!\internal |
3452 | \obsolete. |
3453 | Used to be called from QMetaObject::activate(QObject *, QMetaObject *, int, int, void **) before Qt 4.6 |
3454 | */ |
3455 | void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) |
3456 | { |
3457 | Q_UNUSED(to_signal_index); |
3458 | activate(sender, from_signal_index, argv); |
3459 | } |
3460 | |
3461 | /*!\internal |
3462 | */ |
3463 | void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, |
3464 | void **argv) |
3465 | { |
3466 | int signalOffset; |
3467 | int methodOffset; |
3468 | computeOffsets(m, &signalOffset, &methodOffset); |
3469 | |
3470 | int signal_index = signalOffset + local_signal_index; |
3471 | |
3472 | if (!sender->d_func()->isSignalConnected(signal_index)) |
3473 | return; // nothing connected to these signals, and no spy |
3474 | |
3475 | if (sender->d_func()->blockSig) |
3476 | return; |
3477 | |
3478 | int signal_absolute_index = methodOffset + local_signal_index; |
3479 | |
3480 | void *empty_argv[] = { 0 }; |
3481 | if (qt_signal_spy_callback_set.signal_begin_callback != 0) { |
3482 | qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index, |
3483 | argv ? argv : empty_argv); |
3484 | } |
3485 | |
3486 | Qt::HANDLE currentThreadId = QThread::currentThreadId(); |
3487 | |
3488 | QMutexLocker locker(signalSlotLock(sender)); |
3489 | QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; |
3490 | if (!connectionLists) { |
3491 | locker.unlock(); |
3492 | if (qt_signal_spy_callback_set.signal_end_callback != 0) |
3493 | qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); |
3494 | return; |
3495 | } |
3496 | ++connectionLists->inUse; |
3497 | |
3498 | |
3499 | const QObjectPrivate::ConnectionList *list; |
3500 | if (signal_index < connectionLists->count()) |
3501 | list = &connectionLists->at(signal_index); |
3502 | else |
3503 | list = &connectionLists->allsignals; |
3504 | |
3505 | do { |
3506 | QObjectPrivate::Connection *c = list->first; |
3507 | if (!c) continue; |
3508 | // We need to check against last here to ensure that signals added |
3509 | // during the signal emission are not emitted in this emission. |
3510 | QObjectPrivate::Connection *last = list->last; |
3511 | |
3512 | do { |
3513 | if (!c->receiver) |
3514 | continue; |
3515 | |
3516 | QObject * const receiver = c->receiver; |
3517 | const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId; |
3518 | |
3519 | // determine if this connection should be sent immediately or |
3520 | // put into the event queue |
3521 | if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) |
3522 | || (c->connectionType == Qt::QueuedConnection)) { |
3523 | queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv); |
3524 | continue; |
3525 | #ifndef QT_NO_THREAD |
3526 | } else if (c->connectionType == Qt::BlockingQueuedConnection) { |
3527 | locker.unlock(); |
3528 | if (receiverInSameThread) { |
3529 | qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " |
3530 | "Sender is %s(%p), receiver is %s(%p)" , |
3531 | sender->metaObject()->className(), sender, |
3532 | receiver->metaObject()->className(), receiver); |
3533 | } |
3534 | QSemaphore semaphore; |
3535 | QCoreApplication::postEvent(receiver, new QMetaCallEvent(c->method_offset, c->method_relative, |
3536 | c->callFunction, |
3537 | sender, signal_absolute_index, |
3538 | 0, 0, |
3539 | argv ? argv : empty_argv, |
3540 | &semaphore)); |
3541 | semaphore.acquire(); |
3542 | locker.relock(); |
3543 | continue; |
3544 | #endif |
3545 | } |
3546 | |
3547 | QObjectPrivate::Sender currentSender; |
3548 | QObjectPrivate::Sender *previousSender = 0; |
3549 | if (receiverInSameThread) { |
3550 | currentSender.sender = sender; |
3551 | currentSender.signal = signal_absolute_index; |
3552 | currentSender.ref = 1; |
3553 | previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); |
3554 | } |
3555 | const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; |
3556 | const int method_relative = c->method_relative; |
3557 | if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { |
3558 | //we compare the vtable to make sure we are not in the destructor of the object. |
3559 | locker.unlock(); |
3560 | if (qt_signal_spy_callback_set.slot_begin_callback != 0) |
3561 | qt_signal_spy_callback_set.slot_begin_callback(receiver, c->method(), argv ? argv : empty_argv); |
3562 | |
3563 | #if defined(QT_NO_EXCEPTIONS) |
3564 | callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); |
3565 | #else |
3566 | QT_TRY { |
3567 | callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); |
3568 | } QT_CATCH(...) { |
3569 | locker.relock(); |
3570 | if (receiverInSameThread) |
3571 | QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); |
3572 | |
3573 | --connectionLists->inUse; |
3574 | Q_ASSERT(connectionLists->inUse >= 0); |
3575 | if (connectionLists->orphaned && !connectionLists->inUse) |
3576 | delete connectionLists; |
3577 | QT_RETHROW; |
3578 | } |
3579 | #endif |
3580 | if (qt_signal_spy_callback_set.slot_end_callback != 0) |
3581 | qt_signal_spy_callback_set.slot_end_callback(receiver, c->method()); |
3582 | locker.relock(); |
3583 | } else { |
3584 | const int method = method_relative + c->method_offset; |
3585 | locker.unlock(); |
3586 | |
3587 | if (qt_signal_spy_callback_set.slot_begin_callback != 0) { |
3588 | qt_signal_spy_callback_set.slot_begin_callback(receiver, |
3589 | method, |
3590 | argv ? argv : empty_argv); |
3591 | } |
3592 | |
3593 | #if defined(QT_NO_EXCEPTIONS) |
3594 | metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); |
3595 | #else |
3596 | QT_TRY { |
3597 | metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); |
3598 | } QT_CATCH(...) { |
3599 | locker.relock(); |
3600 | if (receiverInSameThread) |
3601 | QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); |
3602 | |
3603 | --connectionLists->inUse; |
3604 | Q_ASSERT(connectionLists->inUse >= 0); |
3605 | if (connectionLists->orphaned && !connectionLists->inUse) |
3606 | delete connectionLists; |
3607 | QT_RETHROW; |
3608 | } |
3609 | #endif |
3610 | |
3611 | if (qt_signal_spy_callback_set.slot_end_callback != 0) |
3612 | qt_signal_spy_callback_set.slot_end_callback(receiver, method); |
3613 | |
3614 | locker.relock(); |
3615 | } |
3616 | |
3617 | if (receiverInSameThread) |
3618 | QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); |
3619 | |
3620 | if (connectionLists->orphaned) |
3621 | break; |
3622 | } while (c != last && (c = c->nextConnectionList) != 0); |
3623 | |
3624 | if (connectionLists->orphaned) |
3625 | break; |
3626 | } while (list != &connectionLists->allsignals && |
3627 | //start over for all signals; |
3628 | ((list = &connectionLists->allsignals), true)); |
3629 | |
3630 | --connectionLists->inUse; |
3631 | Q_ASSERT(connectionLists->inUse >= 0); |
3632 | if (connectionLists->orphaned) { |
3633 | if (!connectionLists->inUse) |
3634 | delete connectionLists; |
3635 | } else if (connectionLists->dirty) { |
3636 | sender->d_func()->cleanConnectionLists(); |
3637 | } |
3638 | |
3639 | locker.unlock(); |
3640 | |
3641 | if (qt_signal_spy_callback_set.signal_end_callback != 0) |
3642 | qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); |
3643 | |
3644 | } |
3645 | |
3646 | /*!\internal |
3647 | Obsolete. (signal_index comes from indexOfMethod()) |
3648 | */ |
3649 | void QMetaObject::activate(QObject *sender, int signal_index, void **argv) |
3650 | { |
3651 | const QMetaObject *mo = sender->metaObject(); |
3652 | while (mo->methodOffset() > signal_index) |
3653 | mo = mo->superClass(); |
3654 | activate(sender, mo, signal_index - mo->methodOffset(), argv); |
3655 | } |
3656 | |
3657 | /*!\internal |
3658 | Obsolete, called by moc generated code before Qt 4.6 for cloned signals |
3659 | But since Qt 4.6, all clones are connected to their original |
3660 | */ |
3661 | void QMetaObject::activate(QObject *sender, const QMetaObject *m, |
3662 | int from_local_signal_index, int to_local_signal_index, void **argv) |
3663 | { |
3664 | Q_UNUSED(to_local_signal_index); |
3665 | Q_ASSERT(from_local_signal_index == QMetaObjectPrivate::originalClone(m, to_local_signal_index)); |
3666 | activate(sender, m, from_local_signal_index, argv); |
3667 | } |
3668 | |
3669 | /*! \internal |
3670 | Returns the signal index used in the internal connectionLists vector. |
3671 | |
3672 | It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod |
3673 | while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots. |
3674 | */ |
3675 | int QObjectPrivate::signalIndex(const char *signalName) const |
3676 | { |
3677 | Q_Q(const QObject); |
3678 | const QMetaObject *base = q->metaObject(); |
3679 | int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false); |
3680 | if (relative_index < 0) |
3681 | relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true); |
3682 | if (relative_index < 0) |
3683 | return relative_index; |
3684 | relative_index = QMetaObjectPrivate::originalClone(base, relative_index); |
3685 | int signalOffset, methodOffset; |
3686 | computeOffsets(base, &signalOffset, &methodOffset); |
3687 | return relative_index + signalOffset; |
3688 | } |
3689 | |
3690 | /***************************************************************************** |
3691 | Properties |
3692 | *****************************************************************************/ |
3693 | |
3694 | #ifndef QT_NO_PROPERTIES |
3695 | |
3696 | /*! |
3697 | Sets the value of the object's \a name property to \a value. |
3698 | |
3699 | If the property is defined in the class using Q_PROPERTY then |
3700 | true is returned on success and false otherwise. If the property |
3701 | is not defined using Q_PROPERTY, and therefore not listed in the |
3702 | meta-object, it is added as a dynamic property and false is returned. |
3703 | |
3704 | Information about all available properties is provided through the |
3705 | metaObject() and dynamicPropertyNames(). |
3706 | |
3707 | Dynamic properties can be queried again using property() and can be |
3708 | removed by setting the property value to an invalid QVariant. |
3709 | Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent |
3710 | to be sent to the object. |
3711 | |
3712 | \bold{Note:} Dynamic properties starting with "_q_" are reserved for internal |
3713 | purposes. |
3714 | |
3715 | \sa property(), metaObject(), dynamicPropertyNames() |
3716 | */ |
3717 | bool QObject::setProperty(const char *name, const QVariant &value) |
3718 | { |
3719 | Q_D(QObject); |
3720 | const QMetaObject* meta = metaObject(); |
3721 | if (!name || !meta) |
3722 | return false; |
3723 | |
3724 | int id = meta->indexOfProperty(name); |
3725 | if (id < 0) { |
3726 | if (!d->extraData) |
3727 | d->extraData = new QObjectPrivate::ExtraData; |
3728 | |
3729 | const int idx = d->extraData->propertyNames.indexOf(name); |
3730 | |
3731 | if (!value.isValid()) { |
3732 | if (idx == -1) |
3733 | return false; |
3734 | d->extraData->propertyNames.removeAt(idx); |
3735 | d->extraData->propertyValues.removeAt(idx); |
3736 | } else { |
3737 | if (idx == -1) { |
3738 | d->extraData->propertyNames.append(name); |
3739 | d->extraData->propertyValues.append(value); |
3740 | } else { |
3741 | d->extraData->propertyValues[idx] = value; |
3742 | } |
3743 | } |
3744 | |
3745 | QDynamicPropertyChangeEvent ev(name); |
3746 | QCoreApplication::sendEvent(this, &ev); |
3747 | |
3748 | return false; |
3749 | } |
3750 | QMetaProperty p = meta->property(id); |
3751 | #ifndef QT_NO_DEBUG |
3752 | if (!p.isWritable()) |
3753 | qWarning("%s::setProperty: Property \"%s\" invalid," |
3754 | " read-only or does not exist" , metaObject()->className(), name); |
3755 | #endif |
3756 | return p.write(this, value); |
3757 | } |
3758 | |
3759 | /*! |
3760 | Returns the value of the object's \a name property. |
3761 | |
3762 | If no such property exists, the returned variant is invalid. |
3763 | |
3764 | Information about all available properties is provided through the |
3765 | metaObject() and dynamicPropertyNames(). |
3766 | |
3767 | \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames() |
3768 | */ |
3769 | QVariant QObject::property(const char *name) const |
3770 | { |
3771 | Q_D(const QObject); |
3772 | const QMetaObject* meta = metaObject(); |
3773 | if (!name || !meta) |
3774 | return QVariant(); |
3775 | |
3776 | int id = meta->indexOfProperty(name); |
3777 | if (id < 0) { |
3778 | if (!d->extraData) |
3779 | return QVariant(); |
3780 | const int i = d->extraData->propertyNames.indexOf(name); |
3781 | return d->extraData->propertyValues.value(i); |
3782 | } |
3783 | QMetaProperty p = meta->property(id); |
3784 | #ifndef QT_NO_DEBUG |
3785 | if (!p.isReadable()) |
3786 | qWarning("%s::property: Property \"%s\" invalid or does not exist" , |
3787 | metaObject()->className(), name); |
3788 | #endif |
3789 | return p.read(this); |
3790 | } |
3791 | |
3792 | /*! |
3793 | \since 4.2 |
3794 | |
3795 | Returns the names of all properties that were dynamically added to |
3796 | the object using setProperty(). |
3797 | */ |
3798 | QList<QByteArray> QObject::dynamicPropertyNames() const |
3799 | { |
3800 | Q_D(const QObject); |
3801 | if (d->extraData) |
3802 | return d->extraData->propertyNames; |
3803 | return QList<QByteArray>(); |
3804 | } |
3805 | |
3806 | #endif // QT_NO_PROPERTIES |
3807 | |
3808 | |
3809 | /***************************************************************************** |
3810 | QObject debugging output routines. |
3811 | *****************************************************************************/ |
3812 | |
3813 | static void dumpRecursive(int level, QObject *object) |
3814 | { |
3815 | #if defined(QT_DEBUG) |
3816 | if (object) { |
3817 | QByteArray buf; |
3818 | buf.fill(' ', level / 2 * 8); |
3819 | if (level % 2) |
3820 | buf += " " ; |
3821 | QString name = object->objectName(); |
3822 | QString flags = QLatin1String("" ); |
3823 | #if 0 |
3824 | if (qApp->focusWidget() == object) |
3825 | flags += 'F'; |
3826 | if (object->isWidgetType()) { |
3827 | QWidget * w = (QWidget *)object; |
3828 | if (w->isVisible()) { |
3829 | QString t("<%1,%2,%3,%4>" ); |
3830 | flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height()); |
3831 | } else { |
3832 | flags += 'I'; |
3833 | } |
3834 | } |
3835 | #endif |
3836 | qDebug("%s%s::%s %s" , (const char*)buf, object->metaObject()->className(), name.toLocal8Bit().data(), |
3837 | flags.toLatin1().data()); |
3838 | QObjectList children = object->children(); |
3839 | if (!children.isEmpty()) { |
3840 | for (int i = 0; i < children.size(); ++i) |
3841 | dumpRecursive(level+1, children.at(i)); |
3842 | } |
3843 | } |
3844 | #else |
3845 | Q_UNUSED(level) |
3846 | Q_UNUSED(object) |
3847 | #endif |
3848 | } |
3849 | |
3850 | /*! |
3851 | Dumps a tree of children to the debug output. |
3852 | |
3853 | This function is useful for debugging, but does nothing if the |
3854 | library has been compiled in release mode (i.e. without debugging |
3855 | information). |
3856 | |
3857 | \sa dumpObjectInfo() |
3858 | */ |
3859 | |
3860 | void QObject::dumpObjectTree() |
3861 | { |
3862 | dumpRecursive(0, this); |
3863 | } |
3864 | |
3865 | /*! |
3866 | Dumps information about signal connections, etc. for this object |
3867 | to the debug output. |
3868 | |
3869 | This function is useful for debugging, but does nothing if the |
3870 | library has been compiled in release mode (i.e. without debugging |
3871 | information). |
3872 | |
3873 | \sa dumpObjectTree() |
3874 | */ |
3875 | |
3876 | void QObject::dumpObjectInfo() |
3877 | { |
3878 | #if defined(QT_DEBUG) |
3879 | qDebug("OBJECT %s::%s" , metaObject()->className(), |
3880 | objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); |
3881 | |
3882 | Q_D(QObject); |
3883 | QMutexLocker locker(signalSlotLock(this)); |
3884 | |
3885 | // first, look for connections where this object is the sender |
3886 | qDebug(" SIGNALS OUT" ); |
3887 | |
3888 | if (d->connectionLists) { |
3889 | int offset = 0; |
3890 | int offsetToNextMetaObject = 0; |
3891 | for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) { |
3892 | if (signal_index >= offsetToNextMetaObject) { |
3893 | const QMetaObject *mo = metaObject(); |
3894 | int signalOffset, methodOffset; |
3895 | computeOffsets(mo, &signalOffset, &methodOffset); |
3896 | while (signalOffset > signal_index) { |
3897 | mo = mo->superClass(); |
3898 | offsetToNextMetaObject = signalOffset; |
3899 | computeOffsets(mo, &signalOffset, &methodOffset); |
3900 | } |
3901 | offset = methodOffset - signalOffset; |
3902 | } |
3903 | const QMetaMethod signal = metaObject()->method(signal_index + offset); |
3904 | qDebug(" signal: %s" , signal.signature()); |
3905 | |
3906 | // receivers |
3907 | const QObjectPrivate::Connection *c = |
3908 | d->connectionLists->at(signal_index).first; |
3909 | while (c) { |
3910 | if (!c->receiver) { |
3911 | qDebug(" <Disconnected receiver>" ); |
3912 | c = c->nextConnectionList; |
3913 | continue; |
3914 | } |
3915 | const QMetaObject *receiverMetaObject = c->receiver->metaObject(); |
3916 | const QMetaMethod method = receiverMetaObject->method(c->method()); |
3917 | qDebug(" --> %s::%s %s" , |
3918 | receiverMetaObject->className(), |
3919 | c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()), |
3920 | method.signature()); |
3921 | c = c->nextConnectionList; |
3922 | } |
3923 | } |
3924 | } else { |
3925 | qDebug( " <None>" ); |
3926 | } |
3927 | |
3928 | // now look for connections where this object is the receiver |
3929 | qDebug(" SIGNALS IN" ); |
3930 | |
3931 | if (d->senders) { |
3932 | for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { |
3933 | const QMetaMethod slot = metaObject()->method(s->method()); |
3934 | qDebug(" <-- %s::%s %s" , |
3935 | s->sender->metaObject()->className(), |
3936 | s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()), |
3937 | slot.signature()); |
3938 | } |
3939 | } else { |
3940 | qDebug(" <None>" ); |
3941 | } |
3942 | #endif |
3943 | } |
3944 | |
3945 | #ifndef QT_NO_USERDATA |
3946 | /*!\internal |
3947 | */ |
3948 | uint QObject::registerUserData() |
3949 | { |
3950 | static int user_data_registration = 0; |
3951 | return user_data_registration++; |
3952 | } |
3953 | |
3954 | /*!\internal |
3955 | */ |
3956 | QObjectUserData::~QObjectUserData() |
3957 | { |
3958 | } |
3959 | |
3960 | /*!\internal |
3961 | */ |
3962 | void QObject::setUserData(uint id, QObjectUserData* data) |
3963 | { |
3964 | Q_D(QObject); |
3965 | if (!d->extraData) |
3966 | d->extraData = new QObjectPrivate::ExtraData; |
3967 | |
3968 | if (d->extraData->userData.size() <= (int) id) |
3969 | d->extraData->userData.resize((int) id + 1); |
3970 | d->extraData->userData[id] = data; |
3971 | } |
3972 | |
3973 | /*!\internal |
3974 | */ |
3975 | QObjectUserData* QObject::userData(uint id) const |
3976 | { |
3977 | Q_D(const QObject); |
3978 | if (!d->extraData) |
3979 | return 0; |
3980 | if ((int)id < d->extraData->userData.size()) |
3981 | return d->extraData->userData.at(id); |
3982 | return 0; |
3983 | } |
3984 | |
3985 | #endif // QT_NO_USERDATA |
3986 | |
3987 | |
3988 | #ifndef QT_NO_DEBUG_STREAM |
3989 | QDebug operator<<(QDebug dbg, const QObject *o) { |
3990 | #ifndef Q_BROKEN_DEBUG_STREAM |
3991 | if (!o) |
3992 | return dbg << "QObject(0x0) " ; |
3993 | dbg.nospace() << o->metaObject()->className() << '(' << (void *)o; |
3994 | if (!o->objectName().isEmpty()) |
3995 | dbg << ", name = " << o->objectName(); |
3996 | dbg << ')'; |
3997 | return dbg.space(); |
3998 | #else |
3999 | qWarning("This compiler doesn't support streaming QObject to QDebug" ); |
4000 | return dbg; |
4001 | Q_UNUSED(o); |
4002 | #endif |
4003 | } |
4004 | #endif |
4005 | |
4006 | /*! |
4007 | \fn void QObject::insertChild(QObject *object) |
4008 | |
4009 | Use setParent() instead, i.e., call object->setParent(this). |
4010 | */ |
4011 | |
4012 | /*! |
4013 | \fn void QObject::removeChild(QObject *object) |
4014 | |
4015 | Use setParent() instead, i.e., call object->setParent(0). |
4016 | */ |
4017 | |
4018 | /*! |
4019 | \fn bool QObject::isA(const char *className) const |
4020 | |
4021 | Compare \a className with the object's metaObject()->className() instead. |
4022 | */ |
4023 | |
4024 | /*! |
4025 | \fn const char *QObject::className() const |
4026 | |
4027 | Use metaObject()->className() instead. |
4028 | */ |
4029 | |
4030 | /*! |
4031 | \fn const char *QObject::name() const |
4032 | |
4033 | Use objectName() instead. |
4034 | */ |
4035 | |
4036 | /*! |
4037 | \fn const char *QObject::name(const char *defaultName) const |
4038 | |
4039 | Use objectName() instead. |
4040 | */ |
4041 | |
4042 | /*! |
4043 | \fn void QObject::setName(const char *name) |
4044 | |
4045 | Use setObjectName() instead. |
4046 | */ |
4047 | |
4048 | /*! |
4049 | \fn bool QObject::checkConnectArgs(const char *signal, const |
4050 | QObject *object, const char *method) |
4051 | |
4052 | Use QMetaObject::checkConnectArgs() instead. |
4053 | */ |
4054 | |
4055 | /*! |
4056 | \fn QByteArray QObject::normalizeSignalSlot(const char *signalSlot) |
4057 | |
4058 | Use QMetaObject::normalizedSignature() instead. |
4059 | */ |
4060 | |
4061 | /*! |
4062 | \fn const char *QMetaObject::superClassName() const |
4063 | |
4064 | \internal |
4065 | */ |
4066 | |
4067 | /*! |
4068 | \macro Q_CLASSINFO(Name, Value) |
4069 | \relates QObject |
4070 | |
4071 | This macro associates extra information to the class, which is |
4072 | available using QObject::metaObject(). Except for the ActiveQt |
4073 | extension, Qt doesn't use this information. |
4074 | |
4075 | The extra information takes the form of a \a Name string and a \a |
4076 | Value literal string. |
4077 | |
4078 | Example: |
4079 | |
4080 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 35 |
4081 | |
4082 | \sa QMetaObject::classInfo() |
4083 | */ |
4084 | |
4085 | /*! |
4086 | \macro Q_INTERFACES(...) |
4087 | \relates QObject |
4088 | |
4089 | This macro tells Qt which interfaces the class implements. This |
4090 | is used when implementing plugins. |
4091 | |
4092 | Example: |
4093 | |
4094 | \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 1 |
4095 | \dots |
4096 | \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 3 |
4097 | |
4098 | See the \l{tools/plugandpaintplugins/basictools}{Plug & Paint |
4099 | Basic Tools} example for details. |
4100 | |
4101 | \sa Q_DECLARE_INTERFACE(), Q_EXPORT_PLUGIN2(), {How to Create Qt Plugins} |
4102 | */ |
4103 | |
4104 | /*! |
4105 | \macro Q_PROPERTY(...) |
4106 | \relates QObject |
4107 | |
4108 | This macro is used for declaring properties in classes that |
4109 | inherit QObject. Properties behave like class data members, but |
4110 | they have additional features accessible through the \l |
4111 | {Meta-Object System}. |
4112 | |
4113 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 36 |
4114 | |
4115 | The property name and type and the \c READ function are required. |
4116 | The type can be any type supported by QVariant, or it can be a |
4117 | user-defined type. The other items are optional, but a \c WRITE |
4118 | function is common. The attributes default to true except \c USER, |
4119 | which defaults to false. |
4120 | |
4121 | For example: |
4122 | |
4123 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 37 |
4124 | |
4125 | For more details about how to use this macro, and a more detailed |
4126 | example of its use, see the discussion on \l {Qt's Property System}. |
4127 | |
4128 | \sa {Qt's Property System} |
4129 | */ |
4130 | |
4131 | /*! |
4132 | \macro Q_ENUMS(...) |
4133 | \relates QObject |
4134 | |
4135 | This macro registers one or several enum types to the meta-object |
4136 | system. |
4137 | |
4138 | For example: |
4139 | |
4140 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 38 |
4141 | |
4142 | If you want to register an enum that is declared in another class, |
4143 | the enum must be fully qualified with the name of the class |
4144 | defining it. In addition, the class \e defining the enum has to |
4145 | inherit QObject as well as declare the enum using Q_ENUMS(). |
4146 | |
4147 | \sa {Qt's Property System} |
4148 | */ |
4149 | |
4150 | /*! |
4151 | \macro Q_FLAGS(...) |
4152 | \relates QObject |
4153 | |
4154 | This macro registers one or several \l{QFlags}{flags types} to the |
4155 | meta-object system. It is typically used in a class definition to declare |
4156 | that values of a given enum can be used as flags and combined using the |
4157 | bitwise OR operator. |
4158 | |
4159 | For example, in QLibrary, the \l{QLibrary::LoadHints}{LoadHints} flag is |
4160 | declared in the following way: |
4161 | |
4162 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 39a |
4163 | |
4164 | The declaration of the flags themselves is performed in the public section |
4165 | of the QLibrary class itself, using the \l Q_DECLARE_FLAGS() macro: |
4166 | |
4167 | \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 39b |
4168 | |
4169 | \note This macro takes care of registering individual flag values |
4170 | with the meta-object system, so it is unnecessary to use Q_ENUMS() |
4171 | in addition to this macro. |
4172 | |
4173 | \sa {Qt's Property System} |
4174 | */ |
4175 | |
4176 | /*! |
4177 | \macro Q_OBJECT |
4178 | \relates QObject |
4179 | |
4180 | The Q_OBJECT macro must appear in the private section of a class |
4181 | definition that declares its own signals and slots or that uses |
4182 | other services provided by Qt's meta-object system. |
4183 | |
4184 | For example: |
4185 | |
4186 | \snippet doc/src/snippets/signalsandslots/signalsandslots.h 1 |
4187 | \codeline |
4188 | \snippet doc/src/snippets/signalsandslots/signalsandslots.h 2 |
4189 | \snippet doc/src/snippets/signalsandslots/signalsandslots.h 3 |
4190 | |
4191 | \note This macro requires the class to be a subclass of QObject. Use |
4192 | Q_GADGET instead of Q_OBJECT to enable the meta object system's support |
4193 | for enums in a class that is not a QObject subclass. Q_GADGET makes a |
4194 | class member, \c{staticMetaObject}, available. |
4195 | \c{staticMetaObject} is of type QMetaObject and provides access to the |
4196 | enums declared with Q_ENUMS. |
4197 | Q_GADGET is provided only for C++. |
4198 | |
4199 | \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System} |
4200 | */ |
4201 | |
4202 | /*! |
4203 | \macro Q_SIGNALS |
4204 | \relates QObject |
4205 | |
4206 | Use this macro to replace the \c signals keyword in class |
4207 | declarations, when you want to use Qt Signals and Slots with a |
4208 | \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. |
4209 | |
4210 | The macro is normally used when \c no_keywords is specified with |
4211 | the \c CONFIG variable in the \c .pro file, but it can be used |
4212 | even when \c no_keywords is \e not specified. |
4213 | */ |
4214 | |
4215 | /*! |
4216 | \macro Q_SIGNAL |
4217 | \relates QObject |
4218 | |
4219 | This is an additional macro that allows you to mark a single |
4220 | function as a signal. It can be quite useful, especially when you |
4221 | use a 3rd-party source code parser which doesn't understand a \c |
4222 | signals or \c Q_SIGNALS groups. |
4223 | |
4224 | Use this macro to replace the \c signals keyword in class |
4225 | declarations, when you want to use Qt Signals and Slots with a |
4226 | \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. |
4227 | |
4228 | The macro is normally used when \c no_keywords is specified with |
4229 | the \c CONFIG variable in the \c .pro file, but it can be used |
4230 | even when \c no_keywords is \e not specified. |
4231 | */ |
4232 | |
4233 | /*! |
4234 | \macro Q_SLOTS |
4235 | \relates QObject |
4236 | |
4237 | Use this macro to replace the \c slots keyword in class |
4238 | declarations, when you want to use Qt Signals and Slots with a |
4239 | \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. |
4240 | |
4241 | The macro is normally used when \c no_keywords is specified with |
4242 | the \c CONFIG variable in the \c .pro file, but it can be used |
4243 | even when \c no_keywords is \e not specified. |
4244 | */ |
4245 | |
4246 | /*! |
4247 | \macro Q_SLOT |
4248 | \relates QObject |
4249 | |
4250 | This is an additional macro that allows you to mark a single |
4251 | function as a slot. It can be quite useful, especially when you |
4252 | use a 3rd-party source code parser which doesn't understand a \c |
4253 | slots or \c Q_SLOTS groups. |
4254 | |
4255 | Use this macro to replace the \c slots keyword in class |
4256 | declarations, when you want to use Qt Signals and Slots with a |
4257 | \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. |
4258 | |
4259 | The macro is normally used when \c no_keywords is specified with |
4260 | the \c CONFIG variable in the \c .pro file, but it can be used |
4261 | even when \c no_keywords is \e not specified. |
4262 | */ |
4263 | |
4264 | /*! |
4265 | \macro Q_EMIT |
4266 | \relates QObject |
4267 | |
4268 | Use this macro to replace the \c emit keyword for emitting |
4269 | signals, when you want to use Qt Signals and Slots with a |
4270 | \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}. |
4271 | |
4272 | The macro is normally used when \c no_keywords is specified with |
4273 | the \c CONFIG variable in the \c .pro file, but it can be used |
4274 | even when \c no_keywords is \e not specified. |
4275 | */ |
4276 | |
4277 | /*! |
4278 | \macro Q_INVOKABLE |
4279 | \relates QObject |
4280 | |
4281 | Apply this macro to definitions of member functions to allow them to |
4282 | be invoked via the meta-object system. The macro is written before |
4283 | the return type, as shown in the following example: |
4284 | |
4285 | \snippet snippets/qmetaobject-invokable/window.h Window class with invokable method |
4286 | |
4287 | The \c invokableMethod() function is marked up using Q_INVOKABLE, causing |
4288 | it to be registered with the meta-object system and enabling it to be |
4289 | invoked using QMetaObject::invokeMethod(). |
4290 | Since \c normalMethod() function is not registered in this way, it cannot |
4291 | be invoked using QMetaObject::invokeMethod(). |
4292 | */ |
4293 | |
4294 | /*! |
4295 | \typedef QObjectList |
4296 | \relates QObject |
4297 | |
4298 | Synonym for QList<QObject *>. |
4299 | */ |
4300 | |
4301 | void qDeleteInEventHandler(QObject *o) |
4302 | { |
4303 | #ifdef QT_JAMBI_BUILD |
4304 | if (!o) |
4305 | return; |
4306 | QObjectPrivate::get(o)->inEventHandler = false; |
4307 | #endif |
4308 | delete o; |
4309 | } |
4310 | |
4311 | |
4312 | QT_END_NAMESPACE |
4313 | |
4314 | #include "moc_qobject.cpp" |
4315 | |