1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QOBJECT_H
6#define QOBJECT_H
7
8#ifndef QT_NO_QOBJECT
9
10#include <QtCore/qobjectdefs.h>
11#include <QtCore/qstring.h>
12#include <QtCore/qbytearray.h>
13#include <QtCore/qlist.h>
14#ifdef QT_INCLUDE_COMPAT
15#include <QtCore/qcoreevent.h>
16#endif
17#include <QtCore/qscopedpointer.h>
18#include <QtCore/qmetatype.h>
19
20#include <QtCore/qobject_impl.h>
21#include <QtCore/qbindingstorage.h>
22
23#include <chrono>
24
25QT_BEGIN_NAMESPACE
26
27
28template <typename T> class QBindable;
29class QEvent;
30class QTimerEvent;
31class QChildEvent;
32struct QMetaObject;
33class QVariant;
34class QObjectPrivate;
35class QObject;
36class QThread;
37class QWidget;
38class QAccessibleWidget;
39#if QT_CONFIG(regularexpression)
40class QRegularExpression;
41#endif
42struct QDynamicMetaObjectData;
43
44typedef QList<QObject*> QObjectList;
45
46#if QT_CORE_REMOVED_SINCE(6, 7)
47Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
48 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
49#endif
50Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
51 const QMetaObject &mo, QList<void *> *list,
52 Qt::FindChildOptions options);
53#if QT_CORE_REMOVED_SINCE(6, 7)
54Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
55 QList<void *> *list, Qt::FindChildOptions options);
56#endif
57Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
58 const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
59#if QT_CORE_REMOVED_SINCE(6, 7)
60Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
61#endif
62Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name,
63 const QMetaObject &mo, Qt::FindChildOptions options);
64
65class Q_CORE_EXPORT QObjectData
66{
67 Q_DISABLE_COPY(QObjectData)
68public:
69 QObjectData() = default;
70 virtual ~QObjectData() = 0;
71 QObject *q_ptr;
72 QObject *parent;
73 QObjectList children;
74
75 uint isWidget : 1;
76 uint blockSig : 1;
77 uint wasDeleted : 1;
78 uint isDeletingChildren : 1;
79 uint sendChildEvents : 1;
80 uint receiveChildEvents : 1;
81 uint isWindow : 1; // for QWindow
82 uint deleteLaterCalled : 1;
83 uint isQuickItem : 1;
84 uint willBeWidget : 1; // for handling widget-specific bits in QObject's ctor
85 uint wasWidget : 1; // for properly cleaning up in QObject's dtor
86 uint receiveParentEvents: 1;
87 uint unused : 20;
88 QAtomicInt postedEvents;
89 QDynamicMetaObjectData *metaObject;
90 QBindingStorage bindingStorage;
91
92 // ### Qt7: Make this return a const QMetaObject *. You should not mess with
93 // the metaobjects of existing objects.
94 QMetaObject *dynamicMetaObject() const;
95
96#ifdef QT_DEBUG
97 enum { CheckForParentChildLoopsWarnDepth = 4096 };
98#endif
99};
100
101class Q_CORE_EXPORT QObject
102{
103 Q_OBJECT
104
105 Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged
106 BINDABLE bindableObjectName)
107 Q_DECLARE_PRIVATE(QObject)
108
109public:
110 Q_INVOKABLE explicit QObject(QObject *parent = nullptr);
111 virtual ~QObject();
112
113 virtual bool event(QEvent *event);
114 virtual bool eventFilter(QObject *watched, QEvent *event);
115
116#if defined(QT_NO_TRANSLATION) || defined(Q_QDOC)
117 static QString tr(const char *sourceText, const char * = nullptr, int = -1)
118 { return QString::fromUtf8(sourceText); }
119#endif // QT_NO_TRANSLATION
120
121 QString objectName() const;
122#if QT_CORE_REMOVED_SINCE(6, 4)
123 void setObjectName(const QString &name);
124#endif
125 Q_WEAK_OVERLOAD
126 void setObjectName(const QString &name) { doSetObjectName(name); }
127 void setObjectName(QAnyStringView name);
128 QBindable<QString> bindableObjectName();
129
130 inline bool isWidgetType() const { return d_ptr->isWidget; }
131 inline bool isWindowType() const { return d_ptr->isWindow; }
132 inline bool isQuickItemType() const { return d_ptr->isQuickItem; }
133
134 inline bool signalsBlocked() const noexcept { return d_ptr->blockSig; }
135 bool blockSignals(bool b) noexcept;
136
137 QThread *thread() const;
138#if QT_CORE_REMOVED_SINCE(6, 7)
139 void moveToThread(QThread *thread);
140#endif
141 bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL);
142
143 int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
144 int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
145 void killTimer(int id);
146
147 template<typename T>
148 T findChild(QAnyStringView aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
149 {
150 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
151 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
152 "No Q_OBJECT in the class passed to QObject::findChild");
153 return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
154 }
155
156 template<typename T>
157 QList<T> findChildren(QAnyStringView aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
158 {
159 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
160 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
161 "No Q_OBJECT in the class passed to QObject::findChildren");
162 QList<T> list;
163 qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,
164 reinterpret_cast<QList<void *> *>(&list), options);
165 return list;
166 }
167
168 template<typename T>
169 T findChild(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
170 {
171 return findChild<T>({}, options);
172 }
173
174 template<typename T>
175 QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
176 {
177 return findChildren<T>(QAnyStringView{}, options);
178 }
179
180#if QT_CONFIG(regularexpression)
181 template<typename T>
182 inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
183 {
184 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
185 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
186 "No Q_OBJECT in the class passed to QObject::findChildren");
187 QList<T> list;
188 qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
189 reinterpret_cast<QList<void *> *>(&list), options);
190 return list;
191 }
192#endif // QT_CONFIG(regularexpression)
193
194 inline const QObjectList &children() const { return d_ptr->children; }
195
196 void setParent(QObject *parent);
197 void installEventFilter(QObject *filterObj);
198 void removeEventFilter(QObject *obj);
199
200 static QMetaObject::Connection connect(const QObject *sender, const char *signal,
201 const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
202
203 static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
204 const QObject *receiver, const QMetaMethod &method,
205 Qt::ConnectionType type = Qt::AutoConnection);
206
207 inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
208 const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
209
210#ifdef Q_QDOC
211 template<typename PointerToMemberFunction>
212 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
213 template<typename PointerToMemberFunction, typename Functor>
214 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
215 template<typename PointerToMemberFunction, typename Functor>
216 static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
217#else
218 //connect with context
219 template <typename Func1, typename Func2>
220 static inline QMetaObject::Connection
221 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
222 const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,
223 Qt::ConnectionType type = Qt::AutoConnection)
224 {
225 typedef QtPrivate::FunctionPointer<Func1> SignalType;
226 typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType;
227
228 if constexpr (SlotType::ArgumentCount != -1) {
229 static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
230 "Return type of the slot is not compatible with the return type of the signal.");
231 } else {
232 constexpr int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value;
233 [[maybe_unused]]
234 constexpr int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
235 typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
236
237 static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
238 "Return type of the slot is not compatible with the return type of the signal.");
239 }
240
241 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
242 "No Q_OBJECT in the class with the signal");
243
244 //compilation error if the arguments does not match.
245 static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
246 "The slot requires more arguments than the signal provides.");
247
248 const int *types = nullptr;
249 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
250 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
251
252 void **pSlot = nullptr;
253 if constexpr (std::is_member_function_pointer_v<std::decay_t<Func2>>) {
254 pSlot = const_cast<void **>(reinterpret_cast<void *const *>(&slot));
255 } else {
256 Q_ASSERT_X((type & Qt::UniqueConnection) == 0, "",
257 "QObject::connect: Unique connection requires the slot to be a pointer to "
258 "a member function of a QObject subclass.");
259 }
260
261 return connectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver: context, slotPtr: pSlot,
262 slot: QtPrivate::makeCallableObject<Func1>(std::forward<Func2>(slot)),
263 type, types, senderMetaObject: &SignalType::Object::staticMetaObject);
264 }
265
266#ifndef QT_NO_CONTEXTLESS_CONNECT
267 //connect without context
268 template <typename Func1, typename Func2>
269 static inline QMetaObject::Connection
270 connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
271 {
272 return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection);
273 }
274#endif // QT_NO_CONTEXTLESS_CONNECT
275#endif //Q_QDOC
276
277 static bool disconnect(const QObject *sender, const char *signal,
278 const QObject *receiver, const char *member);
279 static bool disconnect(const QObject *sender, const QMetaMethod &signal,
280 const QObject *receiver, const QMetaMethod &member);
281 inline bool disconnect(const char *signal = nullptr,
282 const QObject *receiver = nullptr, const char *member = nullptr) const
283 { return disconnect(sender: this, signal, receiver, member); }
284 inline bool disconnect(const QObject *receiver, const char *member = nullptr) const
285 { return disconnect(sender: this, signal: nullptr, receiver, member); }
286 static bool disconnect(const QMetaObject::Connection &);
287
288#ifdef Q_QDOC
289 template<typename PointerToMemberFunction>
290 static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method);
291#else
292 template <typename Func1, typename Func2>
293 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
294 const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
295 {
296 typedef QtPrivate::FunctionPointer<Func1> SignalType;
297 typedef QtPrivate::FunctionPointer<Func2> SlotType;
298
299 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
300 "No Q_OBJECT in the class with the signal");
301
302 //compilation error if the arguments does not match.
303 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
304 "Signal and slot arguments are not compatible.");
305
306 return disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver, slot: reinterpret_cast<void **>(&slot),
307 senderMetaObject: &SignalType::Object::staticMetaObject);
308 }
309 template <typename Func1>
310 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
311 const QObject *receiver, void **zero)
312 {
313 // This is the overload for when one wish to disconnect a signal from any slot. (slot=nullptr)
314 // Since the function template parameter cannot be deduced from '0', we use a
315 // dummy void ** parameter that must be equal to 0
316 Q_ASSERT(!zero);
317 typedef QtPrivate::FunctionPointer<Func1> SignalType;
318 return disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal), receiver, slot: zero,
319 senderMetaObject: &SignalType::Object::staticMetaObject);
320 }
321#endif //Q_QDOC
322
323 void dumpObjectTree() const;
324 void dumpObjectInfo() const;
325
326 QT_CORE_INLINE_SINCE(6, 6)
327 bool setProperty(const char *name, const QVariant &value);
328 inline bool setProperty(const char *name, QVariant &&value);
329 QVariant property(const char *name) const;
330 QList<QByteArray> dynamicPropertyNames() const;
331 QBindingStorage *bindingStorage() { return &d_ptr->bindingStorage; }
332 const QBindingStorage *bindingStorage() const { return &d_ptr->bindingStorage; }
333
334Q_SIGNALS:
335 void destroyed(QObject * = nullptr);
336 void objectNameChanged(const QString &objectName, QPrivateSignal);
337
338public:
339 inline QObject *parent() const { return d_ptr->parent; }
340
341 inline bool inherits(const char *classname) const
342 {
343 return const_cast<QObject *>(this)->qt_metacast(classname) != nullptr;
344 }
345
346public Q_SLOTS:
347 void deleteLater();
348
349protected:
350 QObject *sender() const;
351 int senderSignalIndex() const;
352 int receivers(const char *signal) const;
353 bool isSignalConnected(const QMetaMethod &signal) const;
354
355 virtual void timerEvent(QTimerEvent *event);
356 virtual void childEvent(QChildEvent *event);
357 virtual void customEvent(QEvent *event);
358
359 virtual void connectNotify(const QMetaMethod &signal);
360 virtual void disconnectNotify(const QMetaMethod &signal);
361
362protected:
363 QObject(QObjectPrivate &dd, QObject *parent = nullptr);
364
365protected:
366 QScopedPointer<QObjectData> d_ptr;
367
368 friend struct QMetaObject;
369 friend struct QMetaObjectPrivate;
370 friend class QMetaCallEvent;
371 friend class QApplication;
372 friend class QApplicationPrivate;
373 friend class QCoreApplication;
374 friend class QCoreApplicationPrivate;
375 friend class QWidget;
376 friend class QAccessibleWidget;
377 friend class QThreadData;
378
379private:
380 void doSetObjectName(const QString &name);
381 bool doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue);
382
383 Q_DISABLE_COPY(QObject)
384
385private:
386 static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
387 const QObject *receiver, void **slotPtr,
388 QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,
389 const int *types, const QMetaObject *senderMetaObject);
390
391 static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,
392 const QMetaObject *senderMetaObject);
393
394};
395
396inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
397 const char *amember, Qt::ConnectionType atype) const
398{ return connect(sender: asender, signal: asignal, receiver: this, member: amember, atype); }
399
400#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
401bool QObject::setProperty(const char *name, const QVariant &value)
402{
403 return doSetProperty(name, lvalue: &value, rvalue: nullptr);
404}
405#endif // inline since 6.6
406bool QObject::setProperty(const char *name, QVariant &&value)
407{
408 return doSetProperty(name, lvalue: &value, rvalue: &value);
409}
410
411template <class T>
412inline T qobject_cast(QObject *object)
413{
414 static_assert(std::is_pointer_v<T>,
415 "qobject_cast requires to cast towards a pointer type");
416 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
417 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
418 "qobject_cast requires the type to have a Q_OBJECT macro");
419 return static_cast<T>(ObjType::staticMetaObject.cast(object));
420}
421
422template <class T>
423inline T qobject_cast(const QObject *object)
424{
425 static_assert(std::is_pointer_v<T>,
426 "qobject_cast requires to cast towards a pointer type");
427 static_assert(std::is_const_v<std::remove_pointer_t<T>>,
428 "qobject_cast cannot cast away constness (use const_cast)");
429 typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
430 static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
431 "qobject_cast requires the type to have a Q_OBJECT macro");
432 return static_cast<T>(ObjType::staticMetaObject.cast(object));
433}
434
435
436template <class T> constexpr const char * qobject_interface_iid() = delete;
437template <class T> inline T *
438qobject_iid_cast(QObject *object, const char *IId = qobject_interface_iid<T *>())
439{
440 return reinterpret_cast<T *>((object ? object->qt_metacast(IId) : nullptr));
441}
442template <class T> inline std::enable_if_t<std::is_const<T>::value, T *>
443qobject_iid_cast(const QObject *object)
444{
445 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
446 QObject *o = const_cast<QObject *>(object);
447 return qobject_iid_cast<std::remove_cv_t<T>>(o);
448}
449
450#if defined(Q_QDOC)
451# define Q_DECLARE_INTERFACE(IFace, IId)
452#elif !defined(Q_MOC_RUN)
453# define Q_DECLARE_INTERFACE(IFace, IId) \
454 template <> constexpr const char *qobject_interface_iid<IFace *>() \
455 { return IId; } \
456 template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
457 { return qobject_iid_cast<IFace>(object); } \
458 template <> inline const IFace *qobject_cast<const IFace *>(const QObject *object) \
459 { return qobject_iid_cast<const IFace>(object); }
460#endif // Q_MOC_RUN
461
462inline const QBindingStorage *qGetBindingStorage(const QObject *o)
463{
464 return o->bindingStorage();
465}
466inline QBindingStorage *qGetBindingStorage(QObject *o)
467{
468 return o->bindingStorage();
469}
470
471#ifndef QT_NO_DEBUG_STREAM
472Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
473#endif
474
475class QSignalBlocker
476{
477public:
478 Q_NODISCARD_CTOR
479 inline explicit QSignalBlocker(QObject *o) noexcept;
480 Q_NODISCARD_CTOR
481 inline explicit QSignalBlocker(QObject &o) noexcept;
482 inline ~QSignalBlocker();
483
484 Q_NODISCARD_CTOR
485 inline QSignalBlocker(QSignalBlocker &&other) noexcept;
486 inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;
487
488 inline void reblock() noexcept;
489 inline void unblock() noexcept;
490 inline void dismiss() noexcept;
491
492private:
493 Q_DISABLE_COPY(QSignalBlocker)
494 QObject *m_o;
495 bool m_blocked;
496 bool m_inhibited;
497};
498
499QSignalBlocker::QSignalBlocker(QObject *o) noexcept
500 : m_o(o),
501 m_blocked(o && o->blockSignals(b: true)),
502 m_inhibited(false)
503{}
504
505QSignalBlocker::QSignalBlocker(QObject &o) noexcept
506 : m_o(&o),
507 m_blocked(o.blockSignals(b: true)),
508 m_inhibited(false)
509{}
510
511QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) noexcept
512 : m_o(other.m_o),
513 m_blocked(other.m_blocked),
514 m_inhibited(other.m_inhibited)
515{
516 other.m_o = nullptr;
517}
518
519QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) noexcept
520{
521 if (this != &other) {
522 // if both *this and other block the same object's signals:
523 // unblock *this iff our dtor would unblock, but other's wouldn't
524 if (m_o != other.m_o || (!m_inhibited && other.m_inhibited))
525 unblock();
526 m_o = other.m_o;
527 m_blocked = other.m_blocked;
528 m_inhibited = other.m_inhibited;
529 // disable other:
530 other.m_o = nullptr;
531 }
532 return *this;
533}
534
535QSignalBlocker::~QSignalBlocker()
536{
537 if (m_o && !m_inhibited)
538 m_o->blockSignals(b: m_blocked);
539}
540
541void QSignalBlocker::reblock() noexcept
542{
543 if (m_o)
544 m_o->blockSignals(b: true);
545 m_inhibited = false;
546}
547
548void QSignalBlocker::unblock() noexcept
549{
550 if (m_o)
551 m_o->blockSignals(b: m_blocked);
552 m_inhibited = true;
553}
554
555void QSignalBlocker::dismiss() noexcept
556{
557 m_o = nullptr;
558}
559
560namespace QtPrivate {
561 inline QObject & deref_for_methodcall(QObject &o) { return o; }
562 inline QObject & deref_for_methodcall(QObject *o) { return *o; }
563}
564#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1StringView(#obj))
565
566QT_END_NAMESPACE
567
568#endif
569
570#endif // QOBJECT_H
571