1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // Copyright (C) 2015 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 | #include "qmetaobject.h" |
6 | #include "qmetaobject_p.h" |
7 | #include "qmetatype.h" |
8 | #include "qmetatype_p.h" |
9 | #include "qobject.h" |
10 | #include "qobject_p.h" |
11 | |
12 | #include <qcoreapplication.h> |
13 | #include <qvariant.h> |
14 | |
15 | // qthread(_p).h uses QT_CONFIG(thread) internally and has a dummy |
16 | // interface for the non-thread support case |
17 | #include <qthread.h> |
18 | #include "private/qthread_p.h" |
19 | #if QT_CONFIG(thread) |
20 | #include <qsemaphore.h> |
21 | #endif |
22 | |
23 | // for normalizeTypeInternal |
24 | #include "private/qmetaobject_moc_p.h" |
25 | |
26 | #include <ctype.h> |
27 | #include <memory> |
28 | |
29 | QT_BEGIN_NAMESPACE |
30 | |
31 | using namespace Qt::StringLiterals; |
32 | |
33 | /*! |
34 | \class QMetaObject |
35 | \inmodule QtCore |
36 | |
37 | \brief The QMetaObject class contains meta-information about Qt |
38 | objects. |
39 | |
40 | \ingroup objectmodel |
41 | |
42 | The Qt \l{Meta-Object System} in Qt is responsible for the |
43 | signals and slots inter-object communication mechanism, runtime |
44 | type information, and the Qt property system. A single |
45 | QMetaObject instance is created for each QObject subclass that is |
46 | used in an application, and this instance stores all the |
47 | meta-information for the QObject subclass. This object is |
48 | available as QObject::metaObject(). |
49 | |
50 | This class is not normally required for application programming, |
51 | but it is useful if you write meta-applications, such as scripting |
52 | engines or GUI builders. |
53 | |
54 | The functions you are most likely to find useful are these: |
55 | \list |
56 | \li className() returns the name of a class. |
57 | \li superClass() returns the superclass's meta-object. |
58 | \li method() and methodCount() provide information |
59 | about a class's meta-methods (signals, slots and other |
60 | \l{Q_INVOKABLE}{invokable} member functions). |
61 | \li enumerator() and enumeratorCount() and provide information about |
62 | a class's enumerators. |
63 | \li propertyCount() and property() provide information about a |
64 | class's properties. |
65 | \li constructor() and constructorCount() provide information |
66 | about a class's meta-constructors. |
67 | \endlist |
68 | |
69 | The index functions indexOfConstructor(), indexOfMethod(), |
70 | indexOfEnumerator(), and indexOfProperty() map names of constructors, |
71 | member functions, enumerators, or properties to indexes in the |
72 | meta-object. For example, Qt uses indexOfMethod() internally when you |
73 | connect a signal to a slot. |
74 | |
75 | Classes can also have a list of \e{name}--\e{value} pairs of |
76 | additional class information, stored in QMetaClassInfo objects. |
77 | The number of pairs is returned by classInfoCount(), single pairs |
78 | are returned by classInfo(), and you can search for pairs with |
79 | indexOfClassInfo(). |
80 | |
81 | \note Operations that use the meta object system are generally thread- |
82 | safe, as QMetaObjects are typically static read-only instances |
83 | generated at compile time. However, if meta objects are dynamically |
84 | modified by the application (for instance, when using QQmlPropertyMap), |
85 | then the application has to explicitly synchronize access to the |
86 | respective meta object. |
87 | |
88 | \sa QMetaClassInfo, QMetaEnum, QMetaMethod, QMetaProperty, QMetaType, |
89 | {Meta-Object System} |
90 | */ |
91 | |
92 | /*! |
93 | \enum QMetaObject::Call |
94 | |
95 | \internal |
96 | |
97 | \value InvokeMetaMethod |
98 | \value ReadProperty |
99 | \value WriteProperty |
100 | \value ResetProperty |
101 | \value CreateInstance |
102 | \value IndexOfMethod |
103 | \value RegisterPropertyMetaType |
104 | \value RegisterMethodArgumentMetaType |
105 | \value BindableProperty |
106 | \value CustomCall |
107 | \value ConstructInPlace |
108 | */ |
109 | |
110 | /*! |
111 | \enum QMetaMethod::Access |
112 | |
113 | This enum describes the access level of a method, following the conventions used in C++. |
114 | |
115 | \value Private |
116 | \value Protected |
117 | \value Public |
118 | */ |
119 | |
120 | static inline const QMetaObjectPrivate *priv(const uint* data) |
121 | { return reinterpret_cast<const QMetaObjectPrivate*>(data); } |
122 | |
123 | static inline const char *rawStringData(const QMetaObject *mo, int index) |
124 | { |
125 | Q_ASSERT(priv(mo->d.data)->revision >= 7); |
126 | uint offset = mo->d.stringdata[2*index]; |
127 | return reinterpret_cast<const char *>(mo->d.stringdata) + offset; |
128 | } |
129 | |
130 | static inline QByteArrayView stringDataView(const QMetaObject *mo, int index) |
131 | { |
132 | Q_ASSERT(priv(mo->d.data)->revision >= 7); |
133 | uint offset = mo->d.stringdata[2*index]; |
134 | uint length = mo->d.stringdata[2*index + 1]; |
135 | const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset; |
136 | return {string, qsizetype(length)}; |
137 | } |
138 | |
139 | static inline QByteArray stringData(const QMetaObject *mo, int index) |
140 | { |
141 | const auto view = stringDataView(mo, index); |
142 | return QByteArray::fromRawData(data: view.data(), size: view.size()); |
143 | } |
144 | |
145 | static inline QByteArrayView typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo) |
146 | { |
147 | if (typeInfo & IsUnresolvedType) |
148 | return stringDataView(mo, index: typeInfo & TypeNameIndexMask); |
149 | else |
150 | return QByteArrayView(QMetaType(typeInfo).name()); |
151 | } |
152 | |
153 | static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo) |
154 | { |
155 | if (!(typeInfo & IsUnresolvedType)) |
156 | return typeInfo; |
157 | return QMetaType::fromName(name: rawStringData(mo, index: typeInfo & TypeNameIndexMask)).id(); |
158 | } |
159 | |
160 | static auto parse_scope(QByteArrayView qualifiedKey) noexcept |
161 | { |
162 | struct R { |
163 | std::optional<QByteArrayView> scope; |
164 | QByteArrayView key; |
165 | }; |
166 | if (qualifiedKey.startsWith(other: "QFlags<" ) && qualifiedKey.endsWith(c: '>')) |
167 | qualifiedKey.slice(pos: 7, n: qualifiedKey.length() - 8); |
168 | const auto scopePos = qualifiedKey.lastIndexOf(a: "::"_L1 ); |
169 | if (scopePos < 0) |
170 | return R{.scope: std::nullopt, .key: qualifiedKey}; |
171 | else |
172 | return R{.scope: qualifiedKey.first(n: scopePos), .key: qualifiedKey.sliced(pos: scopePos + 2)}; |
173 | } |
174 | |
175 | namespace { |
176 | class QMetaMethodPrivate : public QMetaMethodInvoker |
177 | { |
178 | public: |
179 | static const QMetaMethodPrivate *get(const QMetaMethod *q) |
180 | { return static_cast<const QMetaMethodPrivate *>(q); } |
181 | |
182 | inline QByteArray signature() const; |
183 | inline QByteArray name() const; |
184 | inline int typesDataIndex() const; |
185 | inline const char *rawReturnTypeName() const; |
186 | inline int returnType() const; |
187 | inline int parameterCount() const; |
188 | inline int parametersDataIndex() const; |
189 | inline uint parameterTypeInfo(int index) const; |
190 | inline int parameterType(int index) const; |
191 | inline void getParameterTypes(int *types) const; |
192 | inline const QtPrivate::QMetaTypeInterface *returnMetaTypeInterface() const; |
193 | inline const QtPrivate::QMetaTypeInterface *const *parameterMetaTypeInterfaces() const; |
194 | inline QByteArray parameterTypeName(int index) const; |
195 | inline QList<QByteArray> parameterTypes() const; |
196 | inline QList<QByteArray> parameterNames() const; |
197 | inline QByteArray tag() const; |
198 | inline int ownMethodIndex() const; |
199 | inline int ownConstructorMethodIndex() const; |
200 | |
201 | private: |
202 | void checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, int index) const; |
203 | QMetaMethodPrivate(); |
204 | }; |
205 | } // unnamed namespace |
206 | |
207 | enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value |
208 | |
209 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
210 | /*! |
211 | \since 4.5 |
212 | \obsolete [6.5] Please use the variadic overload of this function |
213 | |
214 | Constructs a new instance of this class. You can pass up to ten arguments |
215 | (\a val0, \a val1, \a val2, \a val3, \a val4, \a val5, \a val6, \a val7, |
216 | \a val8, and \a val9) to the constructor. Returns the new object, or |
217 | \nullptr if no suitable constructor is available. |
218 | |
219 | Note that only constructors that are declared with the Q_INVOKABLE |
220 | modifier are made available through the meta-object system. |
221 | |
222 | \sa Q_ARG(), constructor() |
223 | */ |
224 | QObject *QMetaObject::newInstance(QGenericArgument val0, |
225 | QGenericArgument val1, |
226 | QGenericArgument val2, |
227 | QGenericArgument val3, |
228 | QGenericArgument val4, |
229 | QGenericArgument val5, |
230 | QGenericArgument val6, |
231 | QGenericArgument val7, |
232 | QGenericArgument val8, |
233 | QGenericArgument val9) const |
234 | { |
235 | const char *typeNames[] = { |
236 | nullptr, |
237 | val0.name(), val1.name(), val2.name(), val3.name(), val4.name(), |
238 | val5.name(), val6.name(), val7.name(), val8.name(), val9.name() |
239 | }; |
240 | const void *parameters[] = { |
241 | nullptr, |
242 | val0.data(), val1.data(), val2.data(), val3.data(), val4.data(), |
243 | val5.data(), val6.data(), val7.data(), val8.data(), val9.data() |
244 | }; |
245 | |
246 | int paramCount; |
247 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
248 | int len = int(qstrlen(str: typeNames[paramCount])); |
249 | if (len <= 0) |
250 | break; |
251 | } |
252 | |
253 | return newInstanceImpl(mobj: this, parameterCount: paramCount, parameters, typeNames, metaTypes: nullptr); |
254 | } |
255 | #endif |
256 | |
257 | /*! |
258 | \fn template <typename... Args> QObject *QMetaObject::newInstance(Args &&... arguments) const |
259 | \since 6.5 |
260 | |
261 | Constructs a new instance of this class and returns the new object, or |
262 | \nullptr if no suitable constructor is available. The types of the |
263 | arguments \a arguments will be used to find a matching constructor, and then |
264 | forwarded to it the same way signal-slot connections do. |
265 | |
266 | Note that only constructors that are declared with the Q_INVOKABLE |
267 | modifier are made available through the meta-object system. |
268 | |
269 | \sa constructor() |
270 | */ |
271 | |
272 | QObject *QMetaObject::newInstanceImpl(const QMetaObject *mobj, qsizetype paramCount, |
273 | const void **parameters, const char **typeNames, |
274 | const QtPrivate::QMetaTypeInterface **metaTypes) |
275 | { |
276 | if (!mobj->inherits(metaObject: &QObject::staticMetaObject)) { |
277 | qWarning(msg: "QMetaObject::newInstance: type %s does not inherit QObject" , mobj->className()); |
278 | return nullptr; |
279 | } |
280 | |
281 | QT_WARNING_PUSH |
282 | #if Q_CC_GNU >= 1200 |
283 | QT_WARNING_DISABLE_GCC("-Wdangling-pointer" ) |
284 | #endif |
285 | |
286 | // set the return type |
287 | QObject *returnValue = nullptr; |
288 | QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>(); |
289 | parameters[0] = &returnValue; |
290 | typeNames[0] = returnValueMetaType.name(); |
291 | if (metaTypes) |
292 | metaTypes[0] = returnValueMetaType.iface(); |
293 | |
294 | QT_WARNING_POP |
295 | |
296 | // find the constructor |
297 | auto priv = QMetaObjectPrivate::get(metaobject: mobj); |
298 | for (int i = 0; i < priv->constructorCount; ++i) { |
299 | QMetaMethod m = QMetaMethod::fromRelativeConstructorIndex(mobj, index: i); |
300 | if (m.parameterCount() != (paramCount - 1)) |
301 | continue; |
302 | |
303 | // attempt to call |
304 | QMetaMethodPrivate::InvokeFailReason r = |
305 | QMetaMethodPrivate::invokeImpl(self: m, target: nullptr, Qt::DirectConnection, paramCount, |
306 | parameters, typeNames, metaTypes); |
307 | if (r == QMetaMethodPrivate::InvokeFailReason::None) |
308 | return returnValue; |
309 | if (int(r) < 0) |
310 | return nullptr; |
311 | } |
312 | |
313 | return returnValue; |
314 | } |
315 | |
316 | /*! |
317 | \internal |
318 | */ |
319 | int QMetaObject::static_metacall(Call cl, int idx, void **argv) const |
320 | { |
321 | Q_ASSERT(priv(d.data)->revision >= 6); |
322 | if (!d.static_metacall) |
323 | return 0; |
324 | d.static_metacall(nullptr, cl, idx, argv); |
325 | return -1; |
326 | } |
327 | |
328 | /*! |
329 | \internal |
330 | */ |
331 | int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv) |
332 | { |
333 | if (object->d_ptr->metaObject) |
334 | return object->d_ptr->metaObject->metaCall(object, cl, id: idx, argv); |
335 | else |
336 | return object->qt_metacall(cl, idx, argv); |
337 | } |
338 | |
339 | static inline QByteArrayView objectClassName(const QMetaObject *m) |
340 | { |
341 | return stringDataView(mo: m, index: priv(data: m->d.data)->className); |
342 | } |
343 | |
344 | /*! |
345 | Returns the class name. |
346 | |
347 | \sa superClass() |
348 | */ |
349 | const char *QMetaObject::className() const |
350 | { |
351 | return objectClassName(m: this).constData(); |
352 | } |
353 | |
354 | /*! |
355 | \fn QMetaObject *QMetaObject::superClass() const |
356 | |
357 | Returns the meta-object of the superclass, or \nullptr if there is |
358 | no such object. |
359 | |
360 | \sa className() |
361 | */ |
362 | |
363 | /*! |
364 | Returns \c true if the class described by this QMetaObject inherits |
365 | the type described by \a metaObject; otherwise returns false. |
366 | |
367 | A type is considered to inherit itself. |
368 | |
369 | \since 5.7 |
370 | */ |
371 | bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept |
372 | { |
373 | const QMetaObject *m = this; |
374 | do { |
375 | if (metaObject == m) |
376 | return true; |
377 | } while ((m = m->d.superdata)); |
378 | return false; |
379 | } |
380 | |
381 | /*! |
382 | \fn QObject *QMetaObject::cast(QObject *obj) const |
383 | \internal |
384 | |
385 | Returns \a obj if object \a obj inherits from this |
386 | meta-object; otherwise returns \nullptr. |
387 | */ |
388 | |
389 | /*! |
390 | \internal |
391 | |
392 | Returns \a obj if object \a obj inherits from this |
393 | meta-object; otherwise returns \nullptr. |
394 | */ |
395 | const QObject *QMetaObject::cast(const QObject *obj) const |
396 | { |
397 | return (obj && obj->metaObject()->inherits(metaObject: this)) ? obj : nullptr; |
398 | } |
399 | |
400 | #ifndef QT_NO_TRANSLATION |
401 | /*! |
402 | \internal |
403 | */ |
404 | QString QMetaObject::tr(const char *s, const char *c, int n) const |
405 | { |
406 | return QCoreApplication::translate(context: className(), key: s, disambiguation: c, n); |
407 | } |
408 | #endif // QT_NO_TRANSLATION |
409 | |
410 | /*! |
411 | \since 6.2 |
412 | Returns the metatype corresponding to this metaobject. |
413 | If the metaobject originates from a namespace, an invalid metatype is returned. |
414 | */ |
415 | QMetaType QMetaObject::metaType() const |
416 | { |
417 | |
418 | const QMetaObjectPrivate *d = priv(data: this->d.data); |
419 | if (d->revision < 10) { |
420 | // before revision 10, we did not store the metatype in the metatype array |
421 | return QMetaType::fromName(name: className()); |
422 | } else { |
423 | /* in the metatype array, we store |
424 | |
425 | | index | data | |
426 | |----------------------------------------------------------------------| |
427 | | 0 | QMetaType(property0) | |
428 | | ... | ... | |
429 | | propertyCount - 1 | QMetaType(propertyCount - 1) | |
430 | | propertyCount | QMetaType(enumerator0) | |
431 | | ... | ... | |
432 | | propertyCount + enumeratorCount - 1 | QMetaType(enumeratorCount - 1) | |
433 | | propertyCount + enumeratorCount | QMetaType(class) | |
434 | |
435 | */ |
436 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
437 | // Before revision 12 we only stored metatypes for enums if they showed |
438 | // up as types of properties or method arguments or return values. |
439 | // From revision 12 on, we always store them in a predictable place. |
440 | const qsizetype offset = d->revision < 12 |
441 | ? d->propertyCount |
442 | : d->propertyCount + d->enumeratorCount; |
443 | #else |
444 | const qsizetype offset = d->propertyCount + d->enumeratorCount; |
445 | #endif |
446 | |
447 | auto iface = this->d.metaTypes[offset]; |
448 | if (iface && QtMetaTypePrivate::isInterfaceFor<void>(iface)) |
449 | return QMetaType(); // return invalid meta-type for namespaces |
450 | if (iface) |
451 | return QMetaType(iface); |
452 | else // in case of a dynamic metaobject, we might have no metatype stored |
453 | return QMetaType::fromName(name: className()); // try lookup by name in that case |
454 | } |
455 | } |
456 | |
457 | /*! |
458 | Returns the method offset for this class; i.e. the index position |
459 | of this class's first member function. |
460 | |
461 | The offset is the sum of all the methods in the class's |
462 | superclasses (which is always positive since QObject has the |
463 | \l{QObject::}{deleteLater()} slot and a \l{QObject::}{destroyed()} signal). |
464 | |
465 | \sa method(), methodCount(), indexOfMethod() |
466 | */ |
467 | int QMetaObject::methodOffset() const |
468 | { |
469 | int offset = 0; |
470 | const QMetaObject *m = d.superdata; |
471 | while (m) { |
472 | offset += priv(data: m->d.data)->methodCount; |
473 | m = m->d.superdata; |
474 | } |
475 | return offset; |
476 | } |
477 | |
478 | |
479 | /*! |
480 | Returns the enumerator offset for this class; i.e. the index |
481 | position of this class's first enumerator. |
482 | |
483 | If the class has no superclasses with enumerators, the offset is |
484 | 0; otherwise the offset is the sum of all the enumerators in the |
485 | class's superclasses. |
486 | |
487 | \sa enumerator(), enumeratorCount(), indexOfEnumerator() |
488 | */ |
489 | int QMetaObject::enumeratorOffset() const |
490 | { |
491 | int offset = 0; |
492 | const QMetaObject *m = d.superdata; |
493 | while (m) { |
494 | offset += priv(data: m->d.data)->enumeratorCount; |
495 | m = m->d.superdata; |
496 | } |
497 | return offset; |
498 | } |
499 | |
500 | /*! |
501 | Returns the property offset for this class; i.e. the index |
502 | position of this class's first property. |
503 | |
504 | The offset is the sum of all the properties in the class's |
505 | superclasses (which is always positive since QObject has the |
506 | \l{QObject::}{objectName} property). |
507 | |
508 | \sa property(), propertyCount(), indexOfProperty() |
509 | */ |
510 | int QMetaObject::propertyOffset() const |
511 | { |
512 | int offset = 0; |
513 | const QMetaObject *m = d.superdata; |
514 | while (m) { |
515 | offset += priv(data: m->d.data)->propertyCount; |
516 | m = m->d.superdata; |
517 | } |
518 | return offset; |
519 | } |
520 | |
521 | /*! |
522 | Returns the class information offset for this class; i.e. the |
523 | index position of this class's first class information item. |
524 | |
525 | If the class has no superclasses with class information, the |
526 | offset is 0; otherwise the offset is the sum of all the class |
527 | information items in the class's superclasses. |
528 | |
529 | \sa classInfo(), classInfoCount(), indexOfClassInfo() |
530 | */ |
531 | int QMetaObject::classInfoOffset() const |
532 | { |
533 | int offset = 0; |
534 | const QMetaObject *m = d.superdata; |
535 | while (m) { |
536 | offset += priv(data: m->d.data)->classInfoCount; |
537 | m = m->d.superdata; |
538 | } |
539 | return offset; |
540 | } |
541 | |
542 | /*! |
543 | \since 4.5 |
544 | |
545 | Returns the number of constructors in this class. |
546 | |
547 | \sa constructor(), indexOfConstructor() |
548 | */ |
549 | int QMetaObject::constructorCount() const |
550 | { |
551 | Q_ASSERT(priv(d.data)->revision >= 2); |
552 | return priv(data: d.data)->constructorCount; |
553 | } |
554 | |
555 | /*! |
556 | Returns the number of methods in this class, including the number of |
557 | methods provided by each base class. These include signals and slots |
558 | as well as normal member functions. |
559 | |
560 | Use code like the following to obtain a QStringList containing the methods |
561 | specific to a given class: |
562 | |
563 | \snippet code/src_corelib_kernel_qmetaobject.cpp methodCount |
564 | |
565 | \sa method(), methodOffset(), indexOfMethod() |
566 | */ |
567 | int QMetaObject::methodCount() const |
568 | { |
569 | int n = priv(data: d.data)->methodCount; |
570 | const QMetaObject *m = d.superdata; |
571 | while (m) { |
572 | n += priv(data: m->d.data)->methodCount; |
573 | m = m->d.superdata; |
574 | } |
575 | return n; |
576 | } |
577 | |
578 | /*! |
579 | Returns the number of enumerators in this class. |
580 | |
581 | \sa enumerator(), enumeratorOffset(), indexOfEnumerator() |
582 | */ |
583 | int QMetaObject::enumeratorCount() const |
584 | { |
585 | int n = priv(data: d.data)->enumeratorCount; |
586 | const QMetaObject *m = d.superdata; |
587 | while (m) { |
588 | n += priv(data: m->d.data)->enumeratorCount; |
589 | m = m->d.superdata; |
590 | } |
591 | return n; |
592 | } |
593 | |
594 | /*! |
595 | Returns the number of properties in this class, including the number of |
596 | properties provided by each base class. |
597 | |
598 | Use code like the following to obtain a QStringList containing the properties |
599 | specific to a given class: |
600 | |
601 | \snippet code/src_corelib_kernel_qmetaobject.cpp propertyCount |
602 | |
603 | \sa property(), propertyOffset(), indexOfProperty() |
604 | */ |
605 | int QMetaObject::propertyCount() const |
606 | { |
607 | int n = priv(data: d.data)->propertyCount; |
608 | const QMetaObject *m = d.superdata; |
609 | while (m) { |
610 | n += priv(data: m->d.data)->propertyCount; |
611 | m = m->d.superdata; |
612 | } |
613 | return n; |
614 | } |
615 | |
616 | /*! |
617 | Returns the number of items of class information in this class. |
618 | |
619 | \sa classInfo(), classInfoOffset(), indexOfClassInfo() |
620 | */ |
621 | int QMetaObject::classInfoCount() const |
622 | { |
623 | int n = priv(data: d.data)->classInfoCount; |
624 | const QMetaObject *m = d.superdata; |
625 | while (m) { |
626 | n += priv(data: m->d.data)->classInfoCount; |
627 | m = m->d.superdata; |
628 | } |
629 | return n; |
630 | } |
631 | |
632 | // Returns \c true if the method defined by the given meta-object&meta-method |
633 | // matches the given name, argument count and argument types, otherwise |
634 | // returns \c false. |
635 | bool QMetaObjectPrivate::methodMatch(const QMetaObject *m, const QMetaMethod &method, |
636 | const QByteArray &name, int argc, |
637 | const QArgumentType *types) |
638 | { |
639 | const QMetaMethod::Data &data = method.data; |
640 | auto priv = QMetaMethodPrivate::get(q: &method); |
641 | if (priv->parameterCount() != argc) |
642 | return false; |
643 | |
644 | if (stringData(mo: m, index: data.name()) != name) |
645 | return false; |
646 | |
647 | const QtPrivate::QMetaTypeInterface * const *ifaces = priv->parameterMetaTypeInterfaces(); |
648 | int paramsIndex = data.parameters() + 1; |
649 | for (int i = 0; i < argc; ++i) { |
650 | uint typeInfo = m->d.data[paramsIndex + i]; |
651 | if (int id = types[i].type()) { |
652 | if (id == QMetaType(ifaces[i]).id()) |
653 | continue; |
654 | if (id != typeFromTypeInfo(mo: m, typeInfo)) |
655 | return false; |
656 | } else { |
657 | if (types[i].name() == QMetaType(ifaces[i]).name()) |
658 | continue; |
659 | if (types[i].name() != typeNameFromTypeInfo(mo: m, typeInfo)) |
660 | return false; |
661 | } |
662 | } |
663 | |
664 | return true; |
665 | } |
666 | |
667 | /*! |
668 | \internal |
669 | Returns the first method with name \a name found in \a baseObject |
670 | */ |
671 | QMetaMethod QMetaObjectPrivate::firstMethod(const QMetaObject *baseObject, QByteArrayView name) |
672 | { |
673 | for (const QMetaObject *currentObject = baseObject; currentObject; currentObject = currentObject->superClass()) { |
674 | const int start = priv(data: currentObject->d.data)->methodCount - 1; |
675 | const int end = 0; |
676 | for (int i = start; i >= end; --i) { |
677 | auto candidate = QMetaMethod::fromRelativeMethodIndex(mobj: currentObject, index: i); |
678 | if (name == candidate.name()) |
679 | return candidate; |
680 | } |
681 | } |
682 | return QMetaMethod{}; |
683 | } |
684 | |
685 | /** |
686 | * \internal |
687 | * helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within |
688 | * the baseObject |
689 | * \a MethodType might be MethodSignal or MethodSlot, or \nullptr to match everything. |
690 | */ |
691 | template<int MethodType> |
692 | inline int QMetaObjectPrivate::indexOfMethodRelative(const QMetaObject **baseObject, |
693 | const QByteArray &name, int argc, |
694 | const QArgumentType *types) |
695 | { |
696 | for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) { |
697 | Q_ASSERT(priv(m->d.data)->revision >= 7); |
698 | int i = (MethodType == MethodSignal) |
699 | ? (priv(data: m->d.data)->signalCount - 1) : (priv(data: m->d.data)->methodCount - 1); |
700 | const int end = (MethodType == MethodSlot) |
701 | ? (priv(data: m->d.data)->signalCount) : 0; |
702 | |
703 | for (; i >= end; --i) { |
704 | auto data = QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i); |
705 | if (methodMatch(m, method: data, name, argc, types)) { |
706 | *baseObject = m; |
707 | return i; |
708 | } |
709 | } |
710 | } |
711 | return -1; |
712 | } |
713 | |
714 | |
715 | /*! |
716 | \since 4.5 |
717 | |
718 | Finds \a constructor and returns its index; otherwise returns -1. |
719 | |
720 | Note that the \a constructor has to be in normalized form, as returned |
721 | by normalizedSignature(). |
722 | |
723 | \sa constructor(), constructorCount(), normalizedSignature() |
724 | */ |
725 | int QMetaObject::indexOfConstructor(const char *constructor) const |
726 | { |
727 | Q_ASSERT(priv(d.data)->revision >= 7); |
728 | QArgumentTypeArray types; |
729 | QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: constructor, types); |
730 | return QMetaObjectPrivate::indexOfConstructor(m: this, name, argc: types.size(), types: types.constData()); |
731 | } |
732 | |
733 | /*! |
734 | Finds \a method and returns its index; otherwise returns -1. |
735 | |
736 | Note that the \a method has to be in normalized form, as returned |
737 | by normalizedSignature(). |
738 | |
739 | \sa method(), methodCount(), methodOffset(), normalizedSignature() |
740 | */ |
741 | int QMetaObject::indexOfMethod(const char *method) const |
742 | { |
743 | const QMetaObject *m = this; |
744 | int i; |
745 | Q_ASSERT(priv(m->d.data)->revision >= 7); |
746 | QArgumentTypeArray types; |
747 | QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: method, types); |
748 | i = QMetaObjectPrivate::indexOfMethodRelative<0>(baseObject: &m, name, argc: types.size(), types: types.constData()); |
749 | if (i >= 0) |
750 | i += m->methodOffset(); |
751 | return i; |
752 | } |
753 | |
754 | // Parses a string of comma-separated types into QArgumentTypes. |
755 | // No normalization of the type names is performed. |
756 | static void argumentTypesFromString(const char *str, const char *end, |
757 | QArgumentTypeArray &types) |
758 | { |
759 | Q_ASSERT(str <= end); |
760 | while (str != end) { |
761 | if (!types.isEmpty()) |
762 | ++str; // Skip comma |
763 | const char *begin = str; |
764 | int level = 0; |
765 | while (str != end && (level > 0 || *str != ',')) { |
766 | if (*str == '<') |
767 | ++level; |
768 | else if (*str == '>') |
769 | --level; |
770 | ++str; |
771 | } |
772 | QByteArray argType(begin, str - begin); |
773 | argType.replace(before: "QVector<" , after: "QList<" ); |
774 | types += QArgumentType(std::move(argType)); |
775 | } |
776 | } |
777 | |
778 | // Given a method \a signature (e.g. "foo(int,double)"), this function |
779 | // populates the argument \a types array and returns the method name. |
780 | QByteArray QMetaObjectPrivate::decodeMethodSignature( |
781 | const char *signature, QArgumentTypeArray &types) |
782 | { |
783 | Q_ASSERT(signature != nullptr); |
784 | const char *lparens = strchr(s: signature, c: '('); |
785 | if (!lparens) |
786 | return QByteArray(); |
787 | const char *rparens = strrchr(s: lparens + 1, c: ')'); |
788 | if (!rparens || *(rparens+1)) |
789 | return QByteArray(); |
790 | int nameLength = lparens - signature; |
791 | argumentTypesFromString(str: lparens + 1, end: rparens, types); |
792 | return QByteArray::fromRawData(data: signature, size: nameLength); |
793 | } |
794 | |
795 | /*! |
796 | Finds \a signal and returns its index; otherwise returns -1. |
797 | |
798 | This is the same as indexOfMethod(), except that it will return |
799 | -1 if the method exists but isn't a signal. |
800 | |
801 | Note that the \a signal has to be in normalized form, as returned |
802 | by normalizedSignature(). |
803 | |
804 | \sa indexOfMethod(), normalizedSignature(), method(), methodCount(), methodOffset() |
805 | */ |
806 | int QMetaObject::indexOfSignal(const char *signal) const |
807 | { |
808 | const QMetaObject *m = this; |
809 | int i; |
810 | Q_ASSERT(priv(m->d.data)->revision >= 7); |
811 | QArgumentTypeArray types; |
812 | QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: signal, types); |
813 | i = QMetaObjectPrivate::indexOfSignalRelative(baseObject: &m, name, argc: types.size(), types: types.constData()); |
814 | if (i >= 0) |
815 | i += m->methodOffset(); |
816 | return i; |
817 | } |
818 | |
819 | /*! |
820 | \internal |
821 | Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object. |
822 | |
823 | \a baseObject will be adjusted to the enclosing QMetaObject, or \nullptr if the signal is not found |
824 | */ |
825 | int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject, |
826 | const QByteArray &name, int argc, |
827 | const QArgumentType *types) |
828 | { |
829 | int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types); |
830 | #ifndef QT_NO_DEBUG |
831 | const QMetaObject *m = *baseObject; |
832 | if (i >= 0 && m && m->d.superdata) { |
833 | int conflict = indexOfMethod(m: m->d.superdata, name, argc, types); |
834 | if (conflict >= 0) { |
835 | QMetaMethod conflictMethod = m->d.superdata->method(index: conflict); |
836 | qWarning(msg: "QMetaObject::indexOfSignal: signal %s from %s redefined in %s" , |
837 | conflictMethod.methodSignature().constData(), |
838 | m->d.superdata->className(), m->className()); |
839 | } |
840 | } |
841 | #endif |
842 | return i; |
843 | } |
844 | |
845 | /*! |
846 | Finds \a slot and returns its index; otherwise returns -1. |
847 | |
848 | This is the same as indexOfMethod(), except that it will return |
849 | -1 if the method exists but isn't a slot. |
850 | |
851 | \sa indexOfMethod(), method(), methodCount(), methodOffset() |
852 | */ |
853 | int QMetaObject::indexOfSlot(const char *slot) const |
854 | { |
855 | const QMetaObject *m = this; |
856 | int i; |
857 | Q_ASSERT(priv(m->d.data)->revision >= 7); |
858 | QArgumentTypeArray types; |
859 | QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: slot, types); |
860 | i = QMetaObjectPrivate::indexOfSlotRelative(m: &m, name, argc: types.size(), types: types.constData()); |
861 | if (i >= 0) |
862 | i += m->methodOffset(); |
863 | return i; |
864 | } |
865 | |
866 | // same as indexOfSignalRelative but for slots. |
867 | int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m, |
868 | const QByteArray &name, int argc, |
869 | const QArgumentType *types) |
870 | { |
871 | return indexOfMethodRelative<MethodSlot>(baseObject: m, name, argc, types); |
872 | } |
873 | |
874 | int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name, |
875 | int argc, const QArgumentType *types) |
876 | { |
877 | int i = indexOfSignalRelative(baseObject: &m, name, argc, types); |
878 | if (i >= 0) |
879 | i += m->methodOffset(); |
880 | return i; |
881 | } |
882 | |
883 | int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name, |
884 | int argc, const QArgumentType *types) |
885 | { |
886 | int i = indexOfSlotRelative(m: &m, name, argc, types); |
887 | if (i >= 0) |
888 | i += m->methodOffset(); |
889 | return i; |
890 | } |
891 | |
892 | int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name, |
893 | int argc, const QArgumentType *types) |
894 | { |
895 | int i = indexOfMethodRelative<0>(baseObject: &m, name, argc, types); |
896 | if (i >= 0) |
897 | i += m->methodOffset(); |
898 | return i; |
899 | } |
900 | |
901 | int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name, |
902 | int argc, const QArgumentType *types) |
903 | { |
904 | for (int i = priv(data: m->d.data)->constructorCount-1; i >= 0; --i) { |
905 | const QMetaMethod method = QMetaMethod::fromRelativeConstructorIndex(mobj: m, index: i); |
906 | if (methodMatch(m, method, name, argc, types)) |
907 | return i; |
908 | } |
909 | return -1; |
910 | } |
911 | |
912 | /*! |
913 | \fn int QMetaObjectPrivate::signalOffset(const QMetaObject *m) |
914 | \internal |
915 | \since 5.0 |
916 | |
917 | Returns the signal offset for the class \a m; i.e., the index position |
918 | of the class's first signal. |
919 | |
920 | Similar to QMetaObject::methodOffset(), but non-signal methods are |
921 | excluded. |
922 | */ |
923 | |
924 | /*! |
925 | \internal |
926 | \since 5.0 |
927 | |
928 | Returns the number of signals for the class \a m, including the signals |
929 | for the base class. |
930 | |
931 | Similar to QMetaObject::methodCount(), but non-signal methods are |
932 | excluded. |
933 | */ |
934 | int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m) |
935 | { |
936 | Q_ASSERT(m != nullptr); |
937 | int n = priv(data: m->d.data)->signalCount; |
938 | for (m = m->d.superdata; m; m = m->d.superdata) |
939 | n += priv(data: m->d.data)->signalCount; |
940 | return n; |
941 | } |
942 | |
943 | /*! |
944 | \internal |
945 | \since 5.0 |
946 | |
947 | Returns the index of the signal method \a m. |
948 | |
949 | Similar to QMetaMethod::methodIndex(), but non-signal methods are |
950 | excluded. |
951 | */ |
952 | int QMetaObjectPrivate::signalIndex(const QMetaMethod &m) |
953 | { |
954 | if (!m.mobj) |
955 | return -1; |
956 | return QMetaMethodPrivate::get(q: &m)->ownMethodIndex() + signalOffset(m: m.mobj); |
957 | } |
958 | |
959 | /*! |
960 | \internal |
961 | \since 5.0 |
962 | |
963 | Returns the signal for the given meta-object \a m at \a signal_index. |
964 | |
965 | It it different from QMetaObject::method(); the index should not include |
966 | non-signal methods. |
967 | */ |
968 | QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index) |
969 | { |
970 | if (signal_index < 0) |
971 | return QMetaMethod(); |
972 | |
973 | Q_ASSERT(m != nullptr); |
974 | int i = signal_index; |
975 | i -= signalOffset(m); |
976 | if (i < 0 && m->d.superdata) |
977 | return signal(m: m->d.superdata, signal_index); |
978 | |
979 | |
980 | if (i >= 0 && i < priv(data: m->d.data)->signalCount) |
981 | return QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i); |
982 | return QMetaMethod(); |
983 | } |
984 | |
985 | /*! |
986 | \internal |
987 | |
988 | Returns \c true if the \a signalTypes and \a methodTypes are |
989 | compatible; otherwise returns \c false. |
990 | */ |
991 | bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes, |
992 | int methodArgc, const QArgumentType *methodTypes) |
993 | { |
994 | if (signalArgc < methodArgc) |
995 | return false; |
996 | for (int i = 0; i < methodArgc; ++i) { |
997 | if (signalTypes[i] != methodTypes[i]) |
998 | return false; |
999 | } |
1000 | return true; |
1001 | } |
1002 | |
1003 | /*! |
1004 | \internal |
1005 | |
1006 | Returns \c true if the \a signal and \a method arguments are |
1007 | compatible; otherwise returns \c false. |
1008 | */ |
1009 | bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal, |
1010 | const QMetaMethodPrivate *method) |
1011 | { |
1012 | if (signal->methodType() != QMetaMethod::Signal) |
1013 | return false; |
1014 | if (signal->parameterCount() < method->parameterCount()) |
1015 | return false; |
1016 | const QMetaObject *smeta = signal->enclosingMetaObject(); |
1017 | const QMetaObject *rmeta = method->enclosingMetaObject(); |
1018 | for (int i = 0; i < method->parameterCount(); ++i) { |
1019 | uint sourceTypeInfo = signal->parameterTypeInfo(index: i); |
1020 | uint targetTypeInfo = method->parameterTypeInfo(index: i); |
1021 | if ((sourceTypeInfo & IsUnresolvedType) |
1022 | || (targetTypeInfo & IsUnresolvedType)) { |
1023 | QByteArrayView sourceName = typeNameFromTypeInfo(mo: smeta, typeInfo: sourceTypeInfo); |
1024 | QByteArrayView targetName = typeNameFromTypeInfo(mo: rmeta, typeInfo: targetTypeInfo); |
1025 | if (sourceName != targetName) |
1026 | return false; |
1027 | } else { |
1028 | int sourceType = typeFromTypeInfo(mo: smeta, typeInfo: sourceTypeInfo); |
1029 | int targetType = typeFromTypeInfo(mo: rmeta, typeInfo: targetTypeInfo); |
1030 | if (sourceType != targetType) |
1031 | return false; |
1032 | } |
1033 | } |
1034 | return true; |
1035 | } |
1036 | |
1037 | static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, QByteArrayView name) |
1038 | { |
1039 | while (self) { |
1040 | if (objectClassName(m: self) == name) |
1041 | return self; |
1042 | if (self->d.relatedMetaObjects) { |
1043 | Q_ASSERT(priv(self->d.data)->revision >= 2); |
1044 | const auto *e = self->d.relatedMetaObjects; |
1045 | if (e) { |
1046 | while (*e) { |
1047 | if (const QMetaObject *m =QMetaObject_findMetaObject(self: (*e), name)) |
1048 | return m; |
1049 | ++e; |
1050 | } |
1051 | } |
1052 | } |
1053 | self = self->d.superdata; |
1054 | } |
1055 | return self; |
1056 | } |
1057 | |
1058 | /*! |
1059 | Finds enumerator \a name and returns its index; otherwise returns |
1060 | -1. |
1061 | |
1062 | \sa enumerator(), enumeratorCount(), enumeratorOffset() |
1063 | */ |
1064 | int QMetaObject::indexOfEnumerator(const char *name) const |
1065 | { |
1066 | return QMetaObjectPrivate::indexOfEnumerator(m: this, name); |
1067 | } |
1068 | |
1069 | int QMetaObjectPrivate::indexOfEnumerator(const QMetaObject *m, QByteArrayView name) |
1070 | { |
1071 | using W = QMetaObjectPrivate::Which; |
1072 | for (auto which : { W::Name, W::Alias }) { |
1073 | if (int index = indexOfEnumerator(m, name, which); index != -1) |
1074 | return index; |
1075 | } |
1076 | return -1; |
1077 | } |
1078 | |
1079 | int QMetaObjectPrivate::indexOfEnumerator(const QMetaObject *m, QByteArrayView name, Which which) |
1080 | { |
1081 | while (m) { |
1082 | const QMetaObjectPrivate *d = priv(data: m->d.data); |
1083 | for (int i = 0; i < d->enumeratorCount; ++i) { |
1084 | const QMetaEnum e(m, i); |
1085 | const quint32 id = which == Which::Name ? e.data.name() : e.data.alias(); |
1086 | QByteArrayView prop = stringDataView(mo: m, index: id); |
1087 | if (name == prop) { |
1088 | i += m->enumeratorOffset(); |
1089 | return i; |
1090 | } |
1091 | } |
1092 | m = m->d.superdata; |
1093 | } |
1094 | return -1; |
1095 | } |
1096 | |
1097 | /*! |
1098 | Finds property \a name and returns its index; otherwise returns |
1099 | -1. |
1100 | |
1101 | \sa property(), propertyCount(), propertyOffset() |
1102 | */ |
1103 | int QMetaObject::indexOfProperty(const char *name) const |
1104 | { |
1105 | const QMetaObject *m = this; |
1106 | while (m) { |
1107 | const QMetaObjectPrivate *d = priv(data: m->d.data); |
1108 | for (int i = 0; i < d->propertyCount; ++i) { |
1109 | const QMetaProperty::Data data = QMetaProperty::getMetaPropertyData(mobj: m, index: i); |
1110 | const char *prop = rawStringData(mo: m, index: data.name()); |
1111 | if (strcmp(s1: name, s2: prop) == 0) { |
1112 | i += m->propertyOffset(); |
1113 | return i; |
1114 | } |
1115 | } |
1116 | m = m->d.superdata; |
1117 | } |
1118 | |
1119 | if (priv(data: this->d.data)->flags & DynamicMetaObject) { |
1120 | QAbstractDynamicMetaObject *me = |
1121 | const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(this)); |
1122 | |
1123 | return me->createProperty(name, nullptr); |
1124 | } |
1125 | |
1126 | return -1; |
1127 | } |
1128 | |
1129 | /*! |
1130 | Finds class information item \a name and returns its index; |
1131 | otherwise returns -1. |
1132 | |
1133 | \sa classInfo(), classInfoCount(), classInfoOffset() |
1134 | */ |
1135 | int QMetaObject::indexOfClassInfo(const char *name) const |
1136 | { |
1137 | int i = -1; |
1138 | const QMetaObject *m = this; |
1139 | while (m && i < 0) { |
1140 | for (i = priv(data: m->d.data)->classInfoCount-1; i >= 0; --i) |
1141 | if (strcmp(s1: name, s2: rawStringData(mo: m, index: m->d.data[priv(data: m->d.data)->classInfoData + 2*i])) == 0) { |
1142 | i += m->classInfoOffset(); |
1143 | break; |
1144 | } |
1145 | m = m->d.superdata; |
1146 | } |
1147 | return i; |
1148 | } |
1149 | |
1150 | /*! |
1151 | \since 4.5 |
1152 | |
1153 | Returns the meta-data for the constructor with the given \a index. |
1154 | |
1155 | \sa constructorCount(), newInstance() |
1156 | */ |
1157 | QMetaMethod QMetaObject::constructor(int index) const |
1158 | { |
1159 | int i = index; |
1160 | if (i >= 0 && i < priv(data: d.data)->constructorCount) |
1161 | return QMetaMethod::fromRelativeConstructorIndex(mobj: this, index: i); |
1162 | return QMetaMethod(); |
1163 | } |
1164 | |
1165 | /*! |
1166 | Returns the meta-data for the method with the given \a index. |
1167 | |
1168 | \sa methodCount(), methodOffset(), indexOfMethod() |
1169 | */ |
1170 | QMetaMethod QMetaObject::method(int index) const |
1171 | { |
1172 | int i = index; |
1173 | i -= methodOffset(); |
1174 | if (i < 0 && d.superdata) |
1175 | return d.superdata->method(index); |
1176 | |
1177 | if (i >= 0 && i < priv(data: d.data)->methodCount) |
1178 | return QMetaMethod::fromRelativeMethodIndex(mobj: this, index: i); |
1179 | return QMetaMethod(); |
1180 | } |
1181 | |
1182 | /*! |
1183 | Returns the meta-data for the enumerator with the given \a index. |
1184 | |
1185 | \sa enumeratorCount(), enumeratorOffset(), indexOfEnumerator() |
1186 | */ |
1187 | QMetaEnum QMetaObject::enumerator(int index) const |
1188 | { |
1189 | int i = index; |
1190 | i -= enumeratorOffset(); |
1191 | if (i < 0 && d.superdata) |
1192 | return d.superdata->enumerator(index); |
1193 | |
1194 | if (i >= 0 && i < priv(data: d.data)->enumeratorCount) |
1195 | return QMetaEnum(this, i); |
1196 | return QMetaEnum(); |
1197 | } |
1198 | |
1199 | /*! |
1200 | Returns the meta-data for the property with the given \a index. |
1201 | If no such property exists, a null QMetaProperty is returned. |
1202 | |
1203 | \sa propertyCount(), propertyOffset(), indexOfProperty() |
1204 | */ |
1205 | QMetaProperty QMetaObject::property(int index) const |
1206 | { |
1207 | int i = index; |
1208 | i -= propertyOffset(); |
1209 | if (i < 0 && d.superdata) |
1210 | return d.superdata->property(index); |
1211 | |
1212 | if (i >= 0 && i < priv(data: d.data)->propertyCount) |
1213 | return QMetaProperty(this, i); |
1214 | return QMetaProperty(); |
1215 | } |
1216 | |
1217 | /*! |
1218 | \since 4.2 |
1219 | |
1220 | Returns the property that has the \c USER flag set to true. |
1221 | |
1222 | \sa QMetaProperty::isUser() |
1223 | */ |
1224 | QMetaProperty QMetaObject::userProperty() const |
1225 | { |
1226 | const int propCount = propertyCount(); |
1227 | for (int i = propCount - 1; i >= 0; --i) { |
1228 | const QMetaProperty prop = property(index: i); |
1229 | if (prop.isUser()) |
1230 | return prop; |
1231 | } |
1232 | return QMetaProperty(); |
1233 | } |
1234 | |
1235 | /*! |
1236 | Returns the meta-data for the item of class information with the |
1237 | given \a index. |
1238 | |
1239 | Example: |
1240 | |
1241 | \snippet code/src_corelib_kernel_qmetaobject.cpp 0 |
1242 | |
1243 | \sa classInfoCount(), classInfoOffset(), indexOfClassInfo() |
1244 | */ |
1245 | QMetaClassInfo QMetaObject::classInfo(int index) const |
1246 | { |
1247 | int i = index; |
1248 | i -= classInfoOffset(); |
1249 | if (i < 0 && d.superdata) |
1250 | return d.superdata->classInfo(index); |
1251 | |
1252 | QMetaClassInfo result; |
1253 | if (i >= 0 && i < priv(data: d.data)->classInfoCount) { |
1254 | result.mobj = this; |
1255 | result.data = { .d: d.data + priv(data: d.data)->classInfoData + i * QMetaClassInfo::Data::Size }; |
1256 | } |
1257 | return result; |
1258 | } |
1259 | |
1260 | /*! |
1261 | Returns \c true if the \a signal and \a method arguments are |
1262 | compatible; otherwise returns \c false. |
1263 | |
1264 | Both \a signal and \a method are expected to be normalized. |
1265 | |
1266 | \sa normalizedSignature() |
1267 | */ |
1268 | bool QMetaObject::checkConnectArgs(const char *signal, const char *method) |
1269 | { |
1270 | const char *s1 = signal; |
1271 | const char *s2 = method; |
1272 | while (*s1++ != '(') { } // scan to first '(' |
1273 | while (*s2++ != '(') { } |
1274 | if (*s2 == ')' || qstrcmp(str1: s1,str2: s2) == 0) // method has no args or |
1275 | return true; // exact match |
1276 | const auto s1len = qstrlen(str: s1); |
1277 | const auto s2len = qstrlen(str: s2); |
1278 | if (s2len < s1len && strncmp(s1: s1,s2: s2,n: s2len-1)==0 && s1[s2len-1]==',') |
1279 | return true; // method has less args |
1280 | return false; |
1281 | } |
1282 | |
1283 | /*! |
1284 | \since 5.0 |
1285 | \overload |
1286 | |
1287 | Returns \c true if the \a signal and \a method arguments are |
1288 | compatible; otherwise returns \c false. |
1289 | */ |
1290 | bool QMetaObject::checkConnectArgs(const QMetaMethod &signal, |
1291 | const QMetaMethod &method) |
1292 | { |
1293 | return QMetaObjectPrivate::checkConnectArgs( |
1294 | signal: QMetaMethodPrivate::get(q: &signal), |
1295 | method: QMetaMethodPrivate::get(q: &method)); |
1296 | } |
1297 | |
1298 | static void qRemoveWhitespace(const char *s, char *d) |
1299 | { |
1300 | char last = 0; |
1301 | while (*s && is_space(s: *s)) |
1302 | s++; |
1303 | while (*s) { |
1304 | while (*s && !is_space(s: *s)) |
1305 | last = *d++ = *s++; |
1306 | while (*s && is_space(s: *s)) |
1307 | s++; |
1308 | if (*s && ((is_ident_char(s: *s) && is_ident_char(s: last)) |
1309 | || ((*s == ':') && (last == '<')))) { |
1310 | last = *d++ = ' '; |
1311 | } |
1312 | } |
1313 | *d = '\0'; |
1314 | } |
1315 | |
1316 | static char *qNormalizeType(char *d, int &templdepth, QByteArray &result) |
1317 | { |
1318 | const char *t = d; |
1319 | while (*d && (templdepth |
1320 | || (*d != ',' && *d != ')'))) { |
1321 | if (*d == '<') |
1322 | ++templdepth; |
1323 | if (*d == '>') |
1324 | --templdepth; |
1325 | ++d; |
1326 | } |
1327 | // "void" should only be removed if this is part of a signature that has |
1328 | // an explicit void argument; e.g., "void foo(void)" --> "void foo()" |
1329 | if (strncmp(s1: "void)" , s2: t, n: d - t + 1) != 0) |
1330 | result += normalizeTypeInternal(t, e: d); |
1331 | |
1332 | return d; |
1333 | } |
1334 | |
1335 | |
1336 | /*! |
1337 | \since 4.2 |
1338 | |
1339 | Normalizes a \a type. |
1340 | |
1341 | See QMetaObject::normalizedSignature() for a description on how |
1342 | Qt normalizes. |
1343 | |
1344 | Example: |
1345 | |
1346 | \snippet code/src_corelib_kernel_qmetaobject.cpp 1 |
1347 | |
1348 | \sa normalizedSignature() |
1349 | */ |
1350 | QByteArray QMetaObject::normalizedType(const char *type) |
1351 | { |
1352 | return normalizeTypeInternal(t: type, e: type + qstrlen(str: type)); |
1353 | } |
1354 | |
1355 | /*! |
1356 | Normalizes the signature of the given \a method. |
1357 | |
1358 | Qt uses normalized signatures to decide whether two given signals |
1359 | and slots are compatible. Normalization reduces whitespace to a |
1360 | minimum, moves 'const' to the front where appropriate, removes |
1361 | 'const' from value types and replaces const references with |
1362 | values. |
1363 | |
1364 | \sa checkConnectArgs(), normalizedType() |
1365 | */ |
1366 | QByteArray QMetaObject::normalizedSignature(const char *method) |
1367 | { |
1368 | QByteArray result; |
1369 | if (!method || !*method) |
1370 | return result; |
1371 | int len = int(strlen(s: method)); |
1372 | QVarLengthArray<char> stackbuf(len + 1); |
1373 | char *d = stackbuf.data(); |
1374 | qRemoveWhitespace(s: method, d); |
1375 | |
1376 | result.reserve(asize: len); |
1377 | |
1378 | int argdepth = 0; |
1379 | int templdepth = 0; |
1380 | while (*d) { |
1381 | if (argdepth == 1) { |
1382 | d = qNormalizeType(d, templdepth, result); |
1383 | if (!*d) //most likely an invalid signature. |
1384 | break; |
1385 | } |
1386 | if (*d == '(') |
1387 | ++argdepth; |
1388 | if (*d == ')') |
1389 | --argdepth; |
1390 | result += *d++; |
1391 | } |
1392 | |
1393 | return result; |
1394 | } |
1395 | |
1396 | Q_DECL_COLD_FUNCTION static inline bool |
1397 | printMethodNotFoundWarning(const QMetaObject *meta, QByteArrayView name, qsizetype paramCount, |
1398 | const char *const *names, |
1399 | const QtPrivate::QMetaTypeInterface * const *metaTypes) |
1400 | { |
1401 | // now find the candidates we couldn't use |
1402 | QByteArray candidateMessage; |
1403 | for (int i = 0; i < meta->methodCount(); ++i) { |
1404 | const QMetaMethod method = meta->method(index: i); |
1405 | if (method.name() == name) |
1406 | candidateMessage += " " + method.methodSignature() + '\n'; |
1407 | } |
1408 | if (!candidateMessage.isEmpty()) { |
1409 | candidateMessage.prepend(s: "\nCandidates are:\n" ); |
1410 | candidateMessage.chop(n: 1); |
1411 | } |
1412 | |
1413 | QVarLengthArray<char, 512> sig; |
1414 | for (qsizetype i = 1; i < paramCount; ++i) { |
1415 | if (names[i]) |
1416 | sig.append(buf: names[i], sz: qstrlen(str: names[i])); |
1417 | else |
1418 | sig.append(buf: metaTypes[i]->name, sz: qstrlen(str: metaTypes[i]->name)); |
1419 | sig.append(t: ','); |
1420 | } |
1421 | if (paramCount != 1) |
1422 | sig.resize(sz: sig.size() - 1); |
1423 | |
1424 | qWarning(msg: "QMetaObject::invokeMethod: No such method %s::%.*s(%.*s)%.*s" , |
1425 | meta->className(), int(name.size()), name.constData(), |
1426 | int(sig.size()), sig.constData(), |
1427 | int(candidateMessage.size()), candidateMessage.constData()); |
1428 | return false; |
1429 | } |
1430 | |
1431 | /*! |
1432 | \fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... args) |
1433 | \fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... args) |
1434 | \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, Args &&... args) |
1435 | \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Args &&... args) |
1436 | \since 6.5 |
1437 | \threadsafe |
1438 | |
1439 | Invokes the \a member (a signal or a slot name) on the object \a |
1440 | obj. Returns \c true if the member could be invoked. Returns \c false |
1441 | if there is no such member or the parameters did not match. |
1442 | |
1443 | For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the |
1444 | return value of the \a member function call is placed in \a ret. For the |
1445 | overloads without such a member, the return value of the called function |
1446 | (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an |
1447 | internal type you should not use directly. Instead, use the qReturnArg() |
1448 | function. |
1449 | |
1450 | The overloads with a Qt::ConnectionType \a type parameter allow explicitly |
1451 | selecting whether the invocation will be synchronous or not: |
1452 | |
1453 | \list |
1454 | \li If \a type is Qt::DirectConnection, the member will be invoked immediately |
1455 | in the current thread. |
1456 | |
1457 | \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the |
1458 | member is invoked as soon as the application enters the event loop in the |
1459 | thread that the \a obj was created in or was moved to. |
1460 | |
1461 | \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in |
1462 | the same way as for Qt::QueuedConnection, except that the current thread |
1463 | will block until the event is delivered. Using this connection type to |
1464 | communicate between objects in the same thread will lead to deadlocks. |
1465 | |
1466 | \li If \a type is Qt::AutoConnection, the member is invoked synchronously |
1467 | if \a obj lives in the same thread as the caller; otherwise it will invoke |
1468 | the member asynchronously. This is the behavior of the overloads that do |
1469 | not have the \a type parameter. |
1470 | \endlist |
1471 | |
1472 | You only need to pass the name of the signal or slot to this function, |
1473 | not the entire signature. For example, to asynchronously invoke |
1474 | the \l{QThread::quit()}{quit()} slot on a |
1475 | QThread, use the following code: |
1476 | |
1477 | \snippet code/src_corelib_kernel_qmetaobject.cpp 2 |
1478 | |
1479 | With asynchronous method invocations, the parameters must be copyable |
1480 | types, because Qt needs to copy the arguments to store them in an event |
1481 | behind the scenes. Since Qt 6.5, this function automatically registers the |
1482 | types being used; however, as a side-effect, it is not possible to make |
1483 | calls using types that are only forward-declared. Additionally, it is not |
1484 | possible to make asynchronous calls that use references to |
1485 | non-const-qualified types as parameters either. |
1486 | |
1487 | To synchronously invoke the \c compute(QString, int, double) slot on |
1488 | some arbitrary object \c obj retrieve its return value: |
1489 | |
1490 | \snippet code/src_corelib_kernel_qmetaobject.cpp invokemethod-no-macro |
1491 | |
1492 | If the "compute" slot does not take exactly one \l QString, one \c int, and |
1493 | one \c double in the specified order, the call will fail. Note how it was |
1494 | necessary to be explicit about the type of the QString, as the character |
1495 | literal is not exactly the right type to match. If the method instead took |
1496 | a \l QStringView, a \l qsizetype, and a \c float, the call would need to be |
1497 | written as: |
1498 | |
1499 | \snippet code/src_corelib_kernel_qmetaobject.cpp invokemethod-no-macro-other-types |
1500 | |
1501 | The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros, |
1502 | as in: |
1503 | |
1504 | \snippet code/src_corelib_kernel_qmetaobject.cpp 4 |
1505 | |
1506 | The macros are kept for compatibility with Qt 6.4 and earlier versions, and |
1507 | can be freely mixed with parameters that do not use the macro. They may be |
1508 | necessary in rare situations when calling a method that used a typedef to |
1509 | forward-declared type as a parameter or the return type. |
1510 | |
1511 | \sa Q_ARG(), Q_RETURN_ARG(), QMetaMethod::invoke() |
1512 | */ |
1513 | |
1514 | /*! |
1515 | \threadsafe |
1516 | \overload |
1517 | \obsolete [6.5] Please use the variadic overload of this function |
1518 | |
1519 | Invokes the \a member (a signal or a slot name) on the object \a |
1520 | obj. Returns \c true if the member could be invoked. Returns \c false |
1521 | if there is no such member or the parameters did not match. |
1522 | |
1523 | See the variadic invokeMethod() function for more information. This |
1524 | function should behave the same way as that one, with the following |
1525 | limitations: |
1526 | |
1527 | \list |
1528 | \li The number of parameters is limited to 10. |
1529 | \li Parameter names may need to be an exact string match. |
1530 | \li Meta types are not automatically registered. |
1531 | \endlist |
1532 | |
1533 | With asynchronous method invocations, the parameters must be of |
1534 | types that are already known to Qt's meta-object system, because Qt needs |
1535 | to copy the arguments to store them in an event behind the |
1536 | scenes. If you try to use a queued connection and get the error |
1537 | message |
1538 | |
1539 | \snippet code/src_corelib_kernel_qmetaobject.cpp 3 |
1540 | |
1541 | call qRegisterMetaType() to register the data type before you |
1542 | call invokeMethod(). |
1543 | |
1544 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaMethod::invoke() |
1545 | */ |
1546 | bool QMetaObject::invokeMethod(QObject *obj, |
1547 | const char *member, |
1548 | Qt::ConnectionType type, |
1549 | QGenericReturnArgument ret, |
1550 | QGenericArgument val0, |
1551 | QGenericArgument val1, |
1552 | QGenericArgument val2, |
1553 | QGenericArgument val3, |
1554 | QGenericArgument val4, |
1555 | QGenericArgument val5, |
1556 | QGenericArgument val6, |
1557 | QGenericArgument val7, |
1558 | QGenericArgument val8, |
1559 | QGenericArgument val9) |
1560 | { |
1561 | if (!obj) |
1562 | return false; |
1563 | |
1564 | const char *typeNames[] = {ret.name(), val0.name(), val1.name(), val2.name(), val3.name(), |
1565 | val4.name(), val5.name(), val6.name(), val7.name(), val8.name(), |
1566 | val9.name()}; |
1567 | const void *parameters[] = {ret.data(), val0.data(), val1.data(), val2.data(), val3.data(), |
1568 | val4.data(), val5.data(), val6.data(), val7.data(), val8.data(), |
1569 | val9.data()}; |
1570 | int paramCount; |
1571 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
1572 | if (qstrlen(str: typeNames[paramCount]) <= 0) |
1573 | break; |
1574 | } |
1575 | return invokeMethodImpl(object: obj, member, type, parameterCount: paramCount, parameters, names: typeNames, metaTypes: nullptr); |
1576 | } |
1577 | |
1578 | bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::ConnectionType type, |
1579 | qsizetype paramCount, const void * const *parameters, |
1580 | const char * const *typeNames, |
1581 | const QtPrivate::QMetaTypeInterface * const *metaTypes) |
1582 | { |
1583 | if (!obj) |
1584 | return false; |
1585 | |
1586 | Q_ASSERT(paramCount >= 1); // includes the return type |
1587 | Q_ASSERT(parameters); |
1588 | Q_ASSERT(typeNames); |
1589 | |
1590 | // find the method |
1591 | QByteArrayView name(member); |
1592 | if (name.isEmpty()) |
1593 | return false; |
1594 | |
1595 | const QMetaObject *meta = obj->metaObject(); |
1596 | for ( ; meta; meta = meta->superClass()) { |
1597 | auto priv = QMetaObjectPrivate::get(metaobject: meta); |
1598 | for (int i = 0; i < priv->methodCount; ++i) { |
1599 | QMetaMethod m = QMetaMethod::fromRelativeMethodIndex(mobj: meta, index: i); |
1600 | if (m.parameterCount() != (paramCount - 1)) |
1601 | continue; |
1602 | if (name != stringDataView(mo: meta, index: m.data.name())) |
1603 | continue; |
1604 | |
1605 | // attempt to call |
1606 | QMetaMethodPrivate::InvokeFailReason r = |
1607 | QMetaMethodPrivate::invokeImpl(self: m, target: obj, type, paramCount, parameters, |
1608 | typeNames, metaTypes); |
1609 | if (int(r) <= 0) |
1610 | return r == QMetaMethodPrivate::InvokeFailReason::None; |
1611 | } |
1612 | } |
1613 | |
1614 | // This method doesn't belong to us; print out a nice warning with candidates. |
1615 | return printMethodNotFoundWarning(meta: obj->metaObject(), name, paramCount, names: typeNames, metaTypes); |
1616 | } |
1617 | |
1618 | bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, |
1619 | qsizetype parameterCount, const void *const *params, const char *const *names, |
1620 | const QtPrivate::QMetaTypeInterface * const *metaTypes) |
1621 | { |
1622 | // We don't need this now but maybe we want it later, or we may be able to |
1623 | // share more code between the two invokeMethodImpl() overloads: |
1624 | Q_UNUSED(names); |
1625 | auto slot = QtPrivate::SlotObjUniquePtr(slotObj); |
1626 | |
1627 | if (! object) // ### only if the slot requires the object + not queued? |
1628 | return false; |
1629 | |
1630 | Qt::HANDLE currentThreadId = QThread::currentThreadId(); |
1631 | QThread *objectThread = object->thread(); |
1632 | bool receiverInSameThread = false; |
1633 | if (objectThread) |
1634 | receiverInSameThread = currentThreadId == QThreadData::get2(thread: objectThread)->threadId.loadRelaxed(); |
1635 | |
1636 | if (type == Qt::AutoConnection) |
1637 | type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection; |
1638 | |
1639 | void **argv = const_cast<void **>(params); |
1640 | if (type == Qt::DirectConnection) { |
1641 | slot->call(r: object, a: argv); |
1642 | } else if (type == Qt::QueuedConnection) { |
1643 | if (argv[0]) { |
1644 | qWarning(msg: "QMetaObject::invokeMethod: Unable to invoke methods with return values in " |
1645 | "queued connections" ); |
1646 | return false; |
1647 | } |
1648 | auto event = std::make_unique<QMetaCallEvent>(args: std::move(slot), args: nullptr, args: -1, args&: parameterCount); |
1649 | void **args = event->args(); |
1650 | QMetaType *types = event->types(); |
1651 | |
1652 | for (int i = 1; i < parameterCount; ++i) { |
1653 | types[i] = QMetaType(metaTypes[i]); |
1654 | args[i] = types[i].create(copy: argv[i]); |
1655 | } |
1656 | |
1657 | QCoreApplication::postEvent(receiver: object, event: event.release()); |
1658 | } else if (type == Qt::BlockingQueuedConnection) { |
1659 | #if QT_CONFIG(thread) |
1660 | if (receiverInSameThread) |
1661 | qWarning(msg: "QMetaObject::invokeMethod: Dead lock detected" ); |
1662 | |
1663 | QSemaphore semaphore; |
1664 | QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(std::move(slot), nullptr, -1, argv, &semaphore)); |
1665 | semaphore.acquire(); |
1666 | #endif // QT_CONFIG(thread) |
1667 | } else { |
1668 | qWarning(msg: "QMetaObject::invokeMethod: Unknown connection type" ); |
1669 | return false; |
1670 | } |
1671 | return true; |
1672 | } |
1673 | |
1674 | /*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, |
1675 | QGenericReturnArgument ret, |
1676 | QGenericArgument val0 = QGenericArgument(0), |
1677 | QGenericArgument val1 = QGenericArgument(), |
1678 | QGenericArgument val2 = QGenericArgument(), |
1679 | QGenericArgument val3 = QGenericArgument(), |
1680 | QGenericArgument val4 = QGenericArgument(), |
1681 | QGenericArgument val5 = QGenericArgument(), |
1682 | QGenericArgument val6 = QGenericArgument(), |
1683 | QGenericArgument val7 = QGenericArgument(), |
1684 | QGenericArgument val8 = QGenericArgument(), |
1685 | QGenericArgument val9 = QGenericArgument()); |
1686 | \threadsafe |
1687 | \obsolete [6.5] Please use the variadic overload of this function. |
1688 | \overload invokeMethod() |
1689 | |
1690 | This overload always invokes the member using the connection type Qt::AutoConnection. |
1691 | */ |
1692 | |
1693 | /*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, |
1694 | Qt::ConnectionType type, |
1695 | QGenericArgument val0 = QGenericArgument(0), |
1696 | QGenericArgument val1 = QGenericArgument(), |
1697 | QGenericArgument val2 = QGenericArgument(), |
1698 | QGenericArgument val3 = QGenericArgument(), |
1699 | QGenericArgument val4 = QGenericArgument(), |
1700 | QGenericArgument val5 = QGenericArgument(), |
1701 | QGenericArgument val6 = QGenericArgument(), |
1702 | QGenericArgument val7 = QGenericArgument(), |
1703 | QGenericArgument val8 = QGenericArgument(), |
1704 | QGenericArgument val9 = QGenericArgument()) |
1705 | |
1706 | \threadsafe |
1707 | \obsolete [6.5] Please use the variadic overload of this function. |
1708 | \overload invokeMethod() |
1709 | |
1710 | This overload can be used if the return value of the member is of no interest. |
1711 | */ |
1712 | |
1713 | /*! |
1714 | \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member, |
1715 | QGenericArgument val0 = QGenericArgument(0), |
1716 | QGenericArgument val1 = QGenericArgument(), |
1717 | QGenericArgument val2 = QGenericArgument(), |
1718 | QGenericArgument val3 = QGenericArgument(), |
1719 | QGenericArgument val4 = QGenericArgument(), |
1720 | QGenericArgument val5 = QGenericArgument(), |
1721 | QGenericArgument val6 = QGenericArgument(), |
1722 | QGenericArgument val7 = QGenericArgument(), |
1723 | QGenericArgument val8 = QGenericArgument(), |
1724 | QGenericArgument val9 = QGenericArgument()) |
1725 | |
1726 | \threadsafe |
1727 | \obsolete [6.5] Please use the variadic overload of this function. |
1728 | \overload invokeMethod() |
1729 | |
1730 | This overload invokes the member using the connection type Qt::AutoConnection and |
1731 | ignores return values. |
1732 | */ |
1733 | |
1734 | /*! |
1735 | \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, FunctorReturnType *ret) |
1736 | \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret) |
1737 | |
1738 | \since 5.10 |
1739 | \threadsafe |
1740 | |
1741 | Invokes the \a function in the event loop of \a context. \a function can be a functor |
1742 | or a pointer to a member function. Returns \c true if the function could be invoked. |
1743 | Returns \c false if there is no such function or the parameters did not match. |
1744 | The return value of the function call is placed in \a ret. |
1745 | |
1746 | If \a type is set, then the function is invoked using that connection type. Otherwise, |
1747 | Qt::AutoConnection will be used. |
1748 | */ |
1749 | |
1750 | /*! |
1751 | \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments) |
1752 | \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments) |
1753 | \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments) |
1754 | \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Args &&...arguments) |
1755 | |
1756 | \since 6.7 |
1757 | \threadsafe |
1758 | |
1759 | Invokes the \a function with \a arguments in the event loop of \a context. |
1760 | \a function can be a functor or a pointer to a member function. Returns |
1761 | \c true if the function could be invoked. The return value of the |
1762 | function call is placed in \a ret. The object used for the \a ret argument |
1763 | should be obtained by passing your object to qReturnArg(). For example: |
1764 | |
1765 | \badcode |
1766 | MyClass *obj = ...; |
1767 | int result = 0; |
1768 | QMetaObject::invokeMethod(obj, &MyClass::myMethod, qReturnArg(result), parameter); |
1769 | \endcode |
1770 | |
1771 | If \a type is set, then the function is invoked using that connection type. |
1772 | Otherwise, Qt::AutoConnection will be used. |
1773 | */ |
1774 | |
1775 | /*! |
1776 | \fn QMetaObject::Connection &QMetaObject::Connection::operator=(Connection &&other) |
1777 | |
1778 | Move-assigns \a other to this object, and returns a reference. |
1779 | */ |
1780 | /*! |
1781 | \fn QMetaObject::Connection::Connection(Connection &&o) |
1782 | |
1783 | Move-constructs a Connection instance, making it point to the same object |
1784 | that \a o was pointing to. |
1785 | */ |
1786 | |
1787 | /*! |
1788 | \fn QMetaObject::Connection::swap(Connection &other) |
1789 | \since 5.15 |
1790 | \memberswap{Connection instance} |
1791 | */ |
1792 | |
1793 | /*! |
1794 | \class QMetaMethod |
1795 | \inmodule QtCore |
1796 | |
1797 | \brief The QMetaMethod class provides meta-data about a member |
1798 | function. |
1799 | |
1800 | \ingroup objectmodel |
1801 | \compares equality |
1802 | |
1803 | A QMetaMethod has a methodType(), a methodSignature(), a list of |
1804 | parameterTypes() and parameterNames(), a return typeName(), a |
1805 | tag(), and an access() specifier. You can use invoke() to invoke |
1806 | the method on an arbitrary QObject. |
1807 | |
1808 | \sa QMetaObject, QMetaEnum, QMetaProperty, {Qt's Property System} |
1809 | */ |
1810 | |
1811 | /*! |
1812 | \enum QMetaMethod::Attributes |
1813 | |
1814 | \internal |
1815 | |
1816 | \value Compatibility |
1817 | \value Cloned |
1818 | \value Scriptable |
1819 | */ |
1820 | |
1821 | /*! |
1822 | \fn bool QMetaMethod::isValid() const |
1823 | \since 5.0 |
1824 | |
1825 | Returns \c true if this method is valid (can be introspected and |
1826 | invoked), otherwise returns \c false. |
1827 | */ |
1828 | |
1829 | /*! \fn bool QMetaMethod::operator==(const QMetaMethod &lhs, const QMetaMethod &rhs) |
1830 | \since 5.0 |
1831 | \overload |
1832 | |
1833 | Returns \c true if method \a lhs is equal to method \a rhs, |
1834 | otherwise returns \c false. |
1835 | */ |
1836 | |
1837 | /*! \fn bool QMetaMethod::operator!=(const QMetaMethod &lhs, const QMetaMethod &rhs) |
1838 | \since 5.0 |
1839 | \overload |
1840 | |
1841 | Returns \c true if method \a lhs is not equal to method \a rhs, |
1842 | otherwise returns \c false. |
1843 | */ |
1844 | |
1845 | /*! |
1846 | \fn const QMetaObject *QMetaMethod::enclosingMetaObject() const |
1847 | \internal |
1848 | */ |
1849 | |
1850 | /*! |
1851 | \enum QMetaMethod::MethodType |
1852 | |
1853 | \value Method The function is a plain member function. |
1854 | \value Signal The function is a signal. |
1855 | \value Slot The function is a slot. |
1856 | \value Constructor The function is a constructor. |
1857 | */ |
1858 | |
1859 | /*! |
1860 | \fn QMetaMethod::QMetaMethod() |
1861 | \internal |
1862 | */ |
1863 | |
1864 | /*! |
1865 | \internal |
1866 | */ |
1867 | QMetaMethod QMetaMethod::fromRelativeMethodIndex(const QMetaObject *mobj, int index) |
1868 | { |
1869 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->methodCount); |
1870 | QMetaMethod m; |
1871 | m.mobj = mobj; |
1872 | m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->methodData + index * Data::Size }; |
1873 | return m; |
1874 | } |
1875 | |
1876 | QMetaMethod QMetaMethod::fromRelativeConstructorIndex(const QMetaObject *mobj, int index) |
1877 | { |
1878 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->constructorCount); |
1879 | QMetaMethod m; |
1880 | m.mobj = mobj; |
1881 | m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->constructorData + index * Data::Size }; |
1882 | return m; |
1883 | } |
1884 | |
1885 | /*! |
1886 | \macro Q_METAMETHOD_INVOKE_MAX_ARGS |
1887 | \relates QMetaMethod |
1888 | |
1889 | Equals maximum number of arguments available for |
1890 | execution of the method via QMetaMethod::invoke() |
1891 | */ |
1892 | |
1893 | QByteArray QMetaMethodPrivate::signature() const |
1894 | { |
1895 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1896 | QByteArray result; |
1897 | result.reserve(asize: 256); |
1898 | result += name(); |
1899 | result += '('; |
1900 | QList<QByteArray> argTypes = parameterTypes(); |
1901 | for (int i = 0; i < argTypes.size(); ++i) { |
1902 | if (i) |
1903 | result += ','; |
1904 | result += argTypes.at(i); |
1905 | } |
1906 | result += ')'; |
1907 | return result; |
1908 | } |
1909 | |
1910 | QByteArray QMetaMethodPrivate::name() const |
1911 | { |
1912 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1913 | return stringData(mo: mobj, index: data.name()); |
1914 | } |
1915 | |
1916 | int QMetaMethodPrivate::typesDataIndex() const |
1917 | { |
1918 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1919 | return data.parameters(); |
1920 | } |
1921 | |
1922 | const char *QMetaMethodPrivate::rawReturnTypeName() const |
1923 | { |
1924 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1925 | uint typeInfo = mobj->d.data[typesDataIndex()]; |
1926 | if (typeInfo & IsUnresolvedType) |
1927 | return rawStringData(mo: mobj, index: typeInfo & TypeNameIndexMask); |
1928 | else |
1929 | return QMetaType(typeInfo).name(); |
1930 | } |
1931 | |
1932 | int QMetaMethodPrivate::returnType() const |
1933 | { |
1934 | return parameterType(index: -1); |
1935 | } |
1936 | |
1937 | int QMetaMethodPrivate::parameterCount() const |
1938 | { |
1939 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1940 | return data.argc(); |
1941 | } |
1942 | |
1943 | inline void |
1944 | QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, |
1945 | int index) const |
1946 | { |
1947 | uint typeInfo = parameterTypeInfo(index); |
1948 | QMetaType mt(iface); |
1949 | if (iface) { |
1950 | if ((typeInfo & IsUnresolvedType) == 0) |
1951 | Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask)); |
1952 | Q_ASSERT(mt.name()); |
1953 | } else { |
1954 | // The iface can only be null for a parameter if that parameter is a |
1955 | // const-ref to a forward-declared type. Since primitive types are |
1956 | // never incomplete, we can assert it's not one of them. |
1957 | |
1958 | #define ASSERT_NOT_PRIMITIVE_TYPE(TYPE, METATYPEID, NAME) \ |
1959 | Q_ASSERT(typeInfo != QMetaType::TYPE); |
1960 | QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(ASSERT_NOT_PRIMITIVE_TYPE) |
1961 | #undef ASSERT_NOT_PRIMITIVE_TYPE |
1962 | Q_ASSERT(typeInfo != QMetaType::QObjectStar); |
1963 | |
1964 | // Prior to Qt 6.4 we failed to record void and void* |
1965 | if (priv(data: mobj->d.data)->revision >= 11) { |
1966 | Q_ASSERT(typeInfo != QMetaType::Void); |
1967 | Q_ASSERT(typeInfo != QMetaType::VoidStar); |
1968 | } |
1969 | } |
1970 | } |
1971 | |
1972 | int QMetaMethodPrivate::parametersDataIndex() const |
1973 | { |
1974 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1975 | return typesDataIndex() + 1; |
1976 | } |
1977 | |
1978 | uint QMetaMethodPrivate::parameterTypeInfo(int index) const |
1979 | { |
1980 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1981 | return mobj->d.data[parametersDataIndex() + index]; |
1982 | } |
1983 | |
1984 | const QtPrivate::QMetaTypeInterface *QMetaMethodPrivate::returnMetaTypeInterface() const |
1985 | { |
1986 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1987 | if (methodType() == QMetaMethod::Constructor) |
1988 | return nullptr; // constructors don't have return types |
1989 | |
1990 | const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()]; |
1991 | checkMethodMetaTypeConsistency(iface, index: -1); |
1992 | return iface; |
1993 | } |
1994 | |
1995 | const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTypeInterfaces() const |
1996 | { |
1997 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1998 | int offset = (methodType() == QMetaMethod::Constructor ? 0 : 1); |
1999 | const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset]; |
2000 | |
2001 | for (int i = 0; i < parameterCount(); ++i) |
2002 | checkMethodMetaTypeConsistency(iface: ifaces[i], index: i); |
2003 | |
2004 | return ifaces; |
2005 | } |
2006 | |
2007 | int QMetaMethodPrivate::parameterType(int index) const |
2008 | { |
2009 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2010 | return typeFromTypeInfo(mo: mobj, typeInfo: parameterTypeInfo(index)); |
2011 | } |
2012 | |
2013 | void QMetaMethodPrivate::getParameterTypes(int *types) const |
2014 | { |
2015 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2016 | int dataIndex = parametersDataIndex(); |
2017 | int argc = parameterCount(); |
2018 | for (int i = 0; i < argc; ++i) { |
2019 | int id = typeFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[dataIndex++]); |
2020 | *(types++) = id; |
2021 | } |
2022 | } |
2023 | |
2024 | QByteArray QMetaMethodPrivate::parameterTypeName(int index) const |
2025 | { |
2026 | int paramsIndex = parametersDataIndex(); |
2027 | return typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + index]).toByteArray(); |
2028 | } |
2029 | |
2030 | QList<QByteArray> QMetaMethodPrivate::parameterTypes() const |
2031 | { |
2032 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2033 | int argc = parameterCount(); |
2034 | QList<QByteArray> list; |
2035 | list.reserve(asize: argc); |
2036 | int paramsIndex = parametersDataIndex(); |
2037 | for (int i = 0; i < argc; ++i) { |
2038 | QByteArrayView name = typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + i]); |
2039 | list.emplace_back(args: name.toByteArray()); |
2040 | } |
2041 | return list; |
2042 | } |
2043 | |
2044 | QList<QByteArray> QMetaMethodPrivate::parameterNames() const |
2045 | { |
2046 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2047 | int argc = parameterCount(); |
2048 | QList<QByteArray> list; |
2049 | list.reserve(asize: argc); |
2050 | int namesIndex = parametersDataIndex() + argc; |
2051 | for (int i = 0; i < argc; ++i) |
2052 | list += stringData(mo: mobj, index: mobj->d.data[namesIndex + i]); |
2053 | return list; |
2054 | } |
2055 | |
2056 | QByteArray QMetaMethodPrivate::tag() const |
2057 | { |
2058 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2059 | return stringData(mo: mobj, index: data.tag()); |
2060 | } |
2061 | |
2062 | int QMetaMethodPrivate::ownMethodIndex() const |
2063 | { |
2064 | // recompute the methodIndex by reversing the arithmetic in QMetaObject::method() |
2065 | return ( data.d - mobj->d.data - priv(data: mobj->d.data)->methodData)/Data::Size; |
2066 | } |
2067 | |
2068 | int QMetaMethodPrivate::ownConstructorMethodIndex() const |
2069 | { |
2070 | // recompute the methodIndex by reversing the arithmetic in QMetaObject::constructor() |
2071 | Q_ASSERT(methodType() == Constructor); |
2072 | return ( data.d - mobj->d.data - priv(data: mobj->d.data)->constructorData)/Data::Size; |
2073 | } |
2074 | |
2075 | /*! |
2076 | \since 5.0 |
2077 | |
2078 | Returns the signature of this method (e.g., |
2079 | \c{setValue(double)}). |
2080 | |
2081 | \sa parameterTypes(), parameterNames() |
2082 | */ |
2083 | QByteArray QMetaMethod::methodSignature() const |
2084 | { |
2085 | if (!mobj) |
2086 | return QByteArray(); |
2087 | return QMetaMethodPrivate::get(q: this)->signature(); |
2088 | } |
2089 | |
2090 | /*! |
2091 | \since 5.0 |
2092 | |
2093 | Returns the name of this method. |
2094 | |
2095 | \sa methodSignature(), parameterCount() |
2096 | */ |
2097 | QByteArray QMetaMethod::name() const |
2098 | { |
2099 | if (!mobj) |
2100 | return QByteArray(); |
2101 | return QMetaMethodPrivate::get(q: this)->name(); |
2102 | } |
2103 | |
2104 | /*! |
2105 | \since 5.0 |
2106 | |
2107 | Returns the return type of this method. |
2108 | |
2109 | The return value is one of the types that are registered |
2110 | with QMetaType, or QMetaType::UnknownType if the type is not registered. |
2111 | |
2112 | \sa parameterType(), QMetaType, typeName(), returnMetaType() |
2113 | */ |
2114 | int QMetaMethod::returnType() const |
2115 | { |
2116 | return returnMetaType().id(); |
2117 | } |
2118 | |
2119 | /*! |
2120 | \since 6.0 |
2121 | |
2122 | Returns the return type of this method. |
2123 | \sa parameterMetaType(), QMetaType, typeName() |
2124 | */ |
2125 | QMetaType QMetaMethod::returnMetaType() const |
2126 | { |
2127 | if (!mobj || methodType() == QMetaMethod::Constructor) |
2128 | return QMetaType{}; |
2129 | auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset()]); |
2130 | if (mt.id() == QMetaType::UnknownType) |
2131 | return QMetaType(QMetaMethodPrivate::get(q: this)->returnType()); |
2132 | else |
2133 | return mt; |
2134 | } |
2135 | |
2136 | /*! |
2137 | \since 5.0 |
2138 | |
2139 | Returns the number of parameters of this method. |
2140 | |
2141 | \sa parameterType(), parameterNames() |
2142 | */ |
2143 | int QMetaMethod::parameterCount() const |
2144 | { |
2145 | if (!mobj) |
2146 | return 0; |
2147 | return QMetaMethodPrivate::get(q: this)->parameterCount(); |
2148 | } |
2149 | |
2150 | /*! |
2151 | \since 5.0 |
2152 | |
2153 | Returns the type of the parameter at the given \a index. |
2154 | |
2155 | The return value is one of the types that are registered |
2156 | with QMetaType, or QMetaType::UnknownType if the type is not registered. |
2157 | |
2158 | \sa parameterCount(), parameterMetaType(), returnType(), QMetaType |
2159 | */ |
2160 | int QMetaMethod::parameterType(int index) const |
2161 | { |
2162 | return parameterMetaType(index).id(); |
2163 | } |
2164 | |
2165 | /*! |
2166 | \since 6.0 |
2167 | |
2168 | Returns the metatype of the parameter at the given \a index. |
2169 | |
2170 | If the \a index is smaller than zero or larger than |
2171 | parameterCount(), an invalid QMetaType is returned. |
2172 | |
2173 | \sa parameterCount(), returnMetaType(), QMetaType |
2174 | */ |
2175 | QMetaType QMetaMethod::parameterMetaType(int index) const |
2176 | { |
2177 | if (!mobj || index < 0) |
2178 | return {}; |
2179 | auto priv = QMetaMethodPrivate::get(q: this); |
2180 | if (index >= priv->parameterCount()) |
2181 | return {}; |
2182 | // + 1 if there exists a return type |
2183 | auto parameterOffset = index + (methodType() == QMetaMethod::Constructor ? 0 : 1); |
2184 | auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset() + parameterOffset]); |
2185 | if (mt.id() == QMetaType::UnknownType) |
2186 | return QMetaType(QMetaMethodPrivate::get(q: this)->parameterType(index)); |
2187 | else |
2188 | return mt; |
2189 | } |
2190 | |
2191 | /*! |
2192 | \since 5.0 |
2193 | \internal |
2194 | |
2195 | Gets the parameter \a types of this method. The storage |
2196 | for \a types must be able to hold parameterCount() items. |
2197 | |
2198 | \sa parameterCount(), returnType(), parameterType() |
2199 | */ |
2200 | void QMetaMethod::getParameterTypes(int *types) const |
2201 | { |
2202 | if (!mobj) |
2203 | return; |
2204 | QMetaMethodPrivate::get(q: this)->getParameterTypes(types); |
2205 | } |
2206 | |
2207 | /*! |
2208 | Returns a list of parameter types. |
2209 | |
2210 | \sa parameterNames(), methodSignature() |
2211 | */ |
2212 | QList<QByteArray> QMetaMethod::parameterTypes() const |
2213 | { |
2214 | if (!mobj) |
2215 | return QList<QByteArray>(); |
2216 | return QMetaMethodPrivate::get(q: this)->parameterTypes(); |
2217 | } |
2218 | |
2219 | /*! |
2220 | \since 6.0 |
2221 | Returns the name of the type at position \a index |
2222 | If there is no parameter at \a index, returns an empty QByteArray |
2223 | |
2224 | \sa parameterNames() |
2225 | */ |
2226 | QByteArray QMetaMethod::parameterTypeName(int index) const |
2227 | { |
2228 | if (!mobj || index < 0 || index >= parameterCount()) |
2229 | return {}; |
2230 | return QMetaMethodPrivate::get(q: this)->parameterTypeName(index); |
2231 | } |
2232 | |
2233 | /*! |
2234 | Returns a list of parameter names. |
2235 | |
2236 | \sa parameterTypes(), methodSignature() |
2237 | */ |
2238 | QList<QByteArray> QMetaMethod::parameterNames() const |
2239 | { |
2240 | if (!mobj) |
2241 | return QList<QByteArray>(); |
2242 | return QMetaMethodPrivate::get(q: this)->parameterNames(); |
2243 | } |
2244 | |
2245 | |
2246 | /*! |
2247 | Returns the return type name of this method. |
2248 | |
2249 | \sa returnType(), QMetaType::type() |
2250 | */ |
2251 | const char *QMetaMethod::typeName() const |
2252 | { |
2253 | if (!mobj) |
2254 | return nullptr; |
2255 | return QMetaMethodPrivate::get(q: this)->rawReturnTypeName(); |
2256 | } |
2257 | |
2258 | /*! |
2259 | Returns the tag associated with this method. |
2260 | |
2261 | Tags are special macros recognized by \c moc that make it |
2262 | possible to add extra information about a method. |
2263 | |
2264 | Tag information can be added in the following |
2265 | way in the function declaration: |
2266 | |
2267 | \snippet code/src_corelib_kernel_qmetaobject.cpp 10 |
2268 | |
2269 | and the information can be accessed by using: |
2270 | |
2271 | \snippet code/src_corelib_kernel_qmetaobject.cpp 11 |
2272 | |
2273 | For the moment, \c moc will extract and record all tags, but it will not |
2274 | handle any of them specially. You can use the tags to annotate your methods |
2275 | differently, and treat them according to the specific needs of your |
2276 | application. |
2277 | |
2278 | \note \c moc expands preprocessor macros, so it is necessary |
2279 | to surround the definition with \c #ifndef \c Q_MOC_RUN, as shown in the |
2280 | example above. |
2281 | */ |
2282 | const char *QMetaMethod::tag() const |
2283 | { |
2284 | if (!mobj) |
2285 | return nullptr; |
2286 | return QMetaMethodPrivate::get(q: this)->tag().constData(); |
2287 | } |
2288 | |
2289 | |
2290 | /*! |
2291 | \internal |
2292 | */ |
2293 | int QMetaMethod::attributes() const |
2294 | { |
2295 | if (!mobj) |
2296 | return false; |
2297 | return data.flags() >> 4; |
2298 | } |
2299 | |
2300 | /*! |
2301 | \since 4.6 |
2302 | |
2303 | Returns this method's index. |
2304 | */ |
2305 | int QMetaMethod::methodIndex() const |
2306 | { |
2307 | if (!mobj) |
2308 | return -1; |
2309 | return QMetaMethodPrivate::get(q: this)->ownMethodIndex() + mobj->methodOffset(); |
2310 | } |
2311 | |
2312 | /*! |
2313 | \since 6.0 |
2314 | |
2315 | Returns this method's local index inside. |
2316 | */ |
2317 | int QMetaMethod::relativeMethodIndex() const |
2318 | { |
2319 | if (!mobj) |
2320 | return -1; |
2321 | return QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2322 | } |
2323 | |
2324 | // This method has been around for a while, but the documentation was marked \internal until 5.1 |
2325 | /*! |
2326 | \since 5.1 |
2327 | Returns the method revision if one was specified by Q_REVISION, otherwise |
2328 | returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded |
2329 | using QTypeRevision::fromEncodedVersion(). |
2330 | */ |
2331 | int QMetaMethod::revision() const |
2332 | { |
2333 | if (!mobj) |
2334 | return 0; |
2335 | if (data.flags() & MethodRevisioned) { |
2336 | int offset = priv(data: mobj->d.data)->methodData |
2337 | + priv(data: mobj->d.data)->methodCount * Data::Size |
2338 | + QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2339 | return mobj->d.data[offset]; |
2340 | } |
2341 | return 0; |
2342 | } |
2343 | |
2344 | /*! |
2345 | \since 6.2 |
2346 | |
2347 | Returns whether the method is const qualified. |
2348 | |
2349 | \note This method might erroneously return \c false for a const method |
2350 | if it belongs to a library compiled against an older version of Qt. |
2351 | */ |
2352 | bool QMetaMethod::isConst() const |
2353 | { |
2354 | if (!mobj) |
2355 | return false; |
2356 | if (QMetaObjectPrivate::get(metaobject: mobj)->revision < 10) |
2357 | return false; |
2358 | return data.flags() & MethodIsConst; |
2359 | } |
2360 | |
2361 | /*! |
2362 | Returns the access specification of this method (private, |
2363 | protected, or public). |
2364 | |
2365 | \note Signals are always public, but you should regard that as an |
2366 | implementation detail. It is almost always a bad idea to emit a signal from |
2367 | outside its class. |
2368 | |
2369 | \sa methodType() |
2370 | */ |
2371 | QMetaMethod::Access QMetaMethod::access() const |
2372 | { |
2373 | if (!mobj) |
2374 | return Private; |
2375 | return (QMetaMethod::Access)(data.flags() & AccessMask); |
2376 | } |
2377 | |
2378 | /*! |
2379 | Returns the type of this method (signal, slot, or method). |
2380 | |
2381 | \sa access() |
2382 | */ |
2383 | QMetaMethod::MethodType QMetaMethod::methodType() const |
2384 | { |
2385 | if (!mobj) |
2386 | return QMetaMethod::Method; |
2387 | return (QMetaMethod::MethodType)((data.flags() & MethodTypeMask)>>2); |
2388 | } |
2389 | |
2390 | /*! |
2391 | \fn template <typename PointerToMemberFunction> QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal) |
2392 | \since 5.0 |
2393 | |
2394 | Returns the meta-method that corresponds to the given \a signal, or an |
2395 | invalid QMetaMethod if \a signal is \c{nullptr} or not a signal of the class. |
2396 | |
2397 | Example: |
2398 | |
2399 | \snippet code/src_corelib_kernel_qmetaobject.cpp 9 |
2400 | */ |
2401 | |
2402 | /*! |
2403 | \internal |
2404 | |
2405 | Implementation of the fromSignal() function. |
2406 | |
2407 | \a metaObject is the class's meta-object |
2408 | \a signal is a pointer to a pointer to a member signal of the class |
2409 | */ |
2410 | QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal) |
2411 | { |
2412 | int i = -1; |
2413 | void *args[] = { &i, signal }; |
2414 | for (const QMetaObject *m = metaObject; m; m = m->d.superdata) { |
2415 | m->static_metacall(cl: QMetaObject::IndexOfMethod, idx: 0, argv: args); |
2416 | if (i >= 0) |
2417 | return QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i); |
2418 | } |
2419 | return QMetaMethod(); |
2420 | } |
2421 | |
2422 | /*! |
2423 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2424 | \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const |
2425 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2426 | \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const |
2427 | \since 6.5 |
2428 | |
2429 | Invokes this method on the object \a object. Returns \c true if the member could be invoked. |
2430 | Returns \c false if there is no such member or the parameters did not match. |
2431 | |
2432 | For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the |
2433 | return value of the \a member function call is placed in \a ret. For the |
2434 | overloads without such a member, the return value of the called function |
2435 | (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an |
2436 | internal type you should not use directly. Instead, use the qReturnArg() |
2437 | function. |
2438 | |
2439 | The overloads with a Qt::ConnectionType \a type parameter allow explicitly |
2440 | selecting whether the invocation will be synchronous or not: |
2441 | |
2442 | \list |
2443 | \li If \a type is Qt::DirectConnection, the member will be invoked immediately |
2444 | in the current thread. |
2445 | |
2446 | \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the |
2447 | member is invoked as soon as the application enters the event loop in the |
2448 | thread the \a obj was created in or was moved to. |
2449 | |
2450 | \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in |
2451 | the same way as for Qt::QueuedConnection, except that the current thread |
2452 | will block until the event is delivered. Using this connection type to |
2453 | communicate between objects in the same thread will lead to deadlocks. |
2454 | |
2455 | \li If \a type is Qt::AutoConnection, the member is invoked synchronously |
2456 | if \a obj lives in the same thread as the caller; otherwise it will invoke |
2457 | the member asynchronously. This is the behavior of the overloads that do |
2458 | not have the \a type parameter. |
2459 | \endlist |
2460 | |
2461 | To asynchronously invoke the |
2462 | \l{QPushButton::animateClick()}{animateClick()} slot on a |
2463 | QPushButton: |
2464 | |
2465 | \snippet code/src_corelib_kernel_qmetaobject.cpp 6 |
2466 | |
2467 | With asynchronous method invocations, the parameters must be copyable |
2468 | types, because Qt needs to copy the arguments to store them in an event |
2469 | behind the scenes. Since Qt 6.5, this function automatically registers the |
2470 | types being used; however, as a side-effect, it is not possible to make |
2471 | calls using types that are only forward-declared. Additionally, it is not |
2472 | possible to make asynchronous calls that use references to |
2473 | non-const-qualified types as parameters either. |
2474 | |
2475 | To synchronously invoke the \c compute(QString, int, double) slot on |
2476 | some arbitrary object \c obj retrieve its return value: |
2477 | |
2478 | \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro |
2479 | |
2480 | If the "compute" slot does not take exactly one \l QString, one \c int, and |
2481 | one \c double in the specified order, the call will fail. Note how it was |
2482 | necessary to be explicit about the type of the QString, as the character |
2483 | literal is not exactly the right type to match. If the method instead took |
2484 | a \l QByteArray, a \l qint64, and a \c{long double}, the call would need to be |
2485 | written as: |
2486 | |
2487 | \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro-other-types |
2488 | |
2489 | The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros, |
2490 | as in: |
2491 | |
2492 | \snippet code/src_corelib_kernel_qmetaobject.cpp 8 |
2493 | |
2494 | \warning this method will not test the validity of the arguments: \a object |
2495 | must be an instance of the class of the QMetaObject of which this QMetaMethod |
2496 | has been constructed with. |
2497 | |
2498 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2499 | */ |
2500 | |
2501 | /*! |
2502 | \obsolete [6.5] Please use the variadic overload of this function |
2503 | |
2504 | Invokes this method on the object \a object. Returns \c true if the member could be invoked. |
2505 | Returns \c false if there is no such member or the parameters did not match. |
2506 | |
2507 | See the variadic invokeMethod() function for more information. This |
2508 | function should behave the same way as that one, with the following |
2509 | limitations: |
2510 | |
2511 | \list |
2512 | \li The number of parameters is limited to 10. |
2513 | \li Parameter names may need to be an exact string match. |
2514 | \li Meta types are not automatically registered. |
2515 | \endlist |
2516 | |
2517 | With asynchronous method invocations, the parameters must be of |
2518 | types that are known to Qt's meta-object system, because Qt needs |
2519 | to copy the arguments to store them in an event behind the |
2520 | scenes. If you try to use a queued connection and get the error |
2521 | message |
2522 | |
2523 | \snippet code/src_corelib_kernel_qmetaobject.cpp 7 |
2524 | |
2525 | call qRegisterMetaType() to register the data type before you |
2526 | call QMetaMethod::invoke(). |
2527 | |
2528 | \warning In addition to the limitations of the variadic invoke() overload, |
2529 | the arguments must have the same type as the ones expected by the method, |
2530 | else, the behavior is undefined. |
2531 | |
2532 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2533 | */ |
2534 | bool QMetaMethod::invoke(QObject *object, |
2535 | Qt::ConnectionType connectionType, |
2536 | QGenericReturnArgument returnValue, |
2537 | QGenericArgument val0, |
2538 | QGenericArgument val1, |
2539 | QGenericArgument val2, |
2540 | QGenericArgument val3, |
2541 | QGenericArgument val4, |
2542 | QGenericArgument val5, |
2543 | QGenericArgument val6, |
2544 | QGenericArgument val7, |
2545 | QGenericArgument val8, |
2546 | QGenericArgument val9) const |
2547 | { |
2548 | if (!object || !mobj) |
2549 | return false; |
2550 | |
2551 | // check argument count (we don't allow invoking a method if given too few arguments) |
2552 | const char *typeNames[] = { |
2553 | returnValue.name(), |
2554 | val0.name(), |
2555 | val1.name(), |
2556 | val2.name(), |
2557 | val3.name(), |
2558 | val4.name(), |
2559 | val5.name(), |
2560 | val6.name(), |
2561 | val7.name(), |
2562 | val8.name(), |
2563 | val9.name() |
2564 | }; |
2565 | void *param[] = { |
2566 | returnValue.data(), |
2567 | val0.data(), |
2568 | val1.data(), |
2569 | val2.data(), |
2570 | val3.data(), |
2571 | val4.data(), |
2572 | val5.data(), |
2573 | val6.data(), |
2574 | val7.data(), |
2575 | val8.data(), |
2576 | val9.data() |
2577 | }; |
2578 | |
2579 | int paramCount; |
2580 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
2581 | if (qstrlen(str: typeNames[paramCount]) <= 0) |
2582 | break; |
2583 | } |
2584 | return invokeImpl(self: *this, target: object, connectionType, paramCount, parameters: param, typeNames, metaTypes: nullptr); |
2585 | } |
2586 | |
2587 | bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType, |
2588 | qsizetype paramCount, const void *const *parameters, |
2589 | const char *const *typeNames, |
2590 | const QtPrivate::QMetaTypeInterface *const *metaTypes) |
2591 | { |
2592 | if (!target || !self.mobj) |
2593 | return false; |
2594 | QMetaMethodPrivate::InvokeFailReason r = |
2595 | QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, |
2596 | typeNames, metaTypes); |
2597 | if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None)) |
2598 | return true; |
2599 | |
2600 | if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) { |
2601 | int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch); |
2602 | qWarning(msg: "QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s" , |
2603 | n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name, |
2604 | self.mobj->className(), self.methodSignature().constData()); |
2605 | } |
2606 | if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) { |
2607 | qWarning(msg: "QMetaMethod::invoke: too few arguments (%d) in call to %s::%s" , |
2608 | int(paramCount), self.mobj->className(), self.methodSignature().constData()); |
2609 | } |
2610 | return false; |
2611 | } |
2612 | |
2613 | auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, |
2614 | Qt::ConnectionType connectionType, |
2615 | qsizetype paramCount, const void *const *parameters, |
2616 | const char *const *typeNames, |
2617 | const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason |
2618 | { |
2619 | auto object = static_cast<QObject *>(target); |
2620 | auto priv = QMetaMethodPrivate::get(q: &self); |
2621 | constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0); |
2622 | auto methodMetaTypes = priv->parameterMetaTypeInterfaces(); |
2623 | auto param = const_cast<void **>(parameters); |
2624 | |
2625 | Q_ASSERT(priv->mobj); |
2626 | Q_ASSERT(self.methodType() == Constructor || object); |
2627 | Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) || |
2628 | priv->mobj->cast(object)); |
2629 | Q_ASSERT(paramCount >= 1); // includes the return type |
2630 | Q_ASSERT(parameters); |
2631 | Q_ASSERT(typeNames); |
2632 | Q_ASSERT(MetaTypesAreOptional || metaTypes); |
2633 | |
2634 | if ((paramCount - 1) < qsizetype(priv->data.argc())) |
2635 | return InvokeFailReason::TooFewArguments; |
2636 | |
2637 | // 0 is the return type, 1 is the first formal parameter |
2638 | auto checkTypesAreCompatible = [=](int idx) { |
2639 | uint typeInfo = priv->parameterTypeInfo(index: idx - 1); |
2640 | QByteArrayView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name); |
2641 | |
2642 | if ((typeInfo & IsUnresolvedType) == 0) { |
2643 | // this is a built-in type |
2644 | if (MetaTypesAreOptional && !metaTypes) |
2645 | return int(typeInfo) == QMetaType::fromName(name: userTypeName).id(); |
2646 | return int(typeInfo) == metaTypes[idx]->typeId; |
2647 | } |
2648 | |
2649 | QByteArrayView methodTypeName = stringDataView(mo: priv->mobj, index: typeInfo & TypeNameIndexMask); |
2650 | if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) { |
2651 | // compatibility call, compare strings |
2652 | if (methodTypeName == userTypeName) |
2653 | return true; |
2654 | |
2655 | // maybe the user type needs normalization |
2656 | QByteArray normalized = normalizeTypeInternal(t: userTypeName.begin(), e: userTypeName.end()); |
2657 | return methodTypeName == normalized; |
2658 | } |
2659 | |
2660 | QMetaType userType(metaTypes[idx]); |
2661 | Q_ASSERT(userType.isValid()); |
2662 | if (QMetaType(methodMetaTypes[idx - 1]) == userType) |
2663 | return true; |
2664 | |
2665 | // if the parameter type was NOT only forward-declared, it MUST have |
2666 | // matched |
2667 | if (methodMetaTypes[idx - 1]) |
2668 | return false; |
2669 | |
2670 | // resolve from the name moc stored for us |
2671 | QMetaType resolved = QMetaType::fromName(name: methodTypeName); |
2672 | return resolved == userType; |
2673 | }; |
2674 | |
2675 | // force all types to be registered, just in case |
2676 | for (qsizetype i = 0; metaTypes && i < paramCount; ++i) |
2677 | QMetaType(metaTypes[i]).registerType(); |
2678 | |
2679 | // check formal parameters first (overload set) |
2680 | for (qsizetype i = 1; i < paramCount; ++i) { |
2681 | if (!checkTypesAreCompatible(i)) |
2682 | return InvokeFailReason(int(InvokeFailReason::FormalParameterMismatch) + i - 1); |
2683 | } |
2684 | |
2685 | // handle constructors first |
2686 | if (self.methodType() == Constructor) { |
2687 | if (object) { |
2688 | qWarning(msg: "QMetaMethod::invokeMethod: cannot call constructor %s on object %p" , |
2689 | self.methodSignature().constData(), object); |
2690 | return InvokeFailReason::ConstructorCallOnObject; |
2691 | } |
2692 | |
2693 | if (!parameters[0]) { |
2694 | qWarning(msg: "QMetaMethod::invokeMethod: constructor call to %s must assign a return type" , |
2695 | self.methodSignature().constData()); |
2696 | return InvokeFailReason::ConstructorCallWithoutResult; |
2697 | } |
2698 | |
2699 | if (!MetaTypesAreOptional || metaTypes) { |
2700 | if (metaTypes[0]->typeId != QMetaType::QObjectStar) { |
2701 | qWarning(msg: "QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s" , |
2702 | metaTypes[0]->name, self.methodSignature().constData()); |
2703 | return InvokeFailReason::ReturnTypeMismatch; |
2704 | } |
2705 | } |
2706 | |
2707 | int idx = priv->ownConstructorMethodIndex(); |
2708 | if (priv->mobj->static_metacall(cl: QMetaObject::CreateInstance, idx, argv: param) >= 0) |
2709 | return InvokeFailReason::ConstructorCallFailed; |
2710 | return {}; |
2711 | } |
2712 | |
2713 | // regular type - check return type |
2714 | if (parameters[0]) { |
2715 | if (!checkTypesAreCompatible(0)) { |
2716 | const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name; |
2717 | qWarning(msg: "QMetaMethod::invokeMethod: return type mismatch for method %s::%s:" |
2718 | " cannot convert from %s to %s during invocation" , |
2719 | priv->mobj->className(), priv->methodSignature().constData(), |
2720 | priv->rawReturnTypeName(), retType); |
2721 | return InvokeFailReason::ReturnTypeMismatch; |
2722 | } |
2723 | } |
2724 | |
2725 | Qt::HANDLE currentThreadId = nullptr; |
2726 | QThread *objectThread = nullptr; |
2727 | auto receiverInSameThread = [&]() { |
2728 | if (!currentThreadId) { |
2729 | currentThreadId = QThread::currentThreadId(); |
2730 | objectThread = object->thread(); |
2731 | } |
2732 | if (objectThread) |
2733 | return currentThreadId == QThreadData::get2(thread: objectThread)->threadId.loadRelaxed(); |
2734 | return false; |
2735 | }; |
2736 | |
2737 | // check connection type |
2738 | if (connectionType == Qt::AutoConnection) |
2739 | connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection; |
2740 | else if (connectionType == Qt::ConnectionType(-1)) |
2741 | connectionType = Qt::DirectConnection; |
2742 | |
2743 | #if !QT_CONFIG(thread) |
2744 | if (connectionType == Qt::BlockingQueuedConnection) { |
2745 | connectionType = Qt::DirectConnection; |
2746 | } |
2747 | #endif |
2748 | |
2749 | // invoke! |
2750 | int idx_relative = priv->ownMethodIndex(); |
2751 | int idx_offset = priv->mobj->methodOffset(); |
2752 | QObjectPrivate::StaticMetaCallFunction callFunction = priv->mobj->d.static_metacall; |
2753 | |
2754 | if (connectionType == Qt::DirectConnection) { |
2755 | if (callFunction) |
2756 | callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param); |
2757 | else if (QMetaObject::metacall(object, cl: QMetaObject::InvokeMetaMethod, idx: idx_relative + idx_offset, argv: param) >= 0) |
2758 | return InvokeFailReason::CallViaVirtualFailed; |
2759 | } else if (connectionType == Qt::QueuedConnection) { |
2760 | if (parameters[0]) { |
2761 | qWarning(msg: "QMetaMethod::invoke: Unable to invoke methods with return values in " |
2762 | "queued connections" ); |
2763 | return InvokeFailReason::CouldNotQueueParameter; |
2764 | } |
2765 | |
2766 | auto event = std::make_unique<QMetaCallEvent>(args&: idx_offset, args&: idx_relative, args&: callFunction, args: nullptr, args: -1, args&: paramCount); |
2767 | QMetaType *types = event->types(); |
2768 | void **args = event->args(); |
2769 | |
2770 | // fill in the meta types first |
2771 | for (int i = 1; i < paramCount; ++i) { |
2772 | types[i] = QMetaType(methodMetaTypes[i - 1]); |
2773 | if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes)) |
2774 | types[i] = QMetaType(metaTypes[i]); |
2775 | if (!types[i].iface()) |
2776 | types[i] = priv->parameterMetaType(index: i - 1); |
2777 | if (!types[i].iface() && typeNames[i]) |
2778 | types[i] = QMetaType::fromName(name: typeNames[i]); |
2779 | if (!types[i].iface()) { |
2780 | qWarning(msg: "QMetaMethod::invoke: Unable to handle unregistered datatype '%s'" , |
2781 | typeNames[i]); |
2782 | return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i); |
2783 | } |
2784 | } |
2785 | |
2786 | // now create copies of our parameters using those meta types |
2787 | for (int i = 1; i < paramCount; ++i) |
2788 | args[i] = types[i].create(copy: parameters[i]); |
2789 | |
2790 | QCoreApplication::postEvent(receiver: object, event: event.release()); |
2791 | } else { // blocking queued connection |
2792 | #if QT_CONFIG(thread) |
2793 | if (receiverInSameThread()) { |
2794 | qWarning(msg: "QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: " |
2795 | "Receiver is %s(%p)" , priv->mobj->className(), object); |
2796 | return InvokeFailReason::DeadLockDetected; |
2797 | } |
2798 | |
2799 | QSemaphore semaphore; |
2800 | QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(idx_offset, idx_relative, callFunction, |
2801 | nullptr, -1, param, &semaphore)); |
2802 | semaphore.acquire(); |
2803 | #endif // QT_CONFIG(thread) |
2804 | } |
2805 | return {}; |
2806 | } |
2807 | |
2808 | /*! \fn bool QMetaMethod::invoke(QObject *object, |
2809 | QGenericReturnArgument returnValue, |
2810 | QGenericArgument val0 = QGenericArgument(0), |
2811 | QGenericArgument val1 = QGenericArgument(), |
2812 | QGenericArgument val2 = QGenericArgument(), |
2813 | QGenericArgument val3 = QGenericArgument(), |
2814 | QGenericArgument val4 = QGenericArgument(), |
2815 | QGenericArgument val5 = QGenericArgument(), |
2816 | QGenericArgument val6 = QGenericArgument(), |
2817 | QGenericArgument val7 = QGenericArgument(), |
2818 | QGenericArgument val8 = QGenericArgument(), |
2819 | QGenericArgument val9 = QGenericArgument()) const |
2820 | \obsolete [6.5] Please use the variadic overload of this function |
2821 | \overload invoke() |
2822 | |
2823 | This overload always invokes this method using the connection type Qt::AutoConnection. |
2824 | */ |
2825 | |
2826 | /*! \fn bool QMetaMethod::invoke(QObject *object, |
2827 | Qt::ConnectionType connectionType, |
2828 | QGenericArgument val0 = QGenericArgument(0), |
2829 | QGenericArgument val1 = QGenericArgument(), |
2830 | QGenericArgument val2 = QGenericArgument(), |
2831 | QGenericArgument val3 = QGenericArgument(), |
2832 | QGenericArgument val4 = QGenericArgument(), |
2833 | QGenericArgument val5 = QGenericArgument(), |
2834 | QGenericArgument val6 = QGenericArgument(), |
2835 | QGenericArgument val7 = QGenericArgument(), |
2836 | QGenericArgument val8 = QGenericArgument(), |
2837 | QGenericArgument val9 = QGenericArgument()) const |
2838 | \obsolete [6.5] Please use the variadic overload of this function |
2839 | \overload invoke() |
2840 | |
2841 | This overload can be used if the return value of the member is of no interest. |
2842 | */ |
2843 | |
2844 | /*! |
2845 | \fn bool QMetaMethod::invoke(QObject *object, |
2846 | QGenericArgument val0 = QGenericArgument(0), |
2847 | QGenericArgument val1 = QGenericArgument(), |
2848 | QGenericArgument val2 = QGenericArgument(), |
2849 | QGenericArgument val3 = QGenericArgument(), |
2850 | QGenericArgument val4 = QGenericArgument(), |
2851 | QGenericArgument val5 = QGenericArgument(), |
2852 | QGenericArgument val6 = QGenericArgument(), |
2853 | QGenericArgument val7 = QGenericArgument(), |
2854 | QGenericArgument val8 = QGenericArgument(), |
2855 | QGenericArgument val9 = QGenericArgument()) const |
2856 | \obsolete [6.5] Please use the variadic overload of this function |
2857 | \overload invoke() |
2858 | |
2859 | This overload invokes this method using the |
2860 | connection type Qt::AutoConnection and ignores return values. |
2861 | */ |
2862 | |
2863 | /*! |
2864 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2865 | \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const |
2866 | \since 6.5 |
2867 | |
2868 | Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked. |
2869 | Returns \c false if there is no such member or the parameters did not match. |
2870 | |
2871 | The pointer \a gadget must point to an instance of the gadget class. |
2872 | |
2873 | The invocation is always synchronous. |
2874 | |
2875 | For the overload with a QTemplatedMetaMethodReturnArgument parameter, the |
2876 | return value of the \a member function call is placed in \a ret. For the |
2877 | overload without it, the return value of the called function (if any) will |
2878 | be discarded. QTemplatedMetaMethodReturnArgument is an internal type you |
2879 | should not use directly. Instead, use the qReturnArg() function. |
2880 | |
2881 | \warning this method will not test the validity of the arguments: \a gadget |
2882 | must be an instance of the class of the QMetaObject of which this QMetaMethod |
2883 | has been constructed with. |
2884 | |
2885 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2886 | */ |
2887 | |
2888 | /*! |
2889 | \since 5.5 |
2890 | \obsolete [6.5] Please use the variadic overload of this function |
2891 | |
2892 | Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked. |
2893 | Returns \c false if there is no such member or the parameters did not match. |
2894 | |
2895 | See the variadic invokeMethod() function for more information. This |
2896 | function should behave the same way as that one, with the following |
2897 | limitations: |
2898 | |
2899 | \list |
2900 | \li The number of parameters is limited to 10. |
2901 | \li Parameter names may need to be an exact string match. |
2902 | \li Meta types are not automatically registered. |
2903 | \endlist |
2904 | |
2905 | \warning In addition to the limitations of the variadic invoke() overload, |
2906 | the arguments must have the same type as the ones expected by the method, |
2907 | else, the behavior is undefined. |
2908 | |
2909 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2910 | */ |
2911 | bool QMetaMethod::invokeOnGadget(void *gadget, |
2912 | QGenericReturnArgument returnValue, |
2913 | QGenericArgument val0, |
2914 | QGenericArgument val1, |
2915 | QGenericArgument val2, |
2916 | QGenericArgument val3, |
2917 | QGenericArgument val4, |
2918 | QGenericArgument val5, |
2919 | QGenericArgument val6, |
2920 | QGenericArgument val7, |
2921 | QGenericArgument val8, |
2922 | QGenericArgument val9) const |
2923 | { |
2924 | if (!gadget || !mobj) |
2925 | return false; |
2926 | |
2927 | // check return type |
2928 | if (returnValue.data()) { |
2929 | const char *retType = typeName(); |
2930 | if (qstrcmp(str1: returnValue.name(), str2: retType) != 0) { |
2931 | // normalize the return value as well |
2932 | QByteArray normalized = QMetaObject::normalizedType(type: returnValue.name()); |
2933 | if (qstrcmp(str1: normalized.constData(), str2: retType) != 0) { |
2934 | // String comparison failed, try compare the metatype. |
2935 | int t = returnType(); |
2936 | if (t == QMetaType::UnknownType || t != QMetaType::fromName(name: normalized).id()) |
2937 | return false; |
2938 | } |
2939 | } |
2940 | } |
2941 | |
2942 | // check argument count (we don't allow invoking a method if given too few arguments) |
2943 | const char *typeNames[] = { |
2944 | returnValue.name(), |
2945 | val0.name(), |
2946 | val1.name(), |
2947 | val2.name(), |
2948 | val3.name(), |
2949 | val4.name(), |
2950 | val5.name(), |
2951 | val6.name(), |
2952 | val7.name(), |
2953 | val8.name(), |
2954 | val9.name() |
2955 | }; |
2956 | int paramCount; |
2957 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
2958 | if (qstrlen(str: typeNames[paramCount]) <= 0) |
2959 | break; |
2960 | } |
2961 | if (paramCount <= QMetaMethodPrivate::get(q: this)->parameterCount()) |
2962 | return false; |
2963 | |
2964 | // invoke! |
2965 | void *param[] = { |
2966 | returnValue.data(), |
2967 | val0.data(), |
2968 | val1.data(), |
2969 | val2.data(), |
2970 | val3.data(), |
2971 | val4.data(), |
2972 | val5.data(), |
2973 | val6.data(), |
2974 | val7.data(), |
2975 | val8.data(), |
2976 | val9.data() |
2977 | }; |
2978 | int idx_relative = QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2979 | Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6); |
2980 | QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall; |
2981 | if (!callFunction) |
2982 | return false; |
2983 | callFunction(reinterpret_cast<QObject*>(gadget), QMetaObject::InvokeMetaMethod, idx_relative, param); |
2984 | return true; |
2985 | } |
2986 | |
2987 | /*! |
2988 | \fn bool QMetaMethod::invokeOnGadget(void *gadget, |
2989 | QGenericArgument val0 = QGenericArgument(0), |
2990 | QGenericArgument val1 = QGenericArgument(), |
2991 | QGenericArgument val2 = QGenericArgument(), |
2992 | QGenericArgument val3 = QGenericArgument(), |
2993 | QGenericArgument val4 = QGenericArgument(), |
2994 | QGenericArgument val5 = QGenericArgument(), |
2995 | QGenericArgument val6 = QGenericArgument(), |
2996 | QGenericArgument val7 = QGenericArgument(), |
2997 | QGenericArgument val8 = QGenericArgument(), |
2998 | QGenericArgument val9 = QGenericArgument()) const |
2999 | |
3000 | \overload |
3001 | \obsolete [6.5] Please use the variadic overload of this function |
3002 | \since 5.5 |
3003 | |
3004 | This overload invokes this method for a \a gadget and ignores return values. |
3005 | */ |
3006 | |
3007 | /*! |
3008 | \class QMetaEnum |
3009 | \inmodule QtCore |
3010 | \brief The QMetaEnum class provides meta-data about an enumerator. |
3011 | |
3012 | \ingroup objectmodel |
3013 | |
3014 | Use name() for the enumerator's name. The enumerator's keys (names |
3015 | of each enumerated item) are returned by key(); use keyCount() to find |
3016 | the number of keys. isFlag() returns whether the enumerator is |
3017 | meant to be used as a flag, meaning that its values can be combined |
3018 | using the OR operator. |
3019 | |
3020 | The conversion functions keyToValue(), valueToKey(), keysToValue(), |
3021 | and valueToKeys() allow conversion between the integer |
3022 | representation of an enumeration or set value and its literal |
3023 | representation. The scope() function returns the class scope this |
3024 | enumerator was declared in. |
3025 | |
3026 | \sa QMetaObject, QMetaMethod, QMetaProperty |
3027 | */ |
3028 | |
3029 | /*! |
3030 | \fn bool QMetaEnum::isValid() const |
3031 | |
3032 | Returns \c true if this enum is valid (has a name); otherwise returns |
3033 | false. |
3034 | |
3035 | \sa name() |
3036 | */ |
3037 | |
3038 | /*! |
3039 | \fn const QMetaObject *QMetaEnum::enclosingMetaObject() const |
3040 | \internal |
3041 | */ |
3042 | |
3043 | |
3044 | /*! |
3045 | \fn QMetaEnum::QMetaEnum() |
3046 | \internal |
3047 | */ |
3048 | |
3049 | /*! |
3050 | Returns the name of the type (without the scope). |
3051 | |
3052 | For example, the Qt::Key enumeration has \c |
3053 | Key as the type name and \l Qt as the scope. |
3054 | |
3055 | For flags this returns the name of the flag type, not the |
3056 | name of the enum type. |
3057 | |
3058 | \sa isValid(), scope(), enumName() |
3059 | */ |
3060 | const char *QMetaEnum::name() const |
3061 | { |
3062 | if (!mobj) |
3063 | return nullptr; |
3064 | return rawStringData(mo: mobj, index: data.name()); |
3065 | } |
3066 | |
3067 | /*! |
3068 | Returns the enum name of the flag (without the scope). |
3069 | |
3070 | For example, the Qt::AlignmentFlag flag has \c |
3071 | AlignmentFlag as the enum name, but \c Alignment as the type name. |
3072 | Non flag enums has the same type and enum names. |
3073 | |
3074 | Enum names have the same scope as the type name. |
3075 | |
3076 | \since 5.12 |
3077 | \sa isValid(), name() |
3078 | */ |
3079 | const char *QMetaEnum::enumName() const |
3080 | { |
3081 | if (!mobj) |
3082 | return nullptr; |
3083 | return rawStringData(mo: mobj, index: data.alias()); |
3084 | } |
3085 | |
3086 | /*! |
3087 | Returns the meta type of the enum. |
3088 | |
3089 | If the QMetaObject that this enum is part of was generated with Qt 6.5 or |
3090 | earlier, this will be an invalid meta type. |
3091 | |
3092 | \note This is the meta type of the enum itself, not of its underlying |
3093 | integral type. You can retrieve the meta type of the underlying type of the |
3094 | enum using \l{QMetaType::underlyingType()}. |
3095 | |
3096 | \since 6.6 |
3097 | */ |
3098 | QMetaType QMetaEnum::metaType() const |
3099 | { |
3100 | if (!mobj) |
3101 | return {}; |
3102 | |
3103 | const QMetaObjectPrivate *p = priv(data: mobj->d.data); |
3104 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
3105 | if (p->revision < 12) |
3106 | QMetaType(); |
3107 | #endif |
3108 | |
3109 | return QMetaType(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]); |
3110 | } |
3111 | |
3112 | /*! |
3113 | Returns the number of keys. |
3114 | |
3115 | \sa key() |
3116 | */ |
3117 | int QMetaEnum::keyCount() const |
3118 | { |
3119 | if (!mobj) |
3120 | return 0; |
3121 | return data.keyCount(); |
3122 | } |
3123 | |
3124 | /*! |
3125 | Returns the key with the given \a index, or \nullptr if no such key exists. |
3126 | |
3127 | \sa keyCount(), value(), valueToKey() |
3128 | */ |
3129 | const char *QMetaEnum::key(int index) const |
3130 | { |
3131 | if (!mobj) |
3132 | return nullptr; |
3133 | if (index >= 0 && index < int(data.keyCount())) |
3134 | return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2*index]); |
3135 | return nullptr; |
3136 | } |
3137 | |
3138 | /*! |
3139 | Returns the value with the given \a index; or returns -1 if there |
3140 | is no such value. |
3141 | |
3142 | \sa keyCount(), key(), keyToValue() |
3143 | */ |
3144 | int QMetaEnum::value(int index) const |
3145 | { |
3146 | if (!mobj) |
3147 | return 0; |
3148 | if (index >= 0 && index < int(data.keyCount())) |
3149 | return mobj->d.data[data.data() + 2 * index + 1]; |
3150 | return -1; |
3151 | } |
3152 | |
3153 | /*! |
3154 | Returns \c true if this enumerator is used as a flag; otherwise returns |
3155 | false. |
3156 | |
3157 | When used as flags, enumerators can be combined using the OR |
3158 | operator. |
3159 | |
3160 | \sa keysToValue(), valueToKeys() |
3161 | */ |
3162 | bool QMetaEnum::isFlag() const |
3163 | { |
3164 | if (!mobj) |
3165 | return false; |
3166 | return data.flags() & EnumIsFlag; |
3167 | } |
3168 | |
3169 | /*! |
3170 | \since 5.8 |
3171 | |
3172 | Returns \c true if this enumerator is declared as a C++11 enum class; |
3173 | otherwise returns false. |
3174 | */ |
3175 | bool QMetaEnum::isScoped() const |
3176 | { |
3177 | if (!mobj) |
3178 | return false; |
3179 | return data.flags() & EnumIsScoped; |
3180 | } |
3181 | |
3182 | /*! |
3183 | Returns the scope this enumerator was declared in. |
3184 | |
3185 | For example, the Qt::AlignmentFlag enumeration has \c Qt as |
3186 | the scope and \c AlignmentFlag as the name. |
3187 | |
3188 | \sa name() |
3189 | */ |
3190 | const char *QMetaEnum::scope() const |
3191 | { |
3192 | return mobj ? mobj->className() : nullptr; |
3193 | } |
3194 | |
3195 | static bool isScopeMatch(QByteArrayView scope, const QMetaEnum *e) |
3196 | { |
3197 | const QByteArrayView className = e->enclosingMetaObject()->className(); |
3198 | |
3199 | // Typical use-cases: |
3200 | // a) Unscoped: namespace N { class C { enum E { F }; }; }; key == "N::C::F" |
3201 | // b) Scoped: namespace N { class C { enum class E { F }; }; }; key == "N::C::E::F" |
3202 | if (scope == className) |
3203 | return true; |
3204 | |
3205 | // Not using name() because if isFlag() is true, we want the actual name |
3206 | // of the enum, e.g. "MyFlag", not "MyFlags", e.g. |
3207 | // enum MyFlag { F1, F2 }; Q_DECLARE_FLAGS(MyFlags, MyFlag); |
3208 | QByteArrayView name = e->enumName(); |
3209 | |
3210 | // Match fully qualified enumerator in unscoped enums, key == "N::C::E::F" |
3211 | // equivalent to use-case "a" above |
3212 | const auto sz = className.size(); |
3213 | if (scope.size() == sz + qsizetype(qstrlen(str: "::" )) + name.size() |
3214 | && scope.startsWith(other: className) |
3215 | && scope.sliced(pos: sz, n: 2) == "::" |
3216 | && scope.sliced(pos: sz + 2) == name) |
3217 | return true; |
3218 | |
3219 | return false; |
3220 | } |
3221 | |
3222 | /*! |
3223 | Returns the integer value of the given enumeration \a key, or -1 |
3224 | if \a key is not defined. |
3225 | |
3226 | If \a key is not defined, *\a{ok} is set to false; otherwise |
3227 | *\a{ok} is set to true. |
3228 | |
3229 | For flag types, use keysToValue(). |
3230 | |
3231 | \sa valueToKey(), isFlag(), keysToValue() |
3232 | */ |
3233 | int QMetaEnum::keyToValue(const char *key, bool *ok) const |
3234 | { |
3235 | if (ok != nullptr) |
3236 | *ok = false; |
3237 | if (!mobj || !key) |
3238 | return -1; |
3239 | |
3240 | const auto [scope, enumKey] = parse_scope(qualifiedKey: QLatin1StringView(key)); |
3241 | for (int i = 0; i < int(data.keyCount()); ++i) { |
3242 | if ((!scope || isScopeMatch(scope: *scope, e: this)) |
3243 | && enumKey == stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2 * i])) { |
3244 | if (ok != nullptr) |
3245 | *ok = true; |
3246 | return mobj->d.data[data.data() + 2 * i + 1]; |
3247 | } |
3248 | } |
3249 | return -1; |
3250 | } |
3251 | |
3252 | /*! |
3253 | Returns the string that is used as the name of the given |
3254 | enumeration \a value, or \nullptr if \a value is not defined. |
3255 | |
3256 | For flag types, use valueToKeys(). |
3257 | |
3258 | \sa isFlag(), valueToKeys() |
3259 | */ |
3260 | const char *QMetaEnum::valueToKey(int value) const |
3261 | { |
3262 | if (!mobj) |
3263 | return nullptr; |
3264 | for (int i = 0; i < int(data.keyCount()); ++i) |
3265 | if (value == (int)mobj->d.data[data.data() + 2 * i + 1]) |
3266 | return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2 * i]); |
3267 | return nullptr; |
3268 | } |
3269 | |
3270 | static bool parseEnumFlags(QByteArrayView v, QVarLengthArray<QByteArrayView, 10> &list) |
3271 | { |
3272 | v = v.trimmed(); |
3273 | if (v.empty()) { |
3274 | qWarning(msg: "QMetaEnum::keysToValue: empty keys string." ); |
3275 | return false; |
3276 | } |
3277 | |
3278 | qsizetype sep = v.indexOf(ch: '|', from: 0); |
3279 | if (sep == 0) { |
3280 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, starts with '|', \"%s\"" , |
3281 | v.constData()); |
3282 | return false; |
3283 | } |
3284 | |
3285 | if (sep == -1) { // One flag |
3286 | list.push_back(t: v); |
3287 | return true; |
3288 | } |
3289 | |
3290 | if (v.endsWith(c: '|')) { |
3291 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, ends with '|', \"%s\"" , |
3292 | v.constData()); |
3293 | return false; |
3294 | } |
3295 | |
3296 | const auto begin = v.begin(); |
3297 | const auto end = v.end(); |
3298 | auto b = begin; |
3299 | for (; b != end && sep != -1; sep = v.indexOf(ch: '|', from: sep)) { |
3300 | list.push_back(t: {b, begin + sep}); |
3301 | ++sep; // Skip over '|' |
3302 | b = begin + sep; |
3303 | if (*b == '|') { |
3304 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, has two consecutive '|': " |
3305 | "\"%s\"" , v.constData()); |
3306 | return false; |
3307 | } |
3308 | } |
3309 | |
3310 | // The rest of the string |
3311 | list.push_back(t: {b, end}); |
3312 | return true; |
3313 | } |
3314 | |
3315 | /*! |
3316 | Returns the value derived from combining together the values of |
3317 | the \a keys using the OR operator, or -1 if \a keys is not |
3318 | defined. Note that the strings in \a keys must be '|'-separated. |
3319 | |
3320 | If \a keys is not defined, *\a{ok} is set to false; otherwise |
3321 | *\a{ok} is set to true. |
3322 | |
3323 | \sa isFlag(), valueToKey(), valueToKeys() |
3324 | */ |
3325 | int QMetaEnum::keysToValue(const char *keys, bool *ok) const |
3326 | { |
3327 | if (ok != nullptr) |
3328 | *ok = false; |
3329 | if (!mobj || !keys) |
3330 | return -1; |
3331 | |
3332 | auto lookup = [&] (QByteArrayView key) -> std::optional<int> { |
3333 | for (int i = data.keyCount() - 1; i >= 0; --i) { |
3334 | if (key == stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2*i])) |
3335 | return mobj->d.data[data.data() + 2*i + 1]; |
3336 | } |
3337 | return std::nullopt; |
3338 | }; |
3339 | |
3340 | int value = 0; |
3341 | QVarLengthArray<QByteArrayView, 10> list; |
3342 | const bool r = parseEnumFlags(v: QByteArrayView{keys}, list); |
3343 | if (!r) |
3344 | return -1; |
3345 | for (const auto &untrimmed : list) { |
3346 | const auto parsed = parse_scope(qualifiedKey: untrimmed.trimmed()); |
3347 | if (parsed.scope && !isScopeMatch(scope: *parsed.scope, e: this)) |
3348 | return -1; // wrong type name in qualified name |
3349 | if (auto thisValue = lookup(parsed.key)) |
3350 | value |= *thisValue; |
3351 | else |
3352 | return -1; // no such enumerator |
3353 | } |
3354 | if (ok != nullptr) |
3355 | *ok = true; |
3356 | return value; |
3357 | } |
3358 | |
3359 | namespace |
3360 | { |
3361 | template <typename String, typename Container, typename Separator> |
3362 | void join_reversed(String &s, const Container &c, Separator sep) |
3363 | { |
3364 | if (c.empty()) |
3365 | return; |
3366 | qsizetype len = qsizetype(c.size()) - 1; // N - 1 separators |
3367 | for (auto &e : c) |
3368 | len += qsizetype(e.size()); // N parts |
3369 | s.reserve(len); |
3370 | bool first = true; |
3371 | for (auto rit = c.rbegin(), rend = c.rend(); rit != rend; ++rit) { |
3372 | const auto &e = *rit; |
3373 | if (!first) |
3374 | s.append(sep); |
3375 | first = false; |
3376 | s.append(e.data(), e.size()); |
3377 | } |
3378 | } |
3379 | } // unnamed namespace |
3380 | |
3381 | /*! |
3382 | Returns a byte array of '|'-separated keys that represents the |
3383 | given \a value. |
3384 | |
3385 | \sa isFlag(), valueToKey(), keysToValue() |
3386 | */ |
3387 | QByteArray QMetaEnum::valueToKeys(int value) const |
3388 | { |
3389 | QByteArray keys; |
3390 | if (!mobj) |
3391 | return keys; |
3392 | QVarLengthArray<QByteArrayView, sizeof(int) * CHAR_BIT> parts; |
3393 | int v = value; |
3394 | // reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first. |
3395 | for (int i = data.keyCount() - 1; i >= 0; --i) { |
3396 | int k = mobj->d.data[data.data() + 2 * i + 1]; |
3397 | if ((k != 0 && (v & k) == k) || (k == value)) { |
3398 | v = v & ~k; |
3399 | parts.push_back(t: stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2 * i])); |
3400 | } |
3401 | } |
3402 | join_reversed(s&: keys, c: parts, sep: '|'); |
3403 | return keys; |
3404 | } |
3405 | |
3406 | /*! |
3407 | \internal |
3408 | */ |
3409 | QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index) |
3410 | : mobj(mobj), data({ .d: mobj->d.data + priv(data: mobj->d.data)->enumeratorData + index * Data::Size }) |
3411 | { |
3412 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount); |
3413 | } |
3414 | |
3415 | int QMetaEnum::Data::index(const QMetaObject *mobj) const |
3416 | { |
3417 | return (d - mobj->d.data - priv(data: mobj->d.data)->enumeratorData) / Size; |
3418 | } |
3419 | |
3420 | /*! |
3421 | \fn template<typename T> QMetaEnum QMetaEnum::fromType() |
3422 | \since 5.5 |
3423 | |
3424 | Returns the QMetaEnum corresponding to the type in the template parameter. |
3425 | The enum needs to be declared with Q_ENUM. |
3426 | */ |
3427 | |
3428 | /*! |
3429 | \class QMetaProperty |
3430 | \inmodule QtCore |
3431 | \brief The QMetaProperty class provides meta-data about a property. |
3432 | |
3433 | \ingroup objectmodel |
3434 | |
3435 | Property meta-data is obtained from an object's meta-object. See |
3436 | QMetaObject::property() and QMetaObject::propertyCount() for |
3437 | details. |
3438 | |
3439 | \section1 Property Meta-Data |
3440 | |
3441 | A property has a name() and a metaType(), as well as various |
3442 | attributes that specify its behavior: isReadable(), isWritable(), |
3443 | isDesignable(), isScriptable(), revision(), and isStored(). |
3444 | |
3445 | If the property is an enumeration, isEnumType() returns \c true; if the |
3446 | property is an enumeration that is also a flag (i.e. its values |
3447 | can be combined using the OR operator), isEnumType() and |
3448 | isFlagType() both return true. The enumerator for these types is |
3449 | available from enumerator(). |
3450 | |
3451 | The property's values are set and retrieved with read(), write(), |
3452 | and reset(); they can also be changed through QObject's set and get |
3453 | functions. See QObject::setProperty() and QObject::property() for |
3454 | details. |
3455 | |
3456 | \section1 Copying and Assignment |
3457 | |
3458 | QMetaProperty objects can be copied by value. However, each copy will |
3459 | refer to the same underlying property meta-data. |
3460 | |
3461 | \sa QMetaObject, QMetaEnum, QMetaMethod, {Qt's Property System} |
3462 | */ |
3463 | |
3464 | /*! |
3465 | \fn bool QMetaProperty::isValid() const |
3466 | |
3467 | Returns \c true if this property is valid (readable); otherwise |
3468 | returns \c false. |
3469 | |
3470 | \sa isReadable() |
3471 | */ |
3472 | |
3473 | /*! |
3474 | \fn const QMetaObject *QMetaProperty::enclosingMetaObject() const |
3475 | \internal |
3476 | */ |
3477 | |
3478 | /*! |
3479 | \fn QMetaProperty::QMetaProperty() |
3480 | \internal |
3481 | */ |
3482 | |
3483 | /*! |
3484 | Returns this property's name. |
3485 | |
3486 | \sa type(), typeName() |
3487 | */ |
3488 | const char *QMetaProperty::name() const |
3489 | { |
3490 | if (!mobj) |
3491 | return nullptr; |
3492 | return rawStringData(mo: mobj, index: data.name()); |
3493 | } |
3494 | |
3495 | /*! |
3496 | Returns the name of this property's type. |
3497 | |
3498 | \sa type(), name() |
3499 | */ |
3500 | const char *QMetaProperty::typeName() const |
3501 | { |
3502 | if (!mobj) |
3503 | return nullptr; |
3504 | // TODO: can the metatype be invalid for dynamic metaobjects? |
3505 | if (const auto mt = metaType(); mt.isValid()) |
3506 | return mt.name(); |
3507 | return typeNameFromTypeInfo(mo: mobj, typeInfo: data.type()).constData(); |
3508 | } |
3509 | |
3510 | /*! \fn QVariant::Type QMetaProperty::type() const |
3511 | \deprecated |
3512 | |
3513 | Returns this property's type. The return value is one |
3514 | of the values of the QVariant::Type enumeration. |
3515 | |
3516 | \sa typeName(), name(), metaType() |
3517 | */ |
3518 | |
3519 | /*! \fn int QMetaProperty::userType() const |
3520 | \since 4.2 |
3521 | |
3522 | Returns this property's user type. The return value is one |
3523 | of the values that are registered with QMetaType. |
3524 | |
3525 | This is equivalent to metaType().id() |
3526 | |
3527 | \sa type(), QMetaType, typeName(), metaType() |
3528 | */ |
3529 | |
3530 | /*! \fn int QMetaProperty::typeId() const |
3531 | \since 6.0 |
3532 | |
3533 | Returns the storage type of the property. This is |
3534 | the same as metaType().id(). |
3535 | |
3536 | \sa QMetaType, typeName(), metaType() |
3537 | */ |
3538 | |
3539 | /*! |
3540 | \since 6.0 |
3541 | |
3542 | Returns this property's QMetaType. |
3543 | |
3544 | \sa QMetaType |
3545 | */ |
3546 | QMetaType QMetaProperty::metaType() const |
3547 | { |
3548 | if (!mobj) |
3549 | return {}; |
3550 | return QMetaType(mobj->d.metaTypes[data.index(mobj)]); |
3551 | } |
3552 | |
3553 | int QMetaProperty::Data::index(const QMetaObject *mobj) const |
3554 | { |
3555 | return (d - mobj->d.data - priv(data: mobj->d.data)->propertyData) / Size; |
3556 | } |
3557 | |
3558 | /*! |
3559 | \since 4.6 |
3560 | |
3561 | Returns this property's index. |
3562 | */ |
3563 | int QMetaProperty::propertyIndex() const |
3564 | { |
3565 | if (!mobj) |
3566 | return -1; |
3567 | return data.index(mobj) + mobj->propertyOffset(); |
3568 | } |
3569 | |
3570 | /*! |
3571 | \since 5.14 |
3572 | |
3573 | Returns this property's index relative within the enclosing meta object. |
3574 | */ |
3575 | int QMetaProperty::relativePropertyIndex() const |
3576 | { |
3577 | if (!mobj) |
3578 | return -1; |
3579 | return data.index(mobj); |
3580 | } |
3581 | |
3582 | /*! |
3583 | Returns \c true if the property's type is an enumeration value that |
3584 | is used as a flag; otherwise returns \c false. |
3585 | |
3586 | Flags can be combined using the OR operator. A flag type is |
3587 | implicitly also an enum type. |
3588 | |
3589 | \sa isEnumType(), enumerator(), QMetaEnum::isFlag() |
3590 | */ |
3591 | |
3592 | bool QMetaProperty::isFlagType() const |
3593 | { |
3594 | return isEnumType() && menum.isFlag(); |
3595 | } |
3596 | |
3597 | /*! |
3598 | Returns \c true if the property's type is an enumeration value; |
3599 | otherwise returns \c false. |
3600 | |
3601 | \sa enumerator(), isFlagType() |
3602 | */ |
3603 | bool QMetaProperty::isEnumType() const |
3604 | { |
3605 | if (!mobj) |
3606 | return false; |
3607 | return (data.flags() & EnumOrFlag) && menum.name(); |
3608 | } |
3609 | |
3610 | /*! |
3611 | \internal |
3612 | |
3613 | Returns \c true if the property has a C++ setter function that |
3614 | follows Qt's standard "name" / "setName" pattern. Designer and uic |
3615 | query hasStdCppSet() in order to avoid expensive |
3616 | QObject::setProperty() calls. All properties in Qt [should] follow |
3617 | this pattern. |
3618 | */ |
3619 | bool QMetaProperty::hasStdCppSet() const |
3620 | { |
3621 | if (!mobj) |
3622 | return false; |
3623 | return (data.flags() & StdCppSet); |
3624 | } |
3625 | |
3626 | /*! |
3627 | \internal |
3628 | |
3629 | Returns \c true if the property is an alias. |
3630 | This is for instance true for a property declared in QML |
3631 | as 'property alias'. |
3632 | */ |
3633 | bool QMetaProperty::isAlias() const |
3634 | { |
3635 | if (!mobj) |
3636 | return false; |
3637 | return (data.flags() & Alias); |
3638 | } |
3639 | |
3640 | #if QT_DEPRECATED_SINCE(6, 4) |
3641 | /*! |
3642 | \internal |
3643 | Historically: |
3644 | Executes metacall with QMetaObject::RegisterPropertyMetaType flag. |
3645 | Returns id of registered type or QMetaType::UnknownType if a type |
3646 | could not be registered for any reason. |
3647 | Obsolete since Qt 6 |
3648 | */ |
3649 | int QMetaProperty::registerPropertyType() const |
3650 | { |
3651 | return typeId(); |
3652 | } |
3653 | #endif |
3654 | |
3655 | QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index) |
3656 | : mobj(mobj), |
3657 | data(getMetaPropertyData(mobj, index)) |
3658 | { |
3659 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->propertyCount); |
3660 | // The code below here just resolves menum if the property is an enum type: |
3661 | if (!(data.flags() & EnumOrFlag) || !metaType().flags().testFlag(flag: QMetaType::IsEnumeration)) |
3662 | return; |
3663 | QByteArrayView enum_name = typeNameFromTypeInfo(mo: mobj, typeInfo: data.type()); |
3664 | menum = mobj->enumerator(index: QMetaObjectPrivate::indexOfEnumerator(m: mobj, name: enum_name)); |
3665 | if (menum.isValid()) |
3666 | return; |
3667 | |
3668 | QByteArrayView scope_name; |
3669 | const auto parsed = parse_scope(qualifiedKey: enum_name); |
3670 | if (parsed.scope) { |
3671 | scope_name = *parsed.scope; |
3672 | enum_name = parsed.key; |
3673 | } else { |
3674 | scope_name = objectClassName(m: mobj); |
3675 | } |
3676 | |
3677 | const QMetaObject *scope = nullptr; |
3678 | if (scope_name == "Qt" ) |
3679 | scope = &Qt::staticMetaObject; |
3680 | else |
3681 | scope = QMetaObject_findMetaObject(self: mobj, name: QByteArrayView(scope_name)); |
3682 | |
3683 | if (scope) |
3684 | menum = scope->enumerator(index: QMetaObjectPrivate::indexOfEnumerator(m: scope, name: enum_name)); |
3685 | } |
3686 | |
3687 | /*! |
3688 | \internal |
3689 | Constructs the \c QMetaProperty::Data for the \a index th property of \a mobj |
3690 | */ |
3691 | QMetaProperty::Data QMetaProperty::getMetaPropertyData(const QMetaObject *mobj, int index) |
3692 | { |
3693 | return { .d: mobj->d.data + priv(data: mobj->d.data)->propertyData + index * Data::Size }; |
3694 | } |
3695 | |
3696 | /*! |
3697 | Returns the enumerator if this property's type is an enumerator |
3698 | type; otherwise the returned value is undefined. |
3699 | |
3700 | \sa isEnumType(), isFlagType() |
3701 | */ |
3702 | QMetaEnum QMetaProperty::enumerator() const |
3703 | { |
3704 | return menum; |
3705 | } |
3706 | |
3707 | /*! |
3708 | Reads the property's value from the given \a object. Returns the value |
3709 | if it was able to read it; otherwise returns an invalid variant. |
3710 | |
3711 | \sa write(), reset(), isReadable() |
3712 | */ |
3713 | QVariant QMetaProperty::read(const QObject *object) const |
3714 | { |
3715 | if (!object || !mobj) |
3716 | return QVariant(); |
3717 | |
3718 | // the status variable is changed by qt_metacall to indicate what it did |
3719 | // this feature is currently only used by Qt D-Bus and should not be depended |
3720 | // upon. Don't change it without looking into QDBusAbstractInterface first |
3721 | // -1 (unchanged): normal qt_metacall, result stored in argv[0] |
3722 | // changed: result stored directly in value |
3723 | int status = -1; |
3724 | QVariant value; |
3725 | void *argv[] = { nullptr, &value, &status }; |
3726 | QMetaType t(mobj->d.metaTypes[data.index(mobj)]); |
3727 | if (t == QMetaType::fromType<QVariant>()) { |
3728 | argv[0] = &value; |
3729 | } else { |
3730 | value = QVariant(t, nullptr); |
3731 | argv[0] = value.data(); |
3732 | } |
3733 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) { |
3734 | mobj->d.static_metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty, data.index(mobj), argv); |
3735 | } else { |
3736 | QMetaObject::metacall(object: const_cast<QObject*>(object), cl: QMetaObject::ReadProperty, |
3737 | idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3738 | } |
3739 | |
3740 | if (status != -1) |
3741 | return value; |
3742 | if (t != QMetaType::fromType<QVariant>() && argv[0] != value.data()) |
3743 | // pointer or reference |
3744 | return QVariant(t, argv[0]); |
3745 | return value; |
3746 | } |
3747 | |
3748 | /*! |
3749 | Writes \a value as the property's value to the given \a object. Returns |
3750 | true if the write succeeded; otherwise returns \c false. |
3751 | |
3752 | If \a value is not of the same type as the property, a conversion |
3753 | is attempted. An empty QVariant() is equivalent to a call to reset() |
3754 | if this property is resettable, or setting a default-constructed object |
3755 | otherwise. |
3756 | |
3757 | \note This function internally makes a copy of \a value. Prefer to use the |
3758 | rvalue overload when possible. |
3759 | |
3760 | \sa read(), reset(), isWritable() |
3761 | */ |
3762 | bool QMetaProperty::write(QObject *object, const QVariant &value) const |
3763 | { |
3764 | if (!object || !isWritable()) |
3765 | return false; |
3766 | return write(obj: object, value: QVariant(value)); |
3767 | } |
3768 | |
3769 | /*! |
3770 | \overload |
3771 | \since 6.6 |
3772 | */ |
3773 | bool QMetaProperty::write(QObject *object, QVariant &&v) const |
3774 | { |
3775 | if (!object || !isWritable()) |
3776 | return false; |
3777 | QMetaType t(mobj->d.metaTypes[data.index(mobj)]); |
3778 | if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) { |
3779 | if (isEnumType() && !t.metaObject() && v.metaType() == QMetaType::fromType<QString>()) { |
3780 | // Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM) |
3781 | // means the QMetaType has no associated QMetaObject, so it can't |
3782 | // do the conversion (see qmetatype.cpp:convertToEnum()). |
3783 | bool ok; |
3784 | if (isFlagType()) |
3785 | v = QVariant(menum.keysToValue(keys: v.toByteArray(), ok: &ok)); |
3786 | else |
3787 | v = QVariant(menum.keyToValue(key: v.toByteArray(), ok: &ok)); |
3788 | if (!ok) |
3789 | return false; |
3790 | } |
3791 | if (!v.isValid()) { |
3792 | if (isResettable()) |
3793 | return reset(obj: object); |
3794 | v = QVariant(t, nullptr); |
3795 | } else if (!v.convert(type: t)) { |
3796 | return false; |
3797 | } |
3798 | } |
3799 | // the status variable is changed by qt_metacall to indicate what it did |
3800 | // this feature is currently only used by Qt D-Bus and should not be depended |
3801 | // upon. Don't change it without looking into QDBusAbstractInterface first |
3802 | // -1 (unchanged): normal qt_metacall, result stored in argv[0] |
3803 | // changed: result stored directly in value, return the value of status |
3804 | int status = -1; |
3805 | // the flags variable is used by the declarative module to implement |
3806 | // interception of property writes. |
3807 | int flags = 0; |
3808 | void *argv[] = { nullptr, &v, &status, &flags }; |
3809 | if (t == QMetaType::fromType<QVariant>()) |
3810 | argv[0] = &v; |
3811 | else |
3812 | argv[0] = v.data(); |
3813 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) |
3814 | mobj->d.static_metacall(object, QMetaObject::WriteProperty, data.index(mobj), argv); |
3815 | else |
3816 | QMetaObject::metacall(object, cl: QMetaObject::WriteProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3817 | |
3818 | return status; |
3819 | } |
3820 | |
3821 | /*! |
3822 | Resets the property for the given \a object with a reset method. |
3823 | Returns \c true if the reset worked; otherwise returns \c false. |
3824 | |
3825 | Reset methods are optional; only a few properties support them. |
3826 | |
3827 | \sa read(), write() |
3828 | */ |
3829 | bool QMetaProperty::reset(QObject *object) const |
3830 | { |
3831 | if (!object || !mobj || !isResettable()) |
3832 | return false; |
3833 | void *argv[] = { nullptr }; |
3834 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) |
3835 | mobj->d.static_metacall(object, QMetaObject::ResetProperty, data.index(mobj), argv); |
3836 | else |
3837 | QMetaObject::metacall(object, cl: QMetaObject::ResetProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3838 | return true; |
3839 | } |
3840 | |
3841 | /*! |
3842 | \since 6.0 |
3843 | Returns the bindable interface for the property on a given \a object. |
3844 | |
3845 | If the property doesn't support bindings, the returned interface will be |
3846 | invalid. |
3847 | |
3848 | \sa QObjectBindableProperty, QProperty, isBindable() |
3849 | */ |
3850 | QUntypedBindable QMetaProperty::bindable(QObject *object) const |
3851 | { |
3852 | QUntypedBindable bindable; |
3853 | void * argv[1] { &bindable }; |
3854 | mobj->metacall(object, cl: QMetaObject::BindableProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3855 | return bindable; |
3856 | } |
3857 | /*! |
3858 | \since 5.5 |
3859 | |
3860 | Reads the property's value from the given \a gadget. Returns the value |
3861 | if it was able to read it; otherwise returns an invalid variant. |
3862 | |
3863 | This function should only be used if this is a property of a Q_GADGET |
3864 | */ |
3865 | QVariant QMetaProperty::readOnGadget(const void *gadget) const |
3866 | { |
3867 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3868 | return read(object: reinterpret_cast<const QObject*>(gadget)); |
3869 | } |
3870 | |
3871 | /*! |
3872 | \since 5.5 |
3873 | |
3874 | Writes \a value as the property's value to the given \a gadget. Returns |
3875 | true if the write succeeded; otherwise returns \c false. |
3876 | |
3877 | This function should only be used if this is a property of a Q_GADGET |
3878 | */ |
3879 | bool QMetaProperty::writeOnGadget(void *gadget, const QVariant &value) const |
3880 | { |
3881 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3882 | return write(object: reinterpret_cast<QObject*>(gadget), value); |
3883 | } |
3884 | |
3885 | /*! |
3886 | \overload |
3887 | \since 6.6 |
3888 | */ |
3889 | bool QMetaProperty::writeOnGadget(void *gadget, QVariant &&value) const |
3890 | { |
3891 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3892 | return write(object: reinterpret_cast<QObject*>(gadget), v: std::move(value)); |
3893 | } |
3894 | |
3895 | /*! |
3896 | \since 5.5 |
3897 | |
3898 | Resets the property for the given \a gadget with a reset method. |
3899 | Returns \c true if the reset worked; otherwise returns \c false. |
3900 | |
3901 | Reset methods are optional; only a few properties support them. |
3902 | |
3903 | This function should only be used if this is a property of a Q_GADGET |
3904 | */ |
3905 | bool QMetaProperty::resetOnGadget(void *gadget) const |
3906 | { |
3907 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3908 | return reset(object: reinterpret_cast<QObject*>(gadget)); |
3909 | } |
3910 | |
3911 | /*! |
3912 | Returns \c true if this property can be reset to a default value; otherwise |
3913 | returns \c false. |
3914 | |
3915 | \sa reset() |
3916 | */ |
3917 | bool QMetaProperty::isResettable() const |
3918 | { |
3919 | if (!mobj) |
3920 | return false; |
3921 | return data.flags() & Resettable; |
3922 | } |
3923 | |
3924 | /*! |
3925 | Returns \c true if this property is readable; otherwise returns \c false. |
3926 | |
3927 | \sa isWritable(), read(), isValid() |
3928 | */ |
3929 | bool QMetaProperty::isReadable() const |
3930 | { |
3931 | if (!mobj) |
3932 | return false; |
3933 | return data.flags() & Readable; |
3934 | } |
3935 | |
3936 | /*! |
3937 | Returns \c true if this property has a corresponding change notify signal; |
3938 | otherwise returns \c false. |
3939 | |
3940 | \sa notifySignal() |
3941 | */ |
3942 | bool QMetaProperty::hasNotifySignal() const |
3943 | { |
3944 | if (!mobj) |
3945 | return false; |
3946 | return data.notifyIndex() != uint(-1); |
3947 | } |
3948 | |
3949 | /*! |
3950 | \since 4.5 |
3951 | |
3952 | Returns the QMetaMethod instance of the property change notifying signal if |
3953 | one was specified, otherwise returns an invalid QMetaMethod. |
3954 | |
3955 | \sa hasNotifySignal() |
3956 | */ |
3957 | QMetaMethod QMetaProperty::notifySignal() const |
3958 | { |
3959 | int id = notifySignalIndex(); |
3960 | if (id != -1) |
3961 | return mobj->method(index: id); |
3962 | else |
3963 | return QMetaMethod(); |
3964 | } |
3965 | |
3966 | /*! |
3967 | \since 4.6 |
3968 | |
3969 | Returns the index of the property change notifying signal if one was |
3970 | specified, otherwise returns -1. |
3971 | |
3972 | \sa hasNotifySignal() |
3973 | */ |
3974 | int QMetaProperty::notifySignalIndex() const |
3975 | { |
3976 | if (!mobj || data.notifyIndex() == std::numeric_limits<uint>::max()) |
3977 | return -1; |
3978 | uint methodIndex = data.notifyIndex(); |
3979 | if (!(methodIndex & IsUnresolvedSignal)) |
3980 | return methodIndex + mobj->methodOffset(); |
3981 | methodIndex &= ~IsUnresolvedSignal; |
3982 | const QByteArray signalName = stringData(mo: mobj, index: methodIndex); |
3983 | const QMetaObject *m = mobj; |
3984 | // try 0-arg signal |
3985 | int idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(baseObject: &m, name: signalName, argc: 0, types: nullptr); |
3986 | if (idx >= 0) |
3987 | return idx + m->methodOffset(); |
3988 | // try 1-arg signal |
3989 | QArgumentType argType(typeId()); |
3990 | idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(baseObject: &m, name: signalName, argc: 1, types: &argType); |
3991 | if (idx >= 0) |
3992 | return idx + m->methodOffset(); |
3993 | qWarning(msg: "QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'" , |
3994 | signalName.constData(), mobj->className(), name()); |
3995 | return -1; |
3996 | } |
3997 | |
3998 | // This method has been around for a while, but the documentation was marked \internal until 5.1 |
3999 | /*! |
4000 | \since 5.1 |
4001 | |
4002 | Returns the property revision if one was specified by Q_REVISION, otherwise |
4003 | returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded |
4004 | using QTypeRevision::fromEncodedVersion(). |
4005 | */ |
4006 | int QMetaProperty::revision() const |
4007 | { |
4008 | if (!mobj) |
4009 | return 0; |
4010 | return data.revision(); |
4011 | } |
4012 | |
4013 | /*! |
4014 | Returns \c true if this property is writable; otherwise returns |
4015 | false. |
4016 | |
4017 | \sa isReadable(), write() |
4018 | */ |
4019 | bool QMetaProperty::isWritable() const |
4020 | { |
4021 | if (!mobj) |
4022 | return false; |
4023 | return data.flags() & Writable; |
4024 | } |
4025 | |
4026 | /*! |
4027 | Returns \c false if the \c{Q_PROPERTY()}'s \c DESIGNABLE attribute |
4028 | is false; otherwise returns \c true. |
4029 | |
4030 | \sa isScriptable(), isStored() |
4031 | */ |
4032 | bool QMetaProperty::isDesignable() const |
4033 | { |
4034 | if (!mobj) |
4035 | return false; |
4036 | return data.flags() & Designable; |
4037 | } |
4038 | |
4039 | /*! |
4040 | Returns \c false if the \c{Q_PROPERTY()}'s \c SCRIPTABLE attribute |
4041 | is false; otherwise returns true. |
4042 | |
4043 | \sa isDesignable(), isStored() |
4044 | */ |
4045 | bool QMetaProperty::isScriptable() const |
4046 | { |
4047 | if (!mobj) |
4048 | return false; |
4049 | return data.flags() & Scriptable; |
4050 | } |
4051 | |
4052 | /*! |
4053 | Returns \c true if the property is stored; otherwise returns |
4054 | false. |
4055 | |
4056 | The function returns \c false if the |
4057 | \c{Q_PROPERTY()}'s \c STORED attribute is false; otherwise returns |
4058 | true. |
4059 | |
4060 | \sa isDesignable(), isScriptable() |
4061 | */ |
4062 | bool QMetaProperty::isStored() const |
4063 | { |
4064 | if (!mobj) |
4065 | return false; |
4066 | return data.flags() & Stored; |
4067 | } |
4068 | |
4069 | /*! |
4070 | Returns \c false if the \c {Q_PROPERTY()}'s \c USER attribute is false. |
4071 | Otherwise it returns true, indicating the property is designated as the |
4072 | \c USER property, i.e., the one that the user can edit or |
4073 | that is significant in some other way. |
4074 | |
4075 | \sa QMetaObject::userProperty(), isDesignable(), isScriptable() |
4076 | */ |
4077 | bool QMetaProperty::isUser() const |
4078 | { |
4079 | if (!mobj) |
4080 | return false; |
4081 | return data.flags() & User; |
4082 | } |
4083 | |
4084 | /*! |
4085 | \since 4.6 |
4086 | Returns \c true if the property is constant; otherwise returns \c false. |
4087 | |
4088 | A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute |
4089 | is set. |
4090 | */ |
4091 | bool QMetaProperty::isConstant() const |
4092 | { |
4093 | if (!mobj) |
4094 | return false; |
4095 | return data.flags() & Constant; |
4096 | } |
4097 | |
4098 | /*! |
4099 | \since 4.6 |
4100 | Returns \c true if the property is final; otherwise returns \c false. |
4101 | |
4102 | A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute |
4103 | is set. |
4104 | */ |
4105 | bool QMetaProperty::isFinal() const |
4106 | { |
4107 | if (!mobj) |
4108 | return false; |
4109 | return data.flags() & Final; |
4110 | } |
4111 | |
4112 | /*! |
4113 | \since 5.15 |
4114 | Returns \c true if the property is required; otherwise returns \c false. |
4115 | |
4116 | A property is final if the \c{Q_PROPERTY()}'s \c REQUIRED attribute |
4117 | is set. |
4118 | */ |
4119 | bool QMetaProperty::isRequired() const |
4120 | { |
4121 | if (!mobj) |
4122 | return false; |
4123 | return data.flags() & Required; |
4124 | } |
4125 | |
4126 | /*! |
4127 | \since 6.0 |
4128 | Returns \c true if the \c{Q_PROPERTY()} exposes binding functionality; otherwise returns false. |
4129 | |
4130 | This implies that you can create bindings that use this property as a dependency or install QPropertyObserver |
4131 | objects on this property. Unless the property is readonly, you can also set a binding on this property. |
4132 | |
4133 | \sa QProperty, isWritable(), bindable() |
4134 | */ |
4135 | bool QMetaProperty::isBindable() const |
4136 | { |
4137 | if (!mobj) |
4138 | return false; |
4139 | return (data.flags() & Bindable); |
4140 | } |
4141 | |
4142 | /*! |
4143 | \class QMetaClassInfo |
4144 | \inmodule QtCore |
4145 | |
4146 | \brief The QMetaClassInfo class provides additional information |
4147 | about a class. |
4148 | |
4149 | \ingroup objectmodel |
4150 | |
4151 | Class information items are simple \e{name}--\e{value} pairs that |
4152 | are specified using Q_CLASSINFO() in the source code. The |
4153 | information can be retrieved using name() and value(). For example: |
4154 | |
4155 | \snippet code/src_corelib_kernel_qmetaobject.cpp 5 |
4156 | |
4157 | This mechanism is free for you to use in your Qt applications. |
4158 | |
4159 | \note It's also used by the \l[ActiveQt]{Active Qt}, |
4160 | \l[QtDBus]{Qt D-Bus}, \l[QtQml]{Qt Qml}, and \l{Qt Remote Objects} |
4161 | modules. Some keys might be set when using these modules. |
4162 | |
4163 | \sa QMetaObject |
4164 | */ |
4165 | |
4166 | /*! |
4167 | \fn QMetaClassInfo::QMetaClassInfo() |
4168 | \internal |
4169 | */ |
4170 | |
4171 | /*! |
4172 | \fn const QMetaObject *QMetaClassInfo::enclosingMetaObject() const |
4173 | \internal |
4174 | */ |
4175 | |
4176 | /*! |
4177 | Returns the name of this item. |
4178 | |
4179 | \sa value() |
4180 | */ |
4181 | const char *QMetaClassInfo::name() const |
4182 | { |
4183 | if (!mobj) |
4184 | return nullptr; |
4185 | return rawStringData(mo: mobj, index: data.name()); |
4186 | } |
4187 | |
4188 | /*! |
4189 | Returns the value of this item. |
4190 | |
4191 | \sa name() |
4192 | */ |
4193 | const char *QMetaClassInfo::value() const |
4194 | { |
4195 | if (!mobj) |
4196 | return nullptr; |
4197 | return rawStringData(mo: mobj, index: data.value()); |
4198 | } |
4199 | |
4200 | /*! |
4201 | \class QMethodRawArguments |
4202 | \internal |
4203 | |
4204 | A wrapper class for the void ** arguments array used by the meta |
4205 | object system. If a slot uses a single argument of this type, |
4206 | the meta object system will pass the raw arguments array directly |
4207 | to the slot and set the arguments count in the slot description to |
4208 | zero, so that any signal can connect to it. |
4209 | |
4210 | This is used internally to implement signal relay functionality in |
4211 | our state machine and dbus. |
4212 | */ |
4213 | |
4214 | /*! |
4215 | \macro QMetaMethodArgument Q_ARG(Type, const Type &value) |
4216 | \relates QMetaObject |
4217 | |
4218 | This macro takes a \a Type and a \a value of that type and |
4219 | returns a QMetaMethodArgument, which can be passed to the template |
4220 | QMetaObject::invokeMethod() with the \c {Args &&...} arguments. |
4221 | |
4222 | \sa Q_RETURN_ARG() |
4223 | */ |
4224 | |
4225 | /*! |
4226 | \macro QMetaMethodReturnArgument Q_RETURN_ARG(Type, Type &value) |
4227 | \relates QMetaObject |
4228 | |
4229 | This macro takes a \a Type and a non-const reference to a \a |
4230 | value of that type and returns a QMetaMethodReturnArgument, which can be |
4231 | passed to the template QMetaObject::invokeMethod() with the \c {Args &&...} |
4232 | arguments. |
4233 | |
4234 | \sa Q_ARG() |
4235 | */ |
4236 | |
4237 | /*! |
4238 | \class QGenericArgument |
4239 | \inmodule QtCore |
4240 | |
4241 | \brief The QGenericArgument class is an internal helper class for |
4242 | marshalling arguments. |
4243 | |
4244 | This class should never be used directly. Please use the \l Q_ARG() |
4245 | macro instead. |
4246 | |
4247 | \sa Q_ARG(), QMetaObject::invokeMethod(), QGenericReturnArgument |
4248 | */ |
4249 | |
4250 | /*! |
4251 | \fn QGenericArgument::QGenericArgument(const char *name, const void *data) |
4252 | |
4253 | Constructs a QGenericArgument object with the given \a name and \a data. |
4254 | */ |
4255 | |
4256 | /*! |
4257 | \fn QGenericArgument::data () const |
4258 | |
4259 | Returns the data set in the constructor. |
4260 | */ |
4261 | |
4262 | /*! |
4263 | \fn QGenericArgument::name () const |
4264 | |
4265 | Returns the name set in the constructor. |
4266 | */ |
4267 | |
4268 | /*! |
4269 | \class QGenericReturnArgument |
4270 | \inmodule QtCore |
4271 | |
4272 | \brief The QGenericReturnArgument class is an internal helper class for |
4273 | marshalling arguments. |
4274 | |
4275 | This class should never be used directly. Please use the |
4276 | Q_RETURN_ARG() macro instead. |
4277 | |
4278 | \sa Q_RETURN_ARG(), QMetaObject::invokeMethod(), QGenericArgument |
4279 | */ |
4280 | |
4281 | /*! |
4282 | \fn QGenericReturnArgument::QGenericReturnArgument(const char *name, void *data) |
4283 | |
4284 | Constructs a QGenericReturnArgument object with the given \a name |
4285 | and \a data. |
4286 | */ |
4287 | |
4288 | /*! |
4289 | \internal |
4290 | If the local_method_index is a cloned method, return the index of the original. |
4291 | |
4292 | Example: if the index of "destroyed()" is passed, the index of "destroyed(QObject*)" is returned |
4293 | */ |
4294 | int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index) |
4295 | { |
4296 | Q_ASSERT(local_method_index < get(mobj)->methodCount); |
4297 | while (QMetaMethod::fromRelativeMethodIndex(mobj, index: local_method_index).data.flags() & MethodCloned) { |
4298 | Q_ASSERT(local_method_index > 0); |
4299 | --local_method_index; |
4300 | } |
4301 | return local_method_index; |
4302 | } |
4303 | |
4304 | /*! |
4305 | \internal |
4306 | |
4307 | Returns the parameter type names extracted from the given \a signature. |
4308 | */ |
4309 | QList<QByteArray> QMetaObjectPrivate::parameterTypeNamesFromSignature(const char *signature) |
4310 | { |
4311 | QList<QByteArray> list; |
4312 | while (*signature && *signature != '(') |
4313 | ++signature; |
4314 | while (*signature && *signature != ')' && *++signature != ')') { |
4315 | const char *begin = signature; |
4316 | int level = 0; |
4317 | while (*signature && (level > 0 || *signature != ',') && *signature != ')') { |
4318 | if (*signature == '<') |
4319 | ++level; |
4320 | else if (*signature == '>') |
4321 | --level; |
4322 | ++signature; |
4323 | } |
4324 | list += QByteArray(begin, signature - begin); |
4325 | } |
4326 | return list; |
4327 | } |
4328 | |
4329 | QT_END_NAMESPACE |
4330 | |