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 | deleteLater() slot and a 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 | name() 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 | |
1791 | Swaps this Connection instance with \a other. This operation is very fast |
1792 | and never fails. |
1793 | */ |
1794 | |
1795 | /*! |
1796 | \class QMetaMethod |
1797 | \inmodule QtCore |
1798 | |
1799 | \brief The QMetaMethod class provides meta-data about a member |
1800 | function. |
1801 | |
1802 | \ingroup objectmodel |
1803 | \compares equality |
1804 | |
1805 | A QMetaMethod has a methodType(), a methodSignature(), a list of |
1806 | parameterTypes() and parameterNames(), a return typeName(), a |
1807 | tag(), and an access() specifier. You can use invoke() to invoke |
1808 | the method on an arbitrary QObject. |
1809 | |
1810 | \sa QMetaObject, QMetaEnum, QMetaProperty, {Qt's Property System} |
1811 | */ |
1812 | |
1813 | /*! |
1814 | \enum QMetaMethod::Attributes |
1815 | |
1816 | \internal |
1817 | |
1818 | \value Compatibility |
1819 | \value Cloned |
1820 | \value Scriptable |
1821 | */ |
1822 | |
1823 | /*! |
1824 | \fn bool QMetaMethod::isValid() const |
1825 | \since 5.0 |
1826 | |
1827 | Returns \c true if this method is valid (can be introspected and |
1828 | invoked), otherwise returns \c false. |
1829 | */ |
1830 | |
1831 | /*! \fn bool QMetaMethod::operator==(const QMetaMethod &lhs, const QMetaMethod &rhs) |
1832 | \since 5.0 |
1833 | \overload |
1834 | |
1835 | Returns \c true if method \a lhs is equal to method \a rhs, |
1836 | otherwise returns \c false. |
1837 | */ |
1838 | |
1839 | /*! \fn bool QMetaMethod::operator!=(const QMetaMethod &lhs, const QMetaMethod &rhs) |
1840 | \since 5.0 |
1841 | \overload |
1842 | |
1843 | Returns \c true if method \a lhs is not equal to method \a rhs, |
1844 | otherwise returns \c false. |
1845 | */ |
1846 | |
1847 | /*! |
1848 | \fn const QMetaObject *QMetaMethod::enclosingMetaObject() const |
1849 | \internal |
1850 | */ |
1851 | |
1852 | /*! |
1853 | \enum QMetaMethod::MethodType |
1854 | |
1855 | \value Method The function is a plain member function. |
1856 | \value Signal The function is a signal. |
1857 | \value Slot The function is a slot. |
1858 | \value Constructor The function is a constructor. |
1859 | */ |
1860 | |
1861 | /*! |
1862 | \fn QMetaMethod::QMetaMethod() |
1863 | \internal |
1864 | */ |
1865 | |
1866 | /*! |
1867 | \internal |
1868 | */ |
1869 | QMetaMethod QMetaMethod::fromRelativeMethodIndex(const QMetaObject *mobj, int index) |
1870 | { |
1871 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->methodCount); |
1872 | QMetaMethod m; |
1873 | m.mobj = mobj; |
1874 | m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->methodData + index * Data::Size }; |
1875 | return m; |
1876 | } |
1877 | |
1878 | QMetaMethod QMetaMethod::fromRelativeConstructorIndex(const QMetaObject *mobj, int index) |
1879 | { |
1880 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->constructorCount); |
1881 | QMetaMethod m; |
1882 | m.mobj = mobj; |
1883 | m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->constructorData + index * Data::Size }; |
1884 | return m; |
1885 | } |
1886 | |
1887 | /*! |
1888 | \macro Q_METAMETHOD_INVOKE_MAX_ARGS |
1889 | \relates QMetaMethod |
1890 | |
1891 | Equals maximum number of arguments available for |
1892 | execution of the method via QMetaMethod::invoke() |
1893 | */ |
1894 | |
1895 | QByteArray QMetaMethodPrivate::signature() const |
1896 | { |
1897 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1898 | QByteArray result; |
1899 | result.reserve(asize: 256); |
1900 | result += name(); |
1901 | result += '('; |
1902 | QList<QByteArray> argTypes = parameterTypes(); |
1903 | for (int i = 0; i < argTypes.size(); ++i) { |
1904 | if (i) |
1905 | result += ','; |
1906 | result += argTypes.at(i); |
1907 | } |
1908 | result += ')'; |
1909 | return result; |
1910 | } |
1911 | |
1912 | QByteArray QMetaMethodPrivate::name() const |
1913 | { |
1914 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1915 | return stringData(mo: mobj, index: data.name()); |
1916 | } |
1917 | |
1918 | int QMetaMethodPrivate::typesDataIndex() const |
1919 | { |
1920 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1921 | return data.parameters(); |
1922 | } |
1923 | |
1924 | const char *QMetaMethodPrivate::rawReturnTypeName() const |
1925 | { |
1926 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1927 | uint typeInfo = mobj->d.data[typesDataIndex()]; |
1928 | if (typeInfo & IsUnresolvedType) |
1929 | return rawStringData(mo: mobj, index: typeInfo & TypeNameIndexMask); |
1930 | else |
1931 | return QMetaType(typeInfo).name(); |
1932 | } |
1933 | |
1934 | int QMetaMethodPrivate::returnType() const |
1935 | { |
1936 | return parameterType(index: -1); |
1937 | } |
1938 | |
1939 | int QMetaMethodPrivate::parameterCount() const |
1940 | { |
1941 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1942 | return data.argc(); |
1943 | } |
1944 | |
1945 | inline void |
1946 | QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, |
1947 | int index) const |
1948 | { |
1949 | uint typeInfo = parameterTypeInfo(index); |
1950 | QMetaType mt(iface); |
1951 | if (iface) { |
1952 | if ((typeInfo & IsUnresolvedType) == 0) |
1953 | Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask)); |
1954 | Q_ASSERT(mt.name()); |
1955 | } else { |
1956 | // The iface can only be null for a parameter if that parameter is a |
1957 | // const-ref to a forward-declared type. Since primitive types are |
1958 | // never incomplete, we can assert it's not one of them. |
1959 | |
1960 | #define ASSERT_NOT_PRIMITIVE_TYPE(TYPE, METATYPEID, NAME) \ |
1961 | Q_ASSERT(typeInfo != QMetaType::TYPE); |
1962 | QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(ASSERT_NOT_PRIMITIVE_TYPE) |
1963 | #undef ASSERT_NOT_PRIMITIVE_TYPE |
1964 | Q_ASSERT(typeInfo != QMetaType::QObjectStar); |
1965 | |
1966 | // Prior to Qt 6.4 we failed to record void and void* |
1967 | if (priv(data: mobj->d.data)->revision >= 11) { |
1968 | Q_ASSERT(typeInfo != QMetaType::Void); |
1969 | Q_ASSERT(typeInfo != QMetaType::VoidStar); |
1970 | } |
1971 | } |
1972 | } |
1973 | |
1974 | int QMetaMethodPrivate::parametersDataIndex() const |
1975 | { |
1976 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1977 | return typesDataIndex() + 1; |
1978 | } |
1979 | |
1980 | uint QMetaMethodPrivate::parameterTypeInfo(int index) const |
1981 | { |
1982 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1983 | return mobj->d.data[parametersDataIndex() + index]; |
1984 | } |
1985 | |
1986 | const QtPrivate::QMetaTypeInterface *QMetaMethodPrivate::returnMetaTypeInterface() const |
1987 | { |
1988 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
1989 | if (methodType() == QMetaMethod::Constructor) |
1990 | return nullptr; // constructors don't have return types |
1991 | |
1992 | const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()]; |
1993 | checkMethodMetaTypeConsistency(iface, index: -1); |
1994 | return iface; |
1995 | } |
1996 | |
1997 | const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTypeInterfaces() const |
1998 | { |
1999 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2000 | int offset = (methodType() == QMetaMethod::Constructor ? 0 : 1); |
2001 | const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset]; |
2002 | |
2003 | for (int i = 0; i < parameterCount(); ++i) |
2004 | checkMethodMetaTypeConsistency(iface: ifaces[i], index: i); |
2005 | |
2006 | return ifaces; |
2007 | } |
2008 | |
2009 | int QMetaMethodPrivate::parameterType(int index) const |
2010 | { |
2011 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2012 | return typeFromTypeInfo(mo: mobj, typeInfo: parameterTypeInfo(index)); |
2013 | } |
2014 | |
2015 | void QMetaMethodPrivate::getParameterTypes(int *types) const |
2016 | { |
2017 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2018 | int dataIndex = parametersDataIndex(); |
2019 | int argc = parameterCount(); |
2020 | for (int i = 0; i < argc; ++i) { |
2021 | int id = typeFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[dataIndex++]); |
2022 | *(types++) = id; |
2023 | } |
2024 | } |
2025 | |
2026 | QByteArray QMetaMethodPrivate::parameterTypeName(int index) const |
2027 | { |
2028 | int paramsIndex = parametersDataIndex(); |
2029 | return typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + index]).toByteArray(); |
2030 | } |
2031 | |
2032 | QList<QByteArray> QMetaMethodPrivate::parameterTypes() const |
2033 | { |
2034 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2035 | int argc = parameterCount(); |
2036 | QList<QByteArray> list; |
2037 | list.reserve(asize: argc); |
2038 | int paramsIndex = parametersDataIndex(); |
2039 | for (int i = 0; i < argc; ++i) { |
2040 | QByteArrayView name = typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + i]); |
2041 | list.emplace_back(args: name.toByteArray()); |
2042 | } |
2043 | return list; |
2044 | } |
2045 | |
2046 | QList<QByteArray> QMetaMethodPrivate::parameterNames() const |
2047 | { |
2048 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2049 | int argc = parameterCount(); |
2050 | QList<QByteArray> list; |
2051 | list.reserve(asize: argc); |
2052 | int namesIndex = parametersDataIndex() + argc; |
2053 | for (int i = 0; i < argc; ++i) |
2054 | list += stringData(mo: mobj, index: mobj->d.data[namesIndex + i]); |
2055 | return list; |
2056 | } |
2057 | |
2058 | QByteArray QMetaMethodPrivate::tag() const |
2059 | { |
2060 | Q_ASSERT(priv(mobj->d.data)->revision >= 7); |
2061 | return stringData(mo: mobj, index: data.tag()); |
2062 | } |
2063 | |
2064 | int QMetaMethodPrivate::ownMethodIndex() const |
2065 | { |
2066 | // recompute the methodIndex by reversing the arithmetic in QMetaObject::method() |
2067 | return ( data.d - mobj->d.data - priv(data: mobj->d.data)->methodData)/Data::Size; |
2068 | } |
2069 | |
2070 | int QMetaMethodPrivate::ownConstructorMethodIndex() const |
2071 | { |
2072 | // recompute the methodIndex by reversing the arithmetic in QMetaObject::constructor() |
2073 | Q_ASSERT(methodType() == Constructor); |
2074 | return ( data.d - mobj->d.data - priv(data: mobj->d.data)->constructorData)/Data::Size; |
2075 | } |
2076 | |
2077 | /*! |
2078 | \since 5.0 |
2079 | |
2080 | Returns the signature of this method (e.g., |
2081 | \c{setValue(double)}). |
2082 | |
2083 | \sa parameterTypes(), parameterNames() |
2084 | */ |
2085 | QByteArray QMetaMethod::methodSignature() const |
2086 | { |
2087 | if (!mobj) |
2088 | return QByteArray(); |
2089 | return QMetaMethodPrivate::get(q: this)->signature(); |
2090 | } |
2091 | |
2092 | /*! |
2093 | \since 5.0 |
2094 | |
2095 | Returns the name of this method. |
2096 | |
2097 | \sa methodSignature(), parameterCount() |
2098 | */ |
2099 | QByteArray QMetaMethod::name() const |
2100 | { |
2101 | if (!mobj) |
2102 | return QByteArray(); |
2103 | return QMetaMethodPrivate::get(q: this)->name(); |
2104 | } |
2105 | |
2106 | /*! |
2107 | \since 5.0 |
2108 | |
2109 | Returns the return type of this method. |
2110 | |
2111 | The return value is one of the types that are registered |
2112 | with QMetaType, or QMetaType::UnknownType if the type is not registered. |
2113 | |
2114 | \sa parameterType(), QMetaType, typeName(), returnMetaType() |
2115 | */ |
2116 | int QMetaMethod::returnType() const |
2117 | { |
2118 | return returnMetaType().id(); |
2119 | } |
2120 | |
2121 | /*! |
2122 | \since 6.0 |
2123 | |
2124 | Returns the return type of this method. |
2125 | \sa parameterMetaType(), QMetaType, typeName() |
2126 | */ |
2127 | QMetaType QMetaMethod::returnMetaType() const |
2128 | { |
2129 | if (!mobj || methodType() == QMetaMethod::Constructor) |
2130 | return QMetaType{}; |
2131 | auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset()]); |
2132 | if (mt.id() == QMetaType::UnknownType) |
2133 | return QMetaType(QMetaMethodPrivate::get(q: this)->returnType()); |
2134 | else |
2135 | return mt; |
2136 | } |
2137 | |
2138 | /*! |
2139 | \since 5.0 |
2140 | |
2141 | Returns the number of parameters of this method. |
2142 | |
2143 | \sa parameterType(), parameterNames() |
2144 | */ |
2145 | int QMetaMethod::parameterCount() const |
2146 | { |
2147 | if (!mobj) |
2148 | return 0; |
2149 | return QMetaMethodPrivate::get(q: this)->parameterCount(); |
2150 | } |
2151 | |
2152 | /*! |
2153 | \since 5.0 |
2154 | |
2155 | Returns the type of the parameter at the given \a index. |
2156 | |
2157 | The return value is one of the types that are registered |
2158 | with QMetaType, or QMetaType::UnknownType if the type is not registered. |
2159 | |
2160 | \sa parameterCount(), parameterMetaType(), returnType(), QMetaType |
2161 | */ |
2162 | int QMetaMethod::parameterType(int index) const |
2163 | { |
2164 | return parameterMetaType(index).id(); |
2165 | } |
2166 | |
2167 | /*! |
2168 | \since 6.0 |
2169 | |
2170 | Returns the metatype of the parameter at the given \a index. |
2171 | |
2172 | If the \a index is smaller than zero or larger than |
2173 | parameterCount(), an invalid QMetaType is returned. |
2174 | |
2175 | \sa parameterCount(), returnMetaType(), QMetaType |
2176 | */ |
2177 | QMetaType QMetaMethod::parameterMetaType(int index) const |
2178 | { |
2179 | if (!mobj || index < 0) |
2180 | return {}; |
2181 | auto priv = QMetaMethodPrivate::get(q: this); |
2182 | if (index >= priv->parameterCount()) |
2183 | return {}; |
2184 | // + 1 if there exists a return type |
2185 | auto parameterOffset = index + (methodType() == QMetaMethod::Constructor ? 0 : 1); |
2186 | auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset() + parameterOffset]); |
2187 | if (mt.id() == QMetaType::UnknownType) |
2188 | return QMetaType(QMetaMethodPrivate::get(q: this)->parameterType(index)); |
2189 | else |
2190 | return mt; |
2191 | } |
2192 | |
2193 | /*! |
2194 | \since 5.0 |
2195 | \internal |
2196 | |
2197 | Gets the parameter \a types of this method. The storage |
2198 | for \a types must be able to hold parameterCount() items. |
2199 | |
2200 | \sa parameterCount(), returnType(), parameterType() |
2201 | */ |
2202 | void QMetaMethod::getParameterTypes(int *types) const |
2203 | { |
2204 | if (!mobj) |
2205 | return; |
2206 | QMetaMethodPrivate::get(q: this)->getParameterTypes(types); |
2207 | } |
2208 | |
2209 | /*! |
2210 | Returns a list of parameter types. |
2211 | |
2212 | \sa parameterNames(), methodSignature() |
2213 | */ |
2214 | QList<QByteArray> QMetaMethod::parameterTypes() const |
2215 | { |
2216 | if (!mobj) |
2217 | return QList<QByteArray>(); |
2218 | return QMetaMethodPrivate::get(q: this)->parameterTypes(); |
2219 | } |
2220 | |
2221 | /*! |
2222 | \since 6.0 |
2223 | Returns the name of the type at position \a index |
2224 | If there is no parameter at \a index, returns an empty QByteArray |
2225 | |
2226 | \sa parameterNames() |
2227 | */ |
2228 | QByteArray QMetaMethod::parameterTypeName(int index) const |
2229 | { |
2230 | if (!mobj || index < 0 || index >= parameterCount()) |
2231 | return {}; |
2232 | return QMetaMethodPrivate::get(q: this)->parameterTypeName(index); |
2233 | } |
2234 | |
2235 | /*! |
2236 | Returns a list of parameter names. |
2237 | |
2238 | \sa parameterTypes(), methodSignature() |
2239 | */ |
2240 | QList<QByteArray> QMetaMethod::parameterNames() const |
2241 | { |
2242 | if (!mobj) |
2243 | return QList<QByteArray>(); |
2244 | return QMetaMethodPrivate::get(q: this)->parameterNames(); |
2245 | } |
2246 | |
2247 | |
2248 | /*! |
2249 | Returns the return type name of this method. |
2250 | |
2251 | \sa returnType(), QMetaType::type() |
2252 | */ |
2253 | const char *QMetaMethod::typeName() const |
2254 | { |
2255 | if (!mobj) |
2256 | return nullptr; |
2257 | return QMetaMethodPrivate::get(q: this)->rawReturnTypeName(); |
2258 | } |
2259 | |
2260 | /*! |
2261 | Returns the tag associated with this method. |
2262 | |
2263 | Tags are special macros recognized by \c moc that make it |
2264 | possible to add extra information about a method. |
2265 | |
2266 | Tag information can be added in the following |
2267 | way in the function declaration: |
2268 | |
2269 | \snippet code/src_corelib_kernel_qmetaobject.cpp 10 |
2270 | |
2271 | and the information can be accessed by using: |
2272 | |
2273 | \snippet code/src_corelib_kernel_qmetaobject.cpp 11 |
2274 | |
2275 | For the moment, \c moc will extract and record all tags, but it will not |
2276 | handle any of them specially. You can use the tags to annotate your methods |
2277 | differently, and treat them according to the specific needs of your |
2278 | application. |
2279 | |
2280 | \note \c moc expands preprocessor macros, so it is necessary |
2281 | to surround the definition with \c #ifndef \c Q_MOC_RUN, as shown in the |
2282 | example above. |
2283 | */ |
2284 | const char *QMetaMethod::tag() const |
2285 | { |
2286 | if (!mobj) |
2287 | return nullptr; |
2288 | return QMetaMethodPrivate::get(q: this)->tag().constData(); |
2289 | } |
2290 | |
2291 | |
2292 | /*! |
2293 | \internal |
2294 | */ |
2295 | int QMetaMethod::attributes() const |
2296 | { |
2297 | if (!mobj) |
2298 | return false; |
2299 | return data.flags() >> 4; |
2300 | } |
2301 | |
2302 | /*! |
2303 | \since 4.6 |
2304 | |
2305 | Returns this method's index. |
2306 | */ |
2307 | int QMetaMethod::methodIndex() const |
2308 | { |
2309 | if (!mobj) |
2310 | return -1; |
2311 | return QMetaMethodPrivate::get(q: this)->ownMethodIndex() + mobj->methodOffset(); |
2312 | } |
2313 | |
2314 | /*! |
2315 | \since 6.0 |
2316 | |
2317 | Returns this method's local index inside. |
2318 | */ |
2319 | int QMetaMethod::relativeMethodIndex() const |
2320 | { |
2321 | if (!mobj) |
2322 | return -1; |
2323 | return QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2324 | } |
2325 | |
2326 | // This method has been around for a while, but the documentation was marked \internal until 5.1 |
2327 | /*! |
2328 | \since 5.1 |
2329 | Returns the method revision if one was specified by Q_REVISION, otherwise |
2330 | returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded |
2331 | using QTypeRevision::fromEncodedVersion(). |
2332 | */ |
2333 | int QMetaMethod::revision() const |
2334 | { |
2335 | if (!mobj) |
2336 | return 0; |
2337 | if (data.flags() & MethodRevisioned) { |
2338 | int offset = priv(data: mobj->d.data)->methodData |
2339 | + priv(data: mobj->d.data)->methodCount * Data::Size |
2340 | + QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2341 | return mobj->d.data[offset]; |
2342 | } |
2343 | return 0; |
2344 | } |
2345 | |
2346 | /*! |
2347 | \since 6.2 |
2348 | |
2349 | Returns whether the method is const qualified. |
2350 | |
2351 | \note This method might erroneously return \c false for a const method |
2352 | if it belongs to a library compiled against an older version of Qt. |
2353 | */ |
2354 | bool QMetaMethod::isConst() const |
2355 | { |
2356 | if (!mobj) |
2357 | return false; |
2358 | if (QMetaObjectPrivate::get(metaobject: mobj)->revision < 10) |
2359 | return false; |
2360 | return data.flags() & MethodIsConst; |
2361 | } |
2362 | |
2363 | /*! |
2364 | Returns the access specification of this method (private, |
2365 | protected, or public). |
2366 | |
2367 | \note Signals are always public, but you should regard that as an |
2368 | implementation detail. It is almost always a bad idea to emit a signal from |
2369 | outside its class. |
2370 | |
2371 | \sa methodType() |
2372 | */ |
2373 | QMetaMethod::Access QMetaMethod::access() const |
2374 | { |
2375 | if (!mobj) |
2376 | return Private; |
2377 | return (QMetaMethod::Access)(data.flags() & AccessMask); |
2378 | } |
2379 | |
2380 | /*! |
2381 | Returns the type of this method (signal, slot, or method). |
2382 | |
2383 | \sa access() |
2384 | */ |
2385 | QMetaMethod::MethodType QMetaMethod::methodType() const |
2386 | { |
2387 | if (!mobj) |
2388 | return QMetaMethod::Method; |
2389 | return (QMetaMethod::MethodType)((data.flags() & MethodTypeMask)>>2); |
2390 | } |
2391 | |
2392 | /*! |
2393 | \fn template <typename PointerToMemberFunction> QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal) |
2394 | \since 5.0 |
2395 | |
2396 | Returns the meta-method that corresponds to the given \a signal, or an |
2397 | invalid QMetaMethod if \a signal is \c{nullptr} or not a signal of the class. |
2398 | |
2399 | Example: |
2400 | |
2401 | \snippet code/src_corelib_kernel_qmetaobject.cpp 9 |
2402 | */ |
2403 | |
2404 | /*! |
2405 | \internal |
2406 | |
2407 | Implementation of the fromSignal() function. |
2408 | |
2409 | \a metaObject is the class's meta-object |
2410 | \a signal is a pointer to a pointer to a member signal of the class |
2411 | */ |
2412 | QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal) |
2413 | { |
2414 | int i = -1; |
2415 | void *args[] = { &i, signal }; |
2416 | for (const QMetaObject *m = metaObject; m; m = m->d.superdata) { |
2417 | m->static_metacall(cl: QMetaObject::IndexOfMethod, idx: 0, argv: args); |
2418 | if (i >= 0) |
2419 | return QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i); |
2420 | } |
2421 | return QMetaMethod(); |
2422 | } |
2423 | |
2424 | /*! |
2425 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2426 | \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const |
2427 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2428 | \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const |
2429 | \since 6.5 |
2430 | |
2431 | Invokes this method on the object \a object. Returns \c true if the member could be invoked. |
2432 | Returns \c false if there is no such member or the parameters did not match. |
2433 | |
2434 | For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the |
2435 | return value of the \a member function call is placed in \a ret. For the |
2436 | overloads without such a member, the return value of the called function |
2437 | (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an |
2438 | internal type you should not use directly. Instead, use the qReturnArg() |
2439 | function. |
2440 | |
2441 | The overloads with a Qt::ConnectionType \a type parameter allow explicitly |
2442 | selecting whether the invocation will be synchronous or not: |
2443 | |
2444 | \list |
2445 | \li If \a type is Qt::DirectConnection, the member will be invoked immediately |
2446 | in the current thread. |
2447 | |
2448 | \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the |
2449 | member is invoked as soon as the application enters the event loop in the |
2450 | thread the \a obj was created in or was moved to. |
2451 | |
2452 | \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in |
2453 | the same way as for Qt::QueuedConnection, except that the current thread |
2454 | will block until the event is delivered. Using this connection type to |
2455 | communicate between objects in the same thread will lead to deadlocks. |
2456 | |
2457 | \li If \a type is Qt::AutoConnection, the member is invoked synchronously |
2458 | if \a obj lives in the same thread as the caller; otherwise it will invoke |
2459 | the member asynchronously. This is the behavior of the overloads that do |
2460 | not have the \a type parameter. |
2461 | \endlist |
2462 | |
2463 | To asynchronously invoke the |
2464 | \l{QPushButton::animateClick()}{animateClick()} slot on a |
2465 | QPushButton: |
2466 | |
2467 | \snippet code/src_corelib_kernel_qmetaobject.cpp 6 |
2468 | |
2469 | With asynchronous method invocations, the parameters must be copyable |
2470 | types, because Qt needs to copy the arguments to store them in an event |
2471 | behind the scenes. Since Qt 6.5, this function automatically registers the |
2472 | types being used; however, as a side-effect, it is not possible to make |
2473 | calls using types that are only forward-declared. Additionally, it is not |
2474 | possible to make asynchronous calls that use references to |
2475 | non-const-qualified types as parameters either. |
2476 | |
2477 | To synchronously invoke the \c compute(QString, int, double) slot on |
2478 | some arbitrary object \c obj retrieve its return value: |
2479 | |
2480 | \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro |
2481 | |
2482 | If the "compute" slot does not take exactly one \l QString, one \c int, and |
2483 | one \c double in the specified order, the call will fail. Note how it was |
2484 | necessary to be explicit about the type of the QString, as the character |
2485 | literal is not exactly the right type to match. If the method instead took |
2486 | a \l QByteArray, a \l qint64, and a \c{long double}, the call would need to be |
2487 | written as: |
2488 | |
2489 | \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro-other-types |
2490 | |
2491 | The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros, |
2492 | as in: |
2493 | |
2494 | \snippet code/src_corelib_kernel_qmetaobject.cpp 8 |
2495 | |
2496 | \warning this method will not test the validity of the arguments: \a object |
2497 | must be an instance of the class of the QMetaObject of which this QMetaMethod |
2498 | has been constructed with. |
2499 | |
2500 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2501 | */ |
2502 | |
2503 | /*! |
2504 | \obsolete [6.5] Please use the variadic overload of this function |
2505 | |
2506 | Invokes this method on the object \a object. Returns \c true if the member could be invoked. |
2507 | Returns \c false if there is no such member or the parameters did not match. |
2508 | |
2509 | See the variadic invokeMethod() function for more information. This |
2510 | function should behave the same way as that one, with the following |
2511 | limitations: |
2512 | |
2513 | \list |
2514 | \li The number of parameters is limited to 10. |
2515 | \li Parameter names may need to be an exact string match. |
2516 | \li Meta types are not automatically registered. |
2517 | \endlist |
2518 | |
2519 | With asynchronous method invocations, the parameters must be of |
2520 | types that are known to Qt's meta-object system, because Qt needs |
2521 | to copy the arguments to store them in an event behind the |
2522 | scenes. If you try to use a queued connection and get the error |
2523 | message |
2524 | |
2525 | \snippet code/src_corelib_kernel_qmetaobject.cpp 7 |
2526 | |
2527 | call qRegisterMetaType() to register the data type before you |
2528 | call QMetaMethod::invoke(). |
2529 | |
2530 | \warning In addition to the limitations of the variadic invoke() overload, |
2531 | the arguments must have the same type as the ones expected by the method, |
2532 | else, the behavior is undefined. |
2533 | |
2534 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2535 | */ |
2536 | bool QMetaMethod::invoke(QObject *object, |
2537 | Qt::ConnectionType connectionType, |
2538 | QGenericReturnArgument returnValue, |
2539 | QGenericArgument val0, |
2540 | QGenericArgument val1, |
2541 | QGenericArgument val2, |
2542 | QGenericArgument val3, |
2543 | QGenericArgument val4, |
2544 | QGenericArgument val5, |
2545 | QGenericArgument val6, |
2546 | QGenericArgument val7, |
2547 | QGenericArgument val8, |
2548 | QGenericArgument val9) const |
2549 | { |
2550 | if (!object || !mobj) |
2551 | return false; |
2552 | |
2553 | // check argument count (we don't allow invoking a method if given too few arguments) |
2554 | const char *typeNames[] = { |
2555 | returnValue.name(), |
2556 | val0.name(), |
2557 | val1.name(), |
2558 | val2.name(), |
2559 | val3.name(), |
2560 | val4.name(), |
2561 | val5.name(), |
2562 | val6.name(), |
2563 | val7.name(), |
2564 | val8.name(), |
2565 | val9.name() |
2566 | }; |
2567 | void *param[] = { |
2568 | returnValue.data(), |
2569 | val0.data(), |
2570 | val1.data(), |
2571 | val2.data(), |
2572 | val3.data(), |
2573 | val4.data(), |
2574 | val5.data(), |
2575 | val6.data(), |
2576 | val7.data(), |
2577 | val8.data(), |
2578 | val9.data() |
2579 | }; |
2580 | |
2581 | int paramCount; |
2582 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
2583 | if (qstrlen(str: typeNames[paramCount]) <= 0) |
2584 | break; |
2585 | } |
2586 | return invokeImpl(self: *this, target: object, connectionType, paramCount, parameters: param, typeNames, metaTypes: nullptr); |
2587 | } |
2588 | |
2589 | bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType, |
2590 | qsizetype paramCount, const void *const *parameters, |
2591 | const char *const *typeNames, |
2592 | const QtPrivate::QMetaTypeInterface *const *metaTypes) |
2593 | { |
2594 | if (!target || !self.mobj) |
2595 | return false; |
2596 | QMetaMethodPrivate::InvokeFailReason r = |
2597 | QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, |
2598 | typeNames, metaTypes); |
2599 | if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None)) |
2600 | return true; |
2601 | |
2602 | if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) { |
2603 | int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch); |
2604 | qWarning(msg: "QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s", |
2605 | n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name, |
2606 | self.mobj->className(), self.methodSignature().constData()); |
2607 | } |
2608 | if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) { |
2609 | qWarning(msg: "QMetaMethod::invoke: too few arguments (%d) in call to %s::%s", |
2610 | int(paramCount), self.mobj->className(), self.methodSignature().constData()); |
2611 | } |
2612 | return false; |
2613 | } |
2614 | |
2615 | auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, |
2616 | Qt::ConnectionType connectionType, |
2617 | qsizetype paramCount, const void *const *parameters, |
2618 | const char *const *typeNames, |
2619 | const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason |
2620 | { |
2621 | auto object = static_cast<QObject *>(target); |
2622 | auto priv = QMetaMethodPrivate::get(q: &self); |
2623 | constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0); |
2624 | auto methodMetaTypes = priv->parameterMetaTypeInterfaces(); |
2625 | auto param = const_cast<void **>(parameters); |
2626 | |
2627 | Q_ASSERT(priv->mobj); |
2628 | Q_ASSERT(self.methodType() == Constructor || object); |
2629 | Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) || |
2630 | priv->mobj->cast(object)); |
2631 | Q_ASSERT(paramCount >= 1); // includes the return type |
2632 | Q_ASSERT(parameters); |
2633 | Q_ASSERT(typeNames); |
2634 | Q_ASSERT(MetaTypesAreOptional || metaTypes); |
2635 | |
2636 | if ((paramCount - 1) < qsizetype(priv->data.argc())) |
2637 | return InvokeFailReason::TooFewArguments; |
2638 | |
2639 | // 0 is the return type, 1 is the first formal parameter |
2640 | auto checkTypesAreCompatible = [=](int idx) { |
2641 | uint typeInfo = priv->parameterTypeInfo(index: idx - 1); |
2642 | QByteArrayView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name); |
2643 | |
2644 | if ((typeInfo & IsUnresolvedType) == 0) { |
2645 | // this is a built-in type |
2646 | if (MetaTypesAreOptional && !metaTypes) |
2647 | return int(typeInfo) == QMetaType::fromName(name: userTypeName).id(); |
2648 | return int(typeInfo) == metaTypes[idx]->typeId; |
2649 | } |
2650 | |
2651 | QByteArrayView methodTypeName = stringDataView(mo: priv->mobj, index: typeInfo & TypeNameIndexMask); |
2652 | if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) { |
2653 | // compatibility call, compare strings |
2654 | if (methodTypeName == userTypeName) |
2655 | return true; |
2656 | |
2657 | // maybe the user type needs normalization |
2658 | QByteArray normalized = normalizeTypeInternal(t: userTypeName.begin(), e: userTypeName.end()); |
2659 | return methodTypeName == normalized; |
2660 | } |
2661 | |
2662 | QMetaType userType(metaTypes[idx]); |
2663 | Q_ASSERT(userType.isValid()); |
2664 | if (QMetaType(methodMetaTypes[idx - 1]) == userType) |
2665 | return true; |
2666 | |
2667 | // if the parameter type was NOT only forward-declared, it MUST have |
2668 | // matched |
2669 | if (methodMetaTypes[idx - 1]) |
2670 | return false; |
2671 | |
2672 | // resolve from the name moc stored for us |
2673 | QMetaType resolved = QMetaType::fromName(name: methodTypeName); |
2674 | return resolved == userType; |
2675 | }; |
2676 | |
2677 | // force all types to be registered, just in case |
2678 | for (qsizetype i = 0; metaTypes && i < paramCount; ++i) |
2679 | QMetaType(metaTypes[i]).registerType(); |
2680 | |
2681 | // check formal parameters first (overload set) |
2682 | for (qsizetype i = 1; i < paramCount; ++i) { |
2683 | if (!checkTypesAreCompatible(i)) |
2684 | return InvokeFailReason(int(InvokeFailReason::FormalParameterMismatch) + i - 1); |
2685 | } |
2686 | |
2687 | // handle constructors first |
2688 | if (self.methodType() == Constructor) { |
2689 | if (object) { |
2690 | qWarning(msg: "QMetaMethod::invokeMethod: cannot call constructor %s on object %p", |
2691 | self.methodSignature().constData(), object); |
2692 | return InvokeFailReason::ConstructorCallOnObject; |
2693 | } |
2694 | |
2695 | if (!parameters[0]) { |
2696 | qWarning(msg: "QMetaMethod::invokeMethod: constructor call to %s must assign a return type", |
2697 | self.methodSignature().constData()); |
2698 | return InvokeFailReason::ConstructorCallWithoutResult; |
2699 | } |
2700 | |
2701 | if (!MetaTypesAreOptional || metaTypes) { |
2702 | if (metaTypes[0]->typeId != QMetaType::QObjectStar) { |
2703 | qWarning(msg: "QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s", |
2704 | metaTypes[0]->name, self.methodSignature().constData()); |
2705 | return InvokeFailReason::ReturnTypeMismatch; |
2706 | } |
2707 | } |
2708 | |
2709 | int idx = priv->ownConstructorMethodIndex(); |
2710 | if (priv->mobj->static_metacall(cl: QMetaObject::CreateInstance, idx, argv: param) >= 0) |
2711 | return InvokeFailReason::ConstructorCallFailed; |
2712 | return {}; |
2713 | } |
2714 | |
2715 | // regular type - check return type |
2716 | if (parameters[0]) { |
2717 | if (!checkTypesAreCompatible(0)) { |
2718 | const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name; |
2719 | qWarning(msg: "QMetaMethod::invokeMethod: return type mismatch for method %s::%s:" |
2720 | " cannot convert from %s to %s during invocation", |
2721 | priv->mobj->className(), priv->methodSignature().constData(), |
2722 | priv->rawReturnTypeName(), retType); |
2723 | return InvokeFailReason::ReturnTypeMismatch; |
2724 | } |
2725 | } |
2726 | |
2727 | Qt::HANDLE currentThreadId = nullptr; |
2728 | QThread *objectThread = nullptr; |
2729 | auto receiverInSameThread = [&]() { |
2730 | if (!currentThreadId) { |
2731 | currentThreadId = QThread::currentThreadId(); |
2732 | objectThread = object->thread(); |
2733 | } |
2734 | if (objectThread) |
2735 | return currentThreadId == QThreadData::get2(thread: objectThread)->threadId.loadRelaxed(); |
2736 | return false; |
2737 | }; |
2738 | |
2739 | // check connection type |
2740 | if (connectionType == Qt::AutoConnection) |
2741 | connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection; |
2742 | else if (connectionType == Qt::ConnectionType(-1)) |
2743 | connectionType = Qt::DirectConnection; |
2744 | |
2745 | #if !QT_CONFIG(thread) |
2746 | if (connectionType == Qt::BlockingQueuedConnection) { |
2747 | connectionType = Qt::DirectConnection; |
2748 | } |
2749 | #endif |
2750 | |
2751 | // invoke! |
2752 | int idx_relative = priv->ownMethodIndex(); |
2753 | int idx_offset = priv->mobj->methodOffset(); |
2754 | QObjectPrivate::StaticMetaCallFunction callFunction = priv->mobj->d.static_metacall; |
2755 | |
2756 | if (connectionType == Qt::DirectConnection) { |
2757 | if (callFunction) |
2758 | callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param); |
2759 | else if (QMetaObject::metacall(object, cl: QMetaObject::InvokeMetaMethod, idx: idx_relative + idx_offset, argv: param) >= 0) |
2760 | return InvokeFailReason::CallViaVirtualFailed; |
2761 | } else if (connectionType == Qt::QueuedConnection) { |
2762 | if (parameters[0]) { |
2763 | qWarning(msg: "QMetaMethod::invoke: Unable to invoke methods with return values in " |
2764 | "queued connections"); |
2765 | return InvokeFailReason::CouldNotQueueParameter; |
2766 | } |
2767 | |
2768 | auto event = std::make_unique<QMetaCallEvent>(args&: idx_offset, args&: idx_relative, args&: callFunction, args: nullptr, args: -1, args&: paramCount); |
2769 | QMetaType *types = event->types(); |
2770 | void **args = event->args(); |
2771 | |
2772 | // fill in the meta types first |
2773 | for (int i = 1; i < paramCount; ++i) { |
2774 | types[i] = QMetaType(methodMetaTypes[i - 1]); |
2775 | if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes)) |
2776 | types[i] = QMetaType(metaTypes[i]); |
2777 | if (!types[i].iface()) |
2778 | types[i] = priv->parameterMetaType(index: i - 1); |
2779 | if (!types[i].iface() && typeNames[i]) |
2780 | types[i] = QMetaType::fromName(name: typeNames[i]); |
2781 | if (!types[i].iface()) { |
2782 | qWarning(msg: "QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", |
2783 | typeNames[i]); |
2784 | return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i); |
2785 | } |
2786 | } |
2787 | |
2788 | // now create copies of our parameters using those meta types |
2789 | for (int i = 1; i < paramCount; ++i) |
2790 | args[i] = types[i].create(copy: parameters[i]); |
2791 | |
2792 | QCoreApplication::postEvent(receiver: object, event: event.release()); |
2793 | } else { // blocking queued connection |
2794 | #if QT_CONFIG(thread) |
2795 | if (receiverInSameThread()) { |
2796 | qWarning(msg: "QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: " |
2797 | "Receiver is %s(%p)", priv->mobj->className(), object); |
2798 | return InvokeFailReason::DeadLockDetected; |
2799 | } |
2800 | |
2801 | QSemaphore semaphore; |
2802 | QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(idx_offset, idx_relative, callFunction, |
2803 | nullptr, -1, param, &semaphore)); |
2804 | semaphore.acquire(); |
2805 | #endif // QT_CONFIG(thread) |
2806 | } |
2807 | return {}; |
2808 | } |
2809 | |
2810 | /*! \fn bool QMetaMethod::invoke(QObject *object, |
2811 | QGenericReturnArgument returnValue, |
2812 | QGenericArgument val0 = QGenericArgument(0), |
2813 | QGenericArgument val1 = QGenericArgument(), |
2814 | QGenericArgument val2 = QGenericArgument(), |
2815 | QGenericArgument val3 = QGenericArgument(), |
2816 | QGenericArgument val4 = QGenericArgument(), |
2817 | QGenericArgument val5 = QGenericArgument(), |
2818 | QGenericArgument val6 = QGenericArgument(), |
2819 | QGenericArgument val7 = QGenericArgument(), |
2820 | QGenericArgument val8 = QGenericArgument(), |
2821 | QGenericArgument val9 = QGenericArgument()) const |
2822 | \obsolete [6.5] Please use the variadic overload of this function |
2823 | \overload invoke() |
2824 | |
2825 | This overload always invokes this method using the connection type Qt::AutoConnection. |
2826 | */ |
2827 | |
2828 | /*! \fn bool QMetaMethod::invoke(QObject *object, |
2829 | Qt::ConnectionType connectionType, |
2830 | QGenericArgument val0 = QGenericArgument(0), |
2831 | QGenericArgument val1 = QGenericArgument(), |
2832 | QGenericArgument val2 = QGenericArgument(), |
2833 | QGenericArgument val3 = QGenericArgument(), |
2834 | QGenericArgument val4 = QGenericArgument(), |
2835 | QGenericArgument val5 = QGenericArgument(), |
2836 | QGenericArgument val6 = QGenericArgument(), |
2837 | QGenericArgument val7 = QGenericArgument(), |
2838 | QGenericArgument val8 = QGenericArgument(), |
2839 | QGenericArgument val9 = QGenericArgument()) const |
2840 | \obsolete [6.5] Please use the variadic overload of this function |
2841 | \overload invoke() |
2842 | |
2843 | This overload can be used if the return value of the member is of no interest. |
2844 | */ |
2845 | |
2846 | /*! |
2847 | \fn bool QMetaMethod::invoke(QObject *object, |
2848 | QGenericArgument val0 = QGenericArgument(0), |
2849 | QGenericArgument val1 = QGenericArgument(), |
2850 | QGenericArgument val2 = QGenericArgument(), |
2851 | QGenericArgument val3 = QGenericArgument(), |
2852 | QGenericArgument val4 = QGenericArgument(), |
2853 | QGenericArgument val5 = QGenericArgument(), |
2854 | QGenericArgument val6 = QGenericArgument(), |
2855 | QGenericArgument val7 = QGenericArgument(), |
2856 | QGenericArgument val8 = QGenericArgument(), |
2857 | QGenericArgument val9 = QGenericArgument()) const |
2858 | \obsolete [6.5] Please use the variadic overload of this function |
2859 | \overload invoke() |
2860 | |
2861 | This overload invokes this method using the |
2862 | connection type Qt::AutoConnection and ignores return values. |
2863 | */ |
2864 | |
2865 | /*! |
2866 | \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const |
2867 | \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const |
2868 | \since 6.5 |
2869 | |
2870 | Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked. |
2871 | Returns \c false if there is no such member or the parameters did not match. |
2872 | |
2873 | The pointer \a gadget must point to an instance of the gadget class. |
2874 | |
2875 | The invocation is always synchronous. |
2876 | |
2877 | For the overload with a QTemplatedMetaMethodReturnArgument parameter, the |
2878 | return value of the \a member function call is placed in \a ret. For the |
2879 | overload without it, the return value of the called function (if any) will |
2880 | be discarded. QTemplatedMetaMethodReturnArgument is an internal type you |
2881 | should not use directly. Instead, use the qReturnArg() function. |
2882 | |
2883 | \warning this method will not test the validity of the arguments: \a gadget |
2884 | must be an instance of the class of the QMetaObject of which this QMetaMethod |
2885 | has been constructed with. |
2886 | |
2887 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2888 | */ |
2889 | |
2890 | /*! |
2891 | \since 5.5 |
2892 | \obsolete [6.5] Please use the variadic overload of this function |
2893 | |
2894 | Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked. |
2895 | Returns \c false if there is no such member or the parameters did not match. |
2896 | |
2897 | See the variadic invokeMethod() function for more information. This |
2898 | function should behave the same way as that one, with the following |
2899 | limitations: |
2900 | |
2901 | \list |
2902 | \li The number of parameters is limited to 10. |
2903 | \li Parameter names may need to be an exact string match. |
2904 | \li Meta types are not automatically registered. |
2905 | \endlist |
2906 | |
2907 | \warning In addition to the limitations of the variadic invoke() overload, |
2908 | the arguments must have the same type as the ones expected by the method, |
2909 | else, the behavior is undefined. |
2910 | |
2911 | \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod() |
2912 | */ |
2913 | bool QMetaMethod::invokeOnGadget(void *gadget, |
2914 | QGenericReturnArgument returnValue, |
2915 | QGenericArgument val0, |
2916 | QGenericArgument val1, |
2917 | QGenericArgument val2, |
2918 | QGenericArgument val3, |
2919 | QGenericArgument val4, |
2920 | QGenericArgument val5, |
2921 | QGenericArgument val6, |
2922 | QGenericArgument val7, |
2923 | QGenericArgument val8, |
2924 | QGenericArgument val9) const |
2925 | { |
2926 | if (!gadget || !mobj) |
2927 | return false; |
2928 | |
2929 | // check return type |
2930 | if (returnValue.data()) { |
2931 | const char *retType = typeName(); |
2932 | if (qstrcmp(str1: returnValue.name(), str2: retType) != 0) { |
2933 | // normalize the return value as well |
2934 | QByteArray normalized = QMetaObject::normalizedType(type: returnValue.name()); |
2935 | if (qstrcmp(str1: normalized.constData(), str2: retType) != 0) { |
2936 | // String comparison failed, try compare the metatype. |
2937 | int t = returnType(); |
2938 | if (t == QMetaType::UnknownType || t != QMetaType::fromName(name: normalized).id()) |
2939 | return false; |
2940 | } |
2941 | } |
2942 | } |
2943 | |
2944 | // check argument count (we don't allow invoking a method if given too few arguments) |
2945 | const char *typeNames[] = { |
2946 | returnValue.name(), |
2947 | val0.name(), |
2948 | val1.name(), |
2949 | val2.name(), |
2950 | val3.name(), |
2951 | val4.name(), |
2952 | val5.name(), |
2953 | val6.name(), |
2954 | val7.name(), |
2955 | val8.name(), |
2956 | val9.name() |
2957 | }; |
2958 | int paramCount; |
2959 | for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) { |
2960 | if (qstrlen(str: typeNames[paramCount]) <= 0) |
2961 | break; |
2962 | } |
2963 | if (paramCount <= QMetaMethodPrivate::get(q: this)->parameterCount()) |
2964 | return false; |
2965 | |
2966 | // invoke! |
2967 | void *param[] = { |
2968 | returnValue.data(), |
2969 | val0.data(), |
2970 | val1.data(), |
2971 | val2.data(), |
2972 | val3.data(), |
2973 | val4.data(), |
2974 | val5.data(), |
2975 | val6.data(), |
2976 | val7.data(), |
2977 | val8.data(), |
2978 | val9.data() |
2979 | }; |
2980 | int idx_relative = QMetaMethodPrivate::get(q: this)->ownMethodIndex(); |
2981 | Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6); |
2982 | QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall; |
2983 | if (!callFunction) |
2984 | return false; |
2985 | callFunction(reinterpret_cast<QObject*>(gadget), QMetaObject::InvokeMetaMethod, idx_relative, param); |
2986 | return true; |
2987 | } |
2988 | |
2989 | /*! |
2990 | \fn bool QMetaMethod::invokeOnGadget(void *gadget, |
2991 | QGenericArgument val0 = QGenericArgument(0), |
2992 | QGenericArgument val1 = QGenericArgument(), |
2993 | QGenericArgument val2 = QGenericArgument(), |
2994 | QGenericArgument val3 = QGenericArgument(), |
2995 | QGenericArgument val4 = QGenericArgument(), |
2996 | QGenericArgument val5 = QGenericArgument(), |
2997 | QGenericArgument val6 = QGenericArgument(), |
2998 | QGenericArgument val7 = QGenericArgument(), |
2999 | QGenericArgument val8 = QGenericArgument(), |
3000 | QGenericArgument val9 = QGenericArgument()) const |
3001 | |
3002 | \overload |
3003 | \obsolete [6.5] Please use the variadic overload of this function |
3004 | \since 5.5 |
3005 | |
3006 | This overload invokes this method for a \a gadget and ignores return values. |
3007 | */ |
3008 | |
3009 | /*! |
3010 | \class QMetaEnum |
3011 | \inmodule QtCore |
3012 | \brief The QMetaEnum class provides meta-data about an enumerator. |
3013 | |
3014 | \ingroup objectmodel |
3015 | |
3016 | Use name() for the enumerator's name. The enumerator's keys (names |
3017 | of each enumerated item) are returned by key(); use keyCount() to find |
3018 | the number of keys. isFlag() returns whether the enumerator is |
3019 | meant to be used as a flag, meaning that its values can be combined |
3020 | using the OR operator. |
3021 | |
3022 | The conversion functions keyToValue(), valueToKey(), keysToValue(), |
3023 | and valueToKeys() allow conversion between the integer |
3024 | representation of an enumeration or set value and its literal |
3025 | representation. The scope() function returns the class scope this |
3026 | enumerator was declared in. |
3027 | |
3028 | \sa QMetaObject, QMetaMethod, QMetaProperty |
3029 | */ |
3030 | |
3031 | /*! |
3032 | \fn bool QMetaEnum::isValid() const |
3033 | |
3034 | Returns \c true if this enum is valid (has a name); otherwise returns |
3035 | false. |
3036 | |
3037 | \sa name() |
3038 | */ |
3039 | |
3040 | /*! |
3041 | \fn const QMetaObject *QMetaEnum::enclosingMetaObject() const |
3042 | \internal |
3043 | */ |
3044 | |
3045 | |
3046 | /*! |
3047 | \fn QMetaEnum::QMetaEnum() |
3048 | \internal |
3049 | */ |
3050 | |
3051 | /*! |
3052 | Returns the name of the type (without the scope). |
3053 | |
3054 | For example, the Qt::Key enumeration has \c |
3055 | Key as the type name and \l Qt as the scope. |
3056 | |
3057 | For flags this returns the name of the flag type, not the |
3058 | name of the enum type. |
3059 | |
3060 | \sa isValid(), scope(), enumName() |
3061 | */ |
3062 | const char *QMetaEnum::name() const |
3063 | { |
3064 | if (!mobj) |
3065 | return nullptr; |
3066 | return rawStringData(mo: mobj, index: data.name()); |
3067 | } |
3068 | |
3069 | /*! |
3070 | Returns the enum name of the flag (without the scope). |
3071 | |
3072 | For example, the Qt::AlignmentFlag flag has \c |
3073 | AlignmentFlag as the enum name, but \c Alignment as the type name. |
3074 | Non flag enums has the same type and enum names. |
3075 | |
3076 | Enum names have the same scope as the type name. |
3077 | |
3078 | \since 5.12 |
3079 | \sa isValid(), name() |
3080 | */ |
3081 | const char *QMetaEnum::enumName() const |
3082 | { |
3083 | if (!mobj) |
3084 | return nullptr; |
3085 | return rawStringData(mo: mobj, index: data.alias()); |
3086 | } |
3087 | |
3088 | /*! |
3089 | Returns the meta type of the enum. |
3090 | |
3091 | If the QMetaObject that this enum is part of was generated with Qt 6.5 or |
3092 | earlier, this will be an invalid meta type. |
3093 | |
3094 | \note This is the meta type of the enum itself, not of its underlying |
3095 | integral type. You can retrieve the meta type of the underlying type of the |
3096 | enum using \l{QMetaType::underlyingType()}. |
3097 | |
3098 | \since 6.6 |
3099 | */ |
3100 | QMetaType QMetaEnum::metaType() const |
3101 | { |
3102 | if (!mobj) |
3103 | return {}; |
3104 | |
3105 | const QMetaObjectPrivate *p = priv(data: mobj->d.data); |
3106 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
3107 | if (p->revision < 12) |
3108 | QMetaType(); |
3109 | #endif |
3110 | |
3111 | return QMetaType(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]); |
3112 | } |
3113 | |
3114 | /*! |
3115 | Returns the number of keys. |
3116 | |
3117 | \sa key() |
3118 | */ |
3119 | int QMetaEnum::keyCount() const |
3120 | { |
3121 | if (!mobj) |
3122 | return 0; |
3123 | return data.keyCount(); |
3124 | } |
3125 | |
3126 | /*! |
3127 | Returns the key with the given \a index, or \nullptr if no such key exists. |
3128 | |
3129 | \sa keyCount(), value(), valueToKey() |
3130 | */ |
3131 | const char *QMetaEnum::key(int index) const |
3132 | { |
3133 | if (!mobj) |
3134 | return nullptr; |
3135 | if (index >= 0 && index < int(data.keyCount())) |
3136 | return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2*index]); |
3137 | return nullptr; |
3138 | } |
3139 | |
3140 | /*! |
3141 | Returns the value with the given \a index; or returns -1 if there |
3142 | is no such value. |
3143 | |
3144 | \sa keyCount(), key(), keyToValue() |
3145 | */ |
3146 | int QMetaEnum::value(int index) const |
3147 | { |
3148 | if (!mobj) |
3149 | return 0; |
3150 | if (index >= 0 && index < int(data.keyCount())) |
3151 | return mobj->d.data[data.data() + 2 * index + 1]; |
3152 | return -1; |
3153 | } |
3154 | |
3155 | /*! |
3156 | Returns \c true if this enumerator is used as a flag; otherwise returns |
3157 | false. |
3158 | |
3159 | When used as flags, enumerators can be combined using the OR |
3160 | operator. |
3161 | |
3162 | \sa keysToValue(), valueToKeys() |
3163 | */ |
3164 | bool QMetaEnum::isFlag() const |
3165 | { |
3166 | if (!mobj) |
3167 | return false; |
3168 | return data.flags() & EnumIsFlag; |
3169 | } |
3170 | |
3171 | /*! |
3172 | \since 5.8 |
3173 | |
3174 | Returns \c true if this enumerator is declared as a C++11 enum class; |
3175 | otherwise returns false. |
3176 | */ |
3177 | bool QMetaEnum::isScoped() const |
3178 | { |
3179 | if (!mobj) |
3180 | return false; |
3181 | return data.flags() & EnumIsScoped; |
3182 | } |
3183 | |
3184 | /*! |
3185 | Returns the scope this enumerator was declared in. |
3186 | |
3187 | For example, the Qt::AlignmentFlag enumeration has \c Qt as |
3188 | the scope and \c AlignmentFlag as the name. |
3189 | |
3190 | \sa name() |
3191 | */ |
3192 | const char *QMetaEnum::scope() const |
3193 | { |
3194 | return mobj ? mobj->className() : nullptr; |
3195 | } |
3196 | |
3197 | static bool isScopeMatch(QByteArrayView scope, const QMetaEnum *e) |
3198 | { |
3199 | const QByteArrayView className = e->enclosingMetaObject()->className(); |
3200 | |
3201 | // Typical use-cases: |
3202 | // a) Unscoped: namespace N { class C { enum E { F }; }; }; key == "N::C::F" |
3203 | // b) Scoped: namespace N { class C { enum class E { F }; }; }; key == "N::C::E::F" |
3204 | if (scope == className) |
3205 | return true; |
3206 | |
3207 | // Not using name() because if isFlag() is true, we want the actual name |
3208 | // of the enum, e.g. "MyFlag", not "MyFlags", e.g. |
3209 | // enum MyFlag { F1, F2 }; Q_DECLARE_FLAGS(MyFlags, MyFlag); |
3210 | QByteArrayView name = e->enumName(); |
3211 | |
3212 | // Match fully qualified enumerator in unscoped enums, key == "N::C::E::F" |
3213 | // equivalent to use-case "a" above |
3214 | const auto sz = className.size(); |
3215 | if (scope.size() == sz + qsizetype(qstrlen(str: "::")) + name.size() |
3216 | && scope.startsWith(other: className) |
3217 | && scope.sliced(pos: sz, n: 2) == "::" |
3218 | && scope.sliced(pos: sz + 2) == name) |
3219 | return true; |
3220 | |
3221 | return false; |
3222 | } |
3223 | |
3224 | /*! |
3225 | Returns the integer value of the given enumeration \a key, or -1 |
3226 | if \a key is not defined. |
3227 | |
3228 | If \a key is not defined, *\a{ok} is set to false; otherwise |
3229 | *\a{ok} is set to true. |
3230 | |
3231 | For flag types, use keysToValue(). |
3232 | |
3233 | \sa valueToKey(), isFlag(), keysToValue() |
3234 | */ |
3235 | int QMetaEnum::keyToValue(const char *key, bool *ok) const |
3236 | { |
3237 | if (ok != nullptr) |
3238 | *ok = false; |
3239 | if (!mobj || !key) |
3240 | return -1; |
3241 | |
3242 | const auto [scope, enumKey] = parse_scope(qualifiedKey: QLatin1StringView(key)); |
3243 | for (int i = 0; i < int(data.keyCount()); ++i) { |
3244 | if ((!scope || isScopeMatch(scope: *scope, e: this)) |
3245 | && enumKey == stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2 * i])) { |
3246 | if (ok != nullptr) |
3247 | *ok = true; |
3248 | return mobj->d.data[data.data() + 2 * i + 1]; |
3249 | } |
3250 | } |
3251 | return -1; |
3252 | } |
3253 | |
3254 | /*! |
3255 | Returns the string that is used as the name of the given |
3256 | enumeration \a value, or \nullptr if \a value is not defined. |
3257 | |
3258 | For flag types, use valueToKeys(). |
3259 | |
3260 | \sa isFlag(), valueToKeys() |
3261 | */ |
3262 | const char *QMetaEnum::valueToKey(int value) const |
3263 | { |
3264 | if (!mobj) |
3265 | return nullptr; |
3266 | for (int i = 0; i < int(data.keyCount()); ++i) |
3267 | if (value == (int)mobj->d.data[data.data() + 2 * i + 1]) |
3268 | return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2 * i]); |
3269 | return nullptr; |
3270 | } |
3271 | |
3272 | static bool parseEnumFlags(QByteArrayView v, QVarLengthArray<QByteArrayView, 10> &list) |
3273 | { |
3274 | v = v.trimmed(); |
3275 | if (v.empty()) { |
3276 | qWarning(msg: "QMetaEnum::keysToValue: empty keys string."); |
3277 | return false; |
3278 | } |
3279 | |
3280 | qsizetype sep = v.indexOf(ch: '|', from: 0); |
3281 | if (sep == 0) { |
3282 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, starts with '|', \"%s\"", |
3283 | v.constData()); |
3284 | return false; |
3285 | } |
3286 | |
3287 | if (sep == -1) { // One flag |
3288 | list.push_back(t: v); |
3289 | return true; |
3290 | } |
3291 | |
3292 | if (v.endsWith(c: '|')) { |
3293 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, ends with '|', \"%s\"", |
3294 | v.constData()); |
3295 | return false; |
3296 | } |
3297 | |
3298 | const auto begin = v.begin(); |
3299 | const auto end = v.end(); |
3300 | auto b = begin; |
3301 | for (; b != end && sep != -1; sep = v.indexOf(ch: '|', from: sep)) { |
3302 | list.push_back(t: {b, begin + sep}); |
3303 | ++sep; // Skip over '|' |
3304 | b = begin + sep; |
3305 | if (*b == '|') { |
3306 | qWarning(msg: "QMetaEnum::keysToValue: malformed keys string, has two consecutive '|': " |
3307 | "\"%s\"", v.constData()); |
3308 | return false; |
3309 | } |
3310 | } |
3311 | |
3312 | // The rest of the string |
3313 | list.push_back(t: {b, end}); |
3314 | return true; |
3315 | } |
3316 | |
3317 | /*! |
3318 | Returns the value derived from combining together the values of |
3319 | the \a keys using the OR operator, or -1 if \a keys is not |
3320 | defined. Note that the strings in \a keys must be '|'-separated. |
3321 | |
3322 | If \a keys is not defined, *\a{ok} is set to false; otherwise |
3323 | *\a{ok} is set to true. |
3324 | |
3325 | \sa isFlag(), valueToKey(), valueToKeys() |
3326 | */ |
3327 | int QMetaEnum::keysToValue(const char *keys, bool *ok) const |
3328 | { |
3329 | if (ok != nullptr) |
3330 | *ok = false; |
3331 | if (!mobj || !keys) |
3332 | return -1; |
3333 | |
3334 | auto lookup = [&] (QByteArrayView key) -> std::optional<int> { |
3335 | for (int i = data.keyCount() - 1; i >= 0; --i) { |
3336 | if (key == stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2*i])) |
3337 | return mobj->d.data[data.data() + 2*i + 1]; |
3338 | } |
3339 | return std::nullopt; |
3340 | }; |
3341 | |
3342 | int value = 0; |
3343 | QVarLengthArray<QByteArrayView, 10> list; |
3344 | const bool r = parseEnumFlags(v: QByteArrayView{keys}, list); |
3345 | if (!r) |
3346 | return -1; |
3347 | for (const auto &untrimmed : list) { |
3348 | const auto parsed = parse_scope(qualifiedKey: untrimmed.trimmed()); |
3349 | if (parsed.scope && !isScopeMatch(scope: *parsed.scope, e: this)) |
3350 | return -1; // wrong type name in qualified name |
3351 | if (auto thisValue = lookup(parsed.key)) |
3352 | value |= *thisValue; |
3353 | else |
3354 | return -1; // no such enumerator |
3355 | } |
3356 | if (ok != nullptr) |
3357 | *ok = true; |
3358 | return value; |
3359 | } |
3360 | |
3361 | namespace |
3362 | { |
3363 | template <typename String, typename Container, typename Separator> |
3364 | void join_reversed(String &s, const Container &c, Separator sep) |
3365 | { |
3366 | if (c.empty()) |
3367 | return; |
3368 | qsizetype len = qsizetype(c.size()) - 1; // N - 1 separators |
3369 | for (auto &e : c) |
3370 | len += qsizetype(e.size()); // N parts |
3371 | s.reserve(len); |
3372 | bool first = true; |
3373 | for (auto rit = c.rbegin(), rend = c.rend(); rit != rend; ++rit) { |
3374 | const auto &e = *rit; |
3375 | if (!first) |
3376 | s.append(sep); |
3377 | first = false; |
3378 | s.append(e.data(), e.size()); |
3379 | } |
3380 | } |
3381 | } // unnamed namespace |
3382 | |
3383 | /*! |
3384 | Returns a byte array of '|'-separated keys that represents the |
3385 | given \a value. |
3386 | |
3387 | \sa isFlag(), valueToKey(), keysToValue() |
3388 | */ |
3389 | QByteArray QMetaEnum::valueToKeys(int value) const |
3390 | { |
3391 | QByteArray keys; |
3392 | if (!mobj) |
3393 | return keys; |
3394 | QVarLengthArray<QByteArrayView, sizeof(int) * CHAR_BIT> parts; |
3395 | int v = value; |
3396 | // reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first. |
3397 | for (int i = data.keyCount() - 1; i >= 0; --i) { |
3398 | int k = mobj->d.data[data.data() + 2 * i + 1]; |
3399 | if ((k != 0 && (v & k) == k) || (k == value)) { |
3400 | v = v & ~k; |
3401 | parts.push_back(t: stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2 * i])); |
3402 | } |
3403 | } |
3404 | join_reversed(s&: keys, c: parts, sep: '|'); |
3405 | return keys; |
3406 | } |
3407 | |
3408 | /*! |
3409 | \internal |
3410 | */ |
3411 | QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index) |
3412 | : mobj(mobj), data({ .d: mobj->d.data + priv(data: mobj->d.data)->enumeratorData + index * Data::Size }) |
3413 | { |
3414 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount); |
3415 | } |
3416 | |
3417 | int QMetaEnum::Data::index(const QMetaObject *mobj) const |
3418 | { |
3419 | return (d - mobj->d.data - priv(data: mobj->d.data)->enumeratorData) / Size; |
3420 | } |
3421 | |
3422 | /*! |
3423 | \fn template<typename T> QMetaEnum QMetaEnum::fromType() |
3424 | \since 5.5 |
3425 | |
3426 | Returns the QMetaEnum corresponding to the type in the template parameter. |
3427 | The enum needs to be declared with Q_ENUM. |
3428 | */ |
3429 | |
3430 | /*! |
3431 | \class QMetaProperty |
3432 | \inmodule QtCore |
3433 | \brief The QMetaProperty class provides meta-data about a property. |
3434 | |
3435 | \ingroup objectmodel |
3436 | |
3437 | Property meta-data is obtained from an object's meta-object. See |
3438 | QMetaObject::property() and QMetaObject::propertyCount() for |
3439 | details. |
3440 | |
3441 | \section1 Property Meta-Data |
3442 | |
3443 | A property has a name() and a type(), as well as various |
3444 | attributes that specify its behavior: isReadable(), isWritable(), |
3445 | isDesignable(), isScriptable(), revision(), and isStored(). |
3446 | |
3447 | If the property is an enumeration, isEnumType() returns \c true; if the |
3448 | property is an enumeration that is also a flag (i.e. its values |
3449 | can be combined using the OR operator), isEnumType() and |
3450 | isFlagType() both return true. The enumerator for these types is |
3451 | available from enumerator(). |
3452 | |
3453 | The property's values are set and retrieved with read(), write(), |
3454 | and reset(); they can also be changed through QObject's set and get |
3455 | functions. See QObject::setProperty() and QObject::property() for |
3456 | details. |
3457 | |
3458 | \section1 Copying and Assignment |
3459 | |
3460 | QMetaProperty objects can be copied by value. However, each copy will |
3461 | refer to the same underlying property meta-data. |
3462 | |
3463 | \sa QMetaObject, QMetaEnum, QMetaMethod, {Qt's Property System} |
3464 | */ |
3465 | |
3466 | /*! |
3467 | \fn bool QMetaProperty::isValid() const |
3468 | |
3469 | Returns \c true if this property is valid (readable); otherwise |
3470 | returns \c false. |
3471 | |
3472 | \sa isReadable() |
3473 | */ |
3474 | |
3475 | /*! |
3476 | \fn const QMetaObject *QMetaProperty::enclosingMetaObject() const |
3477 | \internal |
3478 | */ |
3479 | |
3480 | /*! |
3481 | \fn QMetaProperty::QMetaProperty() |
3482 | \internal |
3483 | */ |
3484 | |
3485 | /*! |
3486 | Returns this property's name. |
3487 | |
3488 | \sa type(), typeName() |
3489 | */ |
3490 | const char *QMetaProperty::name() const |
3491 | { |
3492 | if (!mobj) |
3493 | return nullptr; |
3494 | return rawStringData(mo: mobj, index: data.name()); |
3495 | } |
3496 | |
3497 | /*! |
3498 | Returns the name of this property's type. |
3499 | |
3500 | \sa type(), name() |
3501 | */ |
3502 | const char *QMetaProperty::typeName() const |
3503 | { |
3504 | if (!mobj) |
3505 | return nullptr; |
3506 | // TODO: can the metatype be invalid for dynamic metaobjects? |
3507 | if (const auto mt = metaType(); mt.isValid()) |
3508 | return mt.name(); |
3509 | return typeNameFromTypeInfo(mo: mobj, typeInfo: data.type()).constData(); |
3510 | } |
3511 | |
3512 | /*! \fn QVariant::Type QMetaProperty::type() const |
3513 | \deprecated |
3514 | |
3515 | Returns this property's type. The return value is one |
3516 | of the values of the QVariant::Type enumeration. |
3517 | |
3518 | \sa typeName(), name(), metaType() |
3519 | */ |
3520 | |
3521 | /*! \fn int QMetaProperty::userType() const |
3522 | \since 4.2 |
3523 | |
3524 | Returns this property's user type. The return value is one |
3525 | of the values that are registered with QMetaType. |
3526 | |
3527 | This is equivalent to metaType().id() |
3528 | |
3529 | \sa type(), QMetaType, typeName(), metaType() |
3530 | */ |
3531 | |
3532 | /*! \fn int QMetaProperty::typeId() const |
3533 | \since 6.0 |
3534 | |
3535 | Returns the storage type of the property. This is |
3536 | the same as metaType().id(). |
3537 | |
3538 | \sa QMetaType, typeName(), metaType() |
3539 | */ |
3540 | |
3541 | /*! |
3542 | \since 6.0 |
3543 | |
3544 | Returns this property's QMetaType. |
3545 | |
3546 | \sa QMetaType |
3547 | */ |
3548 | QMetaType QMetaProperty::metaType() const |
3549 | { |
3550 | if (!mobj) |
3551 | return {}; |
3552 | return QMetaType(mobj->d.metaTypes[data.index(mobj)]); |
3553 | } |
3554 | |
3555 | int QMetaProperty::Data::index(const QMetaObject *mobj) const |
3556 | { |
3557 | return (d - mobj->d.data - priv(data: mobj->d.data)->propertyData) / Size; |
3558 | } |
3559 | |
3560 | /*! |
3561 | \since 4.6 |
3562 | |
3563 | Returns this property's index. |
3564 | */ |
3565 | int QMetaProperty::propertyIndex() const |
3566 | { |
3567 | if (!mobj) |
3568 | return -1; |
3569 | return data.index(mobj) + mobj->propertyOffset(); |
3570 | } |
3571 | |
3572 | /*! |
3573 | \since 5.14 |
3574 | |
3575 | Returns this property's index relative within the enclosing meta object. |
3576 | */ |
3577 | int QMetaProperty::relativePropertyIndex() const |
3578 | { |
3579 | if (!mobj) |
3580 | return -1; |
3581 | return data.index(mobj); |
3582 | } |
3583 | |
3584 | /*! |
3585 | Returns \c true if the property's type is an enumeration value that |
3586 | is used as a flag; otherwise returns \c false. |
3587 | |
3588 | Flags can be combined using the OR operator. A flag type is |
3589 | implicitly also an enum type. |
3590 | |
3591 | \sa isEnumType(), enumerator(), QMetaEnum::isFlag() |
3592 | */ |
3593 | |
3594 | bool QMetaProperty::isFlagType() const |
3595 | { |
3596 | return isEnumType() && menum.isFlag(); |
3597 | } |
3598 | |
3599 | /*! |
3600 | Returns \c true if the property's type is an enumeration value; |
3601 | otherwise returns \c false. |
3602 | |
3603 | \sa enumerator(), isFlagType() |
3604 | */ |
3605 | bool QMetaProperty::isEnumType() const |
3606 | { |
3607 | if (!mobj) |
3608 | return false; |
3609 | return (data.flags() & EnumOrFlag) && menum.name(); |
3610 | } |
3611 | |
3612 | /*! |
3613 | \internal |
3614 | |
3615 | Returns \c true if the property has a C++ setter function that |
3616 | follows Qt's standard "name" / "setName" pattern. Designer and uic |
3617 | query hasStdCppSet() in order to avoid expensive |
3618 | QObject::setProperty() calls. All properties in Qt [should] follow |
3619 | this pattern. |
3620 | */ |
3621 | bool QMetaProperty::hasStdCppSet() const |
3622 | { |
3623 | if (!mobj) |
3624 | return false; |
3625 | return (data.flags() & StdCppSet); |
3626 | } |
3627 | |
3628 | /*! |
3629 | \internal |
3630 | |
3631 | Returns \c true if the property is an alias. |
3632 | This is for instance true for a property declared in QML |
3633 | as 'property alias'. |
3634 | */ |
3635 | bool QMetaProperty::isAlias() const |
3636 | { |
3637 | if (!mobj) |
3638 | return false; |
3639 | return (data.flags() & Alias); |
3640 | } |
3641 | |
3642 | #if QT_DEPRECATED_SINCE(6, 4) |
3643 | /*! |
3644 | \internal |
3645 | Historically: |
3646 | Executes metacall with QMetaObject::RegisterPropertyMetaType flag. |
3647 | Returns id of registered type or QMetaType::UnknownType if a type |
3648 | could not be registered for any reason. |
3649 | Obsolete since Qt 6 |
3650 | */ |
3651 | int QMetaProperty::registerPropertyType() const |
3652 | { |
3653 | return typeId(); |
3654 | } |
3655 | #endif |
3656 | |
3657 | QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index) |
3658 | : mobj(mobj), |
3659 | data(getMetaPropertyData(mobj, index)) |
3660 | { |
3661 | Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->propertyCount); |
3662 | // The code below here just resolves menum if the property is an enum type: |
3663 | if (!(data.flags() & EnumOrFlag) || !metaType().flags().testFlag(flag: QMetaType::IsEnumeration)) |
3664 | return; |
3665 | QByteArrayView enum_name = typeNameFromTypeInfo(mo: mobj, typeInfo: data.type()); |
3666 | menum = mobj->enumerator(index: QMetaObjectPrivate::indexOfEnumerator(m: mobj, name: enum_name)); |
3667 | if (menum.isValid()) |
3668 | return; |
3669 | |
3670 | QByteArrayView scope_name; |
3671 | const auto parsed = parse_scope(qualifiedKey: enum_name); |
3672 | if (parsed.scope) { |
3673 | scope_name = *parsed.scope; |
3674 | enum_name = parsed.key; |
3675 | } else { |
3676 | scope_name = objectClassName(m: mobj); |
3677 | } |
3678 | |
3679 | const QMetaObject *scope = nullptr; |
3680 | if (scope_name == "Qt") |
3681 | scope = &Qt::staticMetaObject; |
3682 | else |
3683 | scope = QMetaObject_findMetaObject(self: mobj, name: QByteArrayView(scope_name)); |
3684 | |
3685 | if (scope) |
3686 | menum = scope->enumerator(index: QMetaObjectPrivate::indexOfEnumerator(m: scope, name: enum_name)); |
3687 | } |
3688 | |
3689 | /*! |
3690 | \internal |
3691 | Constructs the \c QMetaProperty::Data for the \a index th property of \a mobj |
3692 | */ |
3693 | QMetaProperty::Data QMetaProperty::getMetaPropertyData(const QMetaObject *mobj, int index) |
3694 | { |
3695 | return { .d: mobj->d.data + priv(data: mobj->d.data)->propertyData + index * Data::Size }; |
3696 | } |
3697 | |
3698 | /*! |
3699 | Returns the enumerator if this property's type is an enumerator |
3700 | type; otherwise the returned value is undefined. |
3701 | |
3702 | \sa isEnumType(), isFlagType() |
3703 | */ |
3704 | QMetaEnum QMetaProperty::enumerator() const |
3705 | { |
3706 | return menum; |
3707 | } |
3708 | |
3709 | /*! |
3710 | Reads the property's value from the given \a object. Returns the value |
3711 | if it was able to read it; otherwise returns an invalid variant. |
3712 | |
3713 | \sa write(), reset(), isReadable() |
3714 | */ |
3715 | QVariant QMetaProperty::read(const QObject *object) const |
3716 | { |
3717 | if (!object || !mobj) |
3718 | return QVariant(); |
3719 | |
3720 | // the status variable is changed by qt_metacall to indicate what it did |
3721 | // this feature is currently only used by Qt D-Bus and should not be depended |
3722 | // upon. Don't change it without looking into QDBusAbstractInterface first |
3723 | // -1 (unchanged): normal qt_metacall, result stored in argv[0] |
3724 | // changed: result stored directly in value |
3725 | int status = -1; |
3726 | QVariant value; |
3727 | void *argv[] = { nullptr, &value, &status }; |
3728 | QMetaType t(mobj->d.metaTypes[data.index(mobj)]); |
3729 | if (t == QMetaType::fromType<QVariant>()) { |
3730 | argv[0] = &value; |
3731 | } else { |
3732 | value = QVariant(t, nullptr); |
3733 | argv[0] = value.data(); |
3734 | } |
3735 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) { |
3736 | mobj->d.static_metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty, data.index(mobj), argv); |
3737 | } else { |
3738 | QMetaObject::metacall(object: const_cast<QObject*>(object), cl: QMetaObject::ReadProperty, |
3739 | idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3740 | } |
3741 | |
3742 | if (status != -1) |
3743 | return value; |
3744 | if (t != QMetaType::fromType<QVariant>() && argv[0] != value.data()) |
3745 | // pointer or reference |
3746 | return QVariant(t, argv[0]); |
3747 | return value; |
3748 | } |
3749 | |
3750 | /*! |
3751 | Writes \a value as the property's value to the given \a object. Returns |
3752 | true if the write succeeded; otherwise returns \c false. |
3753 | |
3754 | If \a value is not of the same type as the property, a conversion |
3755 | is attempted. An empty QVariant() is equivalent to a call to reset() |
3756 | if this property is resettable, or setting a default-constructed object |
3757 | otherwise. |
3758 | |
3759 | \note This function internally makes a copy of \a value. Prefer to use the |
3760 | rvalue overload when possible. |
3761 | |
3762 | \sa read(), reset(), isWritable() |
3763 | */ |
3764 | bool QMetaProperty::write(QObject *object, const QVariant &value) const |
3765 | { |
3766 | if (!object || !isWritable()) |
3767 | return false; |
3768 | return write(obj: object, value: QVariant(value)); |
3769 | } |
3770 | |
3771 | /*! |
3772 | \overload |
3773 | \since 6.6 |
3774 | */ |
3775 | bool QMetaProperty::write(QObject *object, QVariant &&v) const |
3776 | { |
3777 | if (!object || !isWritable()) |
3778 | return false; |
3779 | QMetaType t(mobj->d.metaTypes[data.index(mobj)]); |
3780 | if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) { |
3781 | if (isEnumType() && !t.metaObject() && v.metaType() == QMetaType::fromType<QString>()) { |
3782 | // Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM) |
3783 | // means the QMetaType has no associated QMetaObject, so it can't |
3784 | // do the conversion (see qmetatype.cpp:convertToEnum()). |
3785 | bool ok; |
3786 | if (isFlagType()) |
3787 | v = QVariant(menum.keysToValue(keys: v.toByteArray(), ok: &ok)); |
3788 | else |
3789 | v = QVariant(menum.keyToValue(key: v.toByteArray(), ok: &ok)); |
3790 | if (!ok) |
3791 | return false; |
3792 | } |
3793 | if (!v.isValid()) { |
3794 | if (isResettable()) |
3795 | return reset(obj: object); |
3796 | v = QVariant(t, nullptr); |
3797 | } else if (!v.convert(type: t)) { |
3798 | return false; |
3799 | } |
3800 | } |
3801 | // the status variable is changed by qt_metacall to indicate what it did |
3802 | // this feature is currently only used by Qt D-Bus and should not be depended |
3803 | // upon. Don't change it without looking into QDBusAbstractInterface first |
3804 | // -1 (unchanged): normal qt_metacall, result stored in argv[0] |
3805 | // changed: result stored directly in value, return the value of status |
3806 | int status = -1; |
3807 | // the flags variable is used by the declarative module to implement |
3808 | // interception of property writes. |
3809 | int flags = 0; |
3810 | void *argv[] = { nullptr, &v, &status, &flags }; |
3811 | if (t == QMetaType::fromType<QVariant>()) |
3812 | argv[0] = &v; |
3813 | else |
3814 | argv[0] = v.data(); |
3815 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) |
3816 | mobj->d.static_metacall(object, QMetaObject::WriteProperty, data.index(mobj), argv); |
3817 | else |
3818 | QMetaObject::metacall(object, cl: QMetaObject::WriteProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3819 | |
3820 | return status; |
3821 | } |
3822 | |
3823 | /*! |
3824 | Resets the property for the given \a object with a reset method. |
3825 | Returns \c true if the reset worked; otherwise returns \c false. |
3826 | |
3827 | Reset methods are optional; only a few properties support them. |
3828 | |
3829 | \sa read(), write() |
3830 | */ |
3831 | bool QMetaProperty::reset(QObject *object) const |
3832 | { |
3833 | if (!object || !mobj || !isResettable()) |
3834 | return false; |
3835 | void *argv[] = { nullptr }; |
3836 | if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) |
3837 | mobj->d.static_metacall(object, QMetaObject::ResetProperty, data.index(mobj), argv); |
3838 | else |
3839 | QMetaObject::metacall(object, cl: QMetaObject::ResetProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3840 | return true; |
3841 | } |
3842 | |
3843 | /*! |
3844 | \since 6.0 |
3845 | Returns the bindable interface for the property on a given \a object. |
3846 | |
3847 | If the property doesn't support bindings, the returned interface will be |
3848 | invalid. |
3849 | |
3850 | \sa QObjectBindableProperty, QProperty, isBindable() |
3851 | */ |
3852 | QUntypedBindable QMetaProperty::bindable(QObject *object) const |
3853 | { |
3854 | QUntypedBindable bindable; |
3855 | void * argv[1] { &bindable }; |
3856 | mobj->metacall(object, cl: QMetaObject::BindableProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv); |
3857 | return bindable; |
3858 | } |
3859 | /*! |
3860 | \since 5.5 |
3861 | |
3862 | Reads the property's value from the given \a gadget. Returns the value |
3863 | if it was able to read it; otherwise returns an invalid variant. |
3864 | |
3865 | This function should only be used if this is a property of a Q_GADGET |
3866 | */ |
3867 | QVariant QMetaProperty::readOnGadget(const void *gadget) const |
3868 | { |
3869 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3870 | return read(object: reinterpret_cast<const QObject*>(gadget)); |
3871 | } |
3872 | |
3873 | /*! |
3874 | \since 5.5 |
3875 | |
3876 | Writes \a value as the property's value to the given \a gadget. Returns |
3877 | true if the write succeeded; otherwise returns \c false. |
3878 | |
3879 | This function should only be used if this is a property of a Q_GADGET |
3880 | */ |
3881 | bool QMetaProperty::writeOnGadget(void *gadget, const QVariant &value) const |
3882 | { |
3883 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3884 | return write(object: reinterpret_cast<QObject*>(gadget), value); |
3885 | } |
3886 | |
3887 | /*! |
3888 | \overload |
3889 | \since 6.6 |
3890 | */ |
3891 | bool QMetaProperty::writeOnGadget(void *gadget, QVariant &&value) const |
3892 | { |
3893 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3894 | return write(object: reinterpret_cast<QObject*>(gadget), v: std::move(value)); |
3895 | } |
3896 | |
3897 | /*! |
3898 | \since 5.5 |
3899 | |
3900 | Resets the property for the given \a gadget with a reset method. |
3901 | Returns \c true if the reset worked; otherwise returns \c false. |
3902 | |
3903 | Reset methods are optional; only a few properties support them. |
3904 | |
3905 | This function should only be used if this is a property of a Q_GADGET |
3906 | */ |
3907 | bool QMetaProperty::resetOnGadget(void *gadget) const |
3908 | { |
3909 | Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall); |
3910 | return reset(object: reinterpret_cast<QObject*>(gadget)); |
3911 | } |
3912 | |
3913 | /*! |
3914 | Returns \c true if this property can be reset to a default value; otherwise |
3915 | returns \c false. |
3916 | |
3917 | \sa reset() |
3918 | */ |
3919 | bool QMetaProperty::isResettable() const |
3920 | { |
3921 | if (!mobj) |
3922 | return false; |
3923 | return data.flags() & Resettable; |
3924 | } |
3925 | |
3926 | /*! |
3927 | Returns \c true if this property is readable; otherwise returns \c false. |
3928 | |
3929 | \sa isWritable(), read(), isValid() |
3930 | */ |
3931 | bool QMetaProperty::isReadable() const |
3932 | { |
3933 | if (!mobj) |
3934 | return false; |
3935 | return data.flags() & Readable; |
3936 | } |
3937 | |
3938 | /*! |
3939 | Returns \c true if this property has a corresponding change notify signal; |
3940 | otherwise returns \c false. |
3941 | |
3942 | \sa notifySignal() |
3943 | */ |
3944 | bool QMetaProperty::hasNotifySignal() const |
3945 | { |
3946 | if (!mobj) |
3947 | return false; |
3948 | return data.notifyIndex() != uint(-1); |
3949 | } |
3950 | |
3951 | /*! |
3952 | \since 4.5 |
3953 | |
3954 | Returns the QMetaMethod instance of the property change notifying signal if |
3955 | one was specified, otherwise returns an invalid QMetaMethod. |
3956 | |
3957 | \sa hasNotifySignal() |
3958 | */ |
3959 | QMetaMethod QMetaProperty::notifySignal() const |
3960 | { |
3961 | int id = notifySignalIndex(); |
3962 | if (id != -1) |
3963 | return mobj->method(index: id); |
3964 | else |
3965 | return QMetaMethod(); |
3966 | } |
3967 | |
3968 | /*! |
3969 | \since 4.6 |
3970 | |
3971 | Returns the index of the property change notifying signal if one was |
3972 | specified, otherwise returns -1. |
3973 | |
3974 | \sa hasNotifySignal() |
3975 | */ |
3976 | int QMetaProperty::notifySignalIndex() const |
3977 | { |
3978 | if (!mobj || data.notifyIndex() == std::numeric_limits<uint>::max()) |
3979 | return -1; |
3980 | uint methodIndex = data.notifyIndex(); |
3981 | if (!(methodIndex & IsUnresolvedSignal)) |
3982 | return methodIndex + mobj->methodOffset(); |
3983 | methodIndex &= ~IsUnresolvedSignal; |
3984 | const QByteArray signalName = stringData(mo: mobj, index: methodIndex); |
3985 | const QMetaObject *m = mobj; |
3986 | // try 0-arg signal |
3987 | int idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(baseObject: &m, name: signalName, argc: 0, types: nullptr); |
3988 | if (idx >= 0) |
3989 | return idx + m->methodOffset(); |
3990 | // try 1-arg signal |
3991 | QArgumentType argType(typeId()); |
3992 | idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(baseObject: &m, name: signalName, argc: 1, types: &argType); |
3993 | if (idx >= 0) |
3994 | return idx + m->methodOffset(); |
3995 | qWarning(msg: "QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'", |
3996 | signalName.constData(), mobj->className(), name()); |
3997 | return -1; |
3998 | } |
3999 | |
4000 | // This method has been around for a while, but the documentation was marked \internal until 5.1 |
4001 | /*! |
4002 | \since 5.1 |
4003 | |
4004 | Returns the property revision if one was specified by Q_REVISION, otherwise |
4005 | returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded |
4006 | using QTypeRevision::fromEncodedVersion(). |
4007 | */ |
4008 | int QMetaProperty::revision() const |
4009 | { |
4010 | if (!mobj) |
4011 | return 0; |
4012 | return data.revision(); |
4013 | } |
4014 | |
4015 | /*! |
4016 | Returns \c true if this property is writable; otherwise returns |
4017 | false. |
4018 | |
4019 | \sa isReadable(), write() |
4020 | */ |
4021 | bool QMetaProperty::isWritable() const |
4022 | { |
4023 | if (!mobj) |
4024 | return false; |
4025 | return data.flags() & Writable; |
4026 | } |
4027 | |
4028 | /*! |
4029 | Returns \c false if the \c{Q_PROPERTY()}'s \c DESIGNABLE attribute |
4030 | is false; otherwise returns \c true. |
4031 | |
4032 | \sa isScriptable(), isStored() |
4033 | */ |
4034 | bool QMetaProperty::isDesignable() const |
4035 | { |
4036 | if (!mobj) |
4037 | return false; |
4038 | return data.flags() & Designable; |
4039 | } |
4040 | |
4041 | /*! |
4042 | Returns \c false if the \c{Q_PROPERTY()}'s \c SCRIPTABLE attribute |
4043 | is false; otherwise returns true. |
4044 | |
4045 | \sa isDesignable(), isStored() |
4046 | */ |
4047 | bool QMetaProperty::isScriptable() const |
4048 | { |
4049 | if (!mobj) |
4050 | return false; |
4051 | return data.flags() & Scriptable; |
4052 | } |
4053 | |
4054 | /*! |
4055 | Returns \c true if the property is stored; otherwise returns |
4056 | false. |
4057 | |
4058 | The function returns \c false if the |
4059 | \c{Q_PROPERTY()}'s \c STORED attribute is false; otherwise returns |
4060 | true. |
4061 | |
4062 | \sa isDesignable(), isScriptable() |
4063 | */ |
4064 | bool QMetaProperty::isStored() const |
4065 | { |
4066 | if (!mobj) |
4067 | return false; |
4068 | return data.flags() & Stored; |
4069 | } |
4070 | |
4071 | /*! |
4072 | Returns \c false if the \c {Q_PROPERTY()}'s \c USER attribute is false. |
4073 | Otherwise it returns true, indicating the property is designated as the |
4074 | \c USER property, i.e., the one that the user can edit or |
4075 | that is significant in some other way. |
4076 | |
4077 | \sa QMetaObject::userProperty(), isDesignable(), isScriptable() |
4078 | */ |
4079 | bool QMetaProperty::isUser() const |
4080 | { |
4081 | if (!mobj) |
4082 | return false; |
4083 | return data.flags() & User; |
4084 | } |
4085 | |
4086 | /*! |
4087 | \since 4.6 |
4088 | Returns \c true if the property is constant; otherwise returns \c false. |
4089 | |
4090 | A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute |
4091 | is set. |
4092 | */ |
4093 | bool QMetaProperty::isConstant() const |
4094 | { |
4095 | if (!mobj) |
4096 | return false; |
4097 | return data.flags() & Constant; |
4098 | } |
4099 | |
4100 | /*! |
4101 | \since 4.6 |
4102 | Returns \c true if the property is final; otherwise returns \c false. |
4103 | |
4104 | A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute |
4105 | is set. |
4106 | */ |
4107 | bool QMetaProperty::isFinal() const |
4108 | { |
4109 | if (!mobj) |
4110 | return false; |
4111 | return data.flags() & Final; |
4112 | } |
4113 | |
4114 | /*! |
4115 | \since 5.15 |
4116 | Returns \c true if the property is required; otherwise returns \c false. |
4117 | |
4118 | A property is final if the \c{Q_PROPERTY()}'s \c REQUIRED attribute |
4119 | is set. |
4120 | */ |
4121 | bool QMetaProperty::isRequired() const |
4122 | { |
4123 | if (!mobj) |
4124 | return false; |
4125 | return data.flags() & Required; |
4126 | } |
4127 | |
4128 | /*! |
4129 | \since 6.0 |
4130 | Returns \c true if the \c{Q_PROPERTY()} exposes binding functionality; otherwise returns false. |
4131 | |
4132 | This implies that you can create bindings that use this property as a dependency or install QPropertyObserver |
4133 | objects on this property. Unless the property is readonly, you can also set a binding on this property. |
4134 | |
4135 | \sa QProperty, isWritable(), bindable() |
4136 | */ |
4137 | bool QMetaProperty::isBindable() const |
4138 | { |
4139 | if (!mobj) |
4140 | return false; |
4141 | return (data.flags() & Bindable); |
4142 | } |
4143 | |
4144 | /*! |
4145 | \class QMetaClassInfo |
4146 | \inmodule QtCore |
4147 | |
4148 | \brief The QMetaClassInfo class provides additional information |
4149 | about a class. |
4150 | |
4151 | \ingroup objectmodel |
4152 | |
4153 | Class information items are simple \e{name}--\e{value} pairs that |
4154 | are specified using Q_CLASSINFO() in the source code. The |
4155 | information can be retrieved using name() and value(). For example: |
4156 | |
4157 | \snippet code/src_corelib_kernel_qmetaobject.cpp 5 |
4158 | |
4159 | This mechanism is free for you to use in your Qt applications. |
4160 | |
4161 | \note It's also used by the \l[ActiveQt]{Active Qt}, |
4162 | \l[QtDBus]{Qt D-Bus}, \l[QtQml]{Qt Qml}, and \l{Qt Remote Objects} |
4163 | modules. Some keys might be set when using these modules. |
4164 | |
4165 | \sa QMetaObject |
4166 | */ |
4167 | |
4168 | /*! |
4169 | \fn QMetaClassInfo::QMetaClassInfo() |
4170 | \internal |
4171 | */ |
4172 | |
4173 | /*! |
4174 | \fn const QMetaObject *QMetaClassInfo::enclosingMetaObject() const |
4175 | \internal |
4176 | */ |
4177 | |
4178 | /*! |
4179 | Returns the name of this item. |
4180 | |
4181 | \sa value() |
4182 | */ |
4183 | const char *QMetaClassInfo::name() const |
4184 | { |
4185 | if (!mobj) |
4186 | return nullptr; |
4187 | return rawStringData(mo: mobj, index: data.name()); |
4188 | } |
4189 | |
4190 | /*! |
4191 | Returns the value of this item. |
4192 | |
4193 | \sa name() |
4194 | */ |
4195 | const char *QMetaClassInfo::value() const |
4196 | { |
4197 | if (!mobj) |
4198 | return nullptr; |
4199 | return rawStringData(mo: mobj, index: data.value()); |
4200 | } |
4201 | |
4202 | /*! |
4203 | \class QMethodRawArguments |
4204 | \internal |
4205 | |
4206 | A wrapper class for the void ** arguments array used by the meta |
4207 | object system. If a slot uses a single argument of this type, |
4208 | the meta object system will pass the raw arguments array directly |
4209 | to the slot and set the arguments count in the slot description to |
4210 | zero, so that any signal can connect to it. |
4211 | |
4212 | This is used internally to implement signal relay functionality in |
4213 | our state machine and dbus. |
4214 | */ |
4215 | |
4216 | /*! |
4217 | \macro QMetaMethodArgument Q_ARG(Type, const Type &value) |
4218 | \relates QMetaObject |
4219 | |
4220 | This macro takes a \a Type and a \a value of that type and |
4221 | returns a QMetaMethodArgument, which can be passed to the template |
4222 | QMetaObject::invokeMethod() with the \c {Args &&...} arguments. |
4223 | |
4224 | \sa Q_RETURN_ARG() |
4225 | */ |
4226 | |
4227 | /*! |
4228 | \macro QMetaMethodReturnArgument Q_RETURN_ARG(Type, Type &value) |
4229 | \relates QMetaObject |
4230 | |
4231 | This macro takes a \a Type and a non-const reference to a \a |
4232 | value of that type and returns a QMetaMethodReturnArgument, which can be |
4233 | passed to the template QMetaObject::invokeMethod() with the \c {Args &&...} |
4234 | arguments. |
4235 | |
4236 | \sa Q_ARG() |
4237 | */ |
4238 | |
4239 | /*! |
4240 | \class QGenericArgument |
4241 | \inmodule QtCore |
4242 | |
4243 | \brief The QGenericArgument class is an internal helper class for |
4244 | marshalling arguments. |
4245 | |
4246 | This class should never be used directly. Please use the \l Q_ARG() |
4247 | macro instead. |
4248 | |
4249 | \sa Q_ARG(), QMetaObject::invokeMethod(), QGenericReturnArgument |
4250 | */ |
4251 | |
4252 | /*! |
4253 | \fn QGenericArgument::QGenericArgument(const char *name, const void *data) |
4254 | |
4255 | Constructs a QGenericArgument object with the given \a name and \a data. |
4256 | */ |
4257 | |
4258 | /*! |
4259 | \fn QGenericArgument::data () const |
4260 | |
4261 | Returns the data set in the constructor. |
4262 | */ |
4263 | |
4264 | /*! |
4265 | \fn QGenericArgument::name () const |
4266 | |
4267 | Returns the name set in the constructor. |
4268 | */ |
4269 | |
4270 | /*! |
4271 | \class QGenericReturnArgument |
4272 | \inmodule QtCore |
4273 | |
4274 | \brief The QGenericReturnArgument class is an internal helper class for |
4275 | marshalling arguments. |
4276 | |
4277 | This class should never be used directly. Please use the |
4278 | Q_RETURN_ARG() macro instead. |
4279 | |
4280 | \sa Q_RETURN_ARG(), QMetaObject::invokeMethod(), QGenericArgument |
4281 | */ |
4282 | |
4283 | /*! |
4284 | \fn QGenericReturnArgument::QGenericReturnArgument(const char *name, void *data) |
4285 | |
4286 | Constructs a QGenericReturnArgument object with the given \a name |
4287 | and \a data. |
4288 | */ |
4289 | |
4290 | /*! |
4291 | \internal |
4292 | If the local_method_index is a cloned method, return the index of the original. |
4293 | |
4294 | Example: if the index of "destroyed()" is passed, the index of "destroyed(QObject*)" is returned |
4295 | */ |
4296 | int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index) |
4297 | { |
4298 | Q_ASSERT(local_method_index < get(mobj)->methodCount); |
4299 | while (QMetaMethod::fromRelativeMethodIndex(mobj, index: local_method_index).data.flags() & MethodCloned) { |
4300 | Q_ASSERT(local_method_index > 0); |
4301 | --local_method_index; |
4302 | } |
4303 | return local_method_index; |
4304 | } |
4305 | |
4306 | /*! |
4307 | \internal |
4308 | |
4309 | Returns the parameter type names extracted from the given \a signature. |
4310 | */ |
4311 | QList<QByteArray> QMetaObjectPrivate::parameterTypeNamesFromSignature(const char *signature) |
4312 | { |
4313 | QList<QByteArray> list; |
4314 | while (*signature && *signature != '(') |
4315 | ++signature; |
4316 | while (*signature && *signature != ')' && *++signature != ')') { |
4317 | const char *begin = signature; |
4318 | int level = 0; |
4319 | while (*signature && (level > 0 || *signature != ',') && *signature != ')') { |
4320 | if (*signature == '<') |
4321 | ++level; |
4322 | else if (*signature == '>') |
4323 | --level; |
4324 | ++signature; |
4325 | } |
4326 | list += QByteArray(begin, signature - begin); |
4327 | } |
4328 | return list; |
4329 | } |
4330 | |
4331 | QT_END_NAMESPACE |
4332 |
Definitions
- priv
- rawStringData
- stringDataView
- stringData
- typeNameFromTypeInfo
- typeFromTypeInfo
- parse_scope
- QMetaMethodPrivate
- get
- newInstance
- newInstanceImpl
- static_metacall
- metacall
- objectClassName
- className
- inherits
- cast
- tr
- metaType
- methodOffset
- enumeratorOffset
- propertyOffset
- classInfoOffset
- constructorCount
- methodCount
- enumeratorCount
- propertyCount
- classInfoCount
- methodMatch
- firstMethod
- indexOfMethodRelative
- indexOfConstructor
- indexOfMethod
- argumentTypesFromString
- decodeMethodSignature
- indexOfSignal
- indexOfSignalRelative
- indexOfSlot
- indexOfSlotRelative
- indexOfSignal
- indexOfSlot
- indexOfMethod
- indexOfConstructor
- absoluteSignalCount
- signalIndex
- signal
- checkConnectArgs
- checkConnectArgs
- QMetaObject_findMetaObject
- indexOfEnumerator
- indexOfEnumerator
- indexOfEnumerator
- indexOfProperty
- indexOfClassInfo
- constructor
- method
- enumerator
- property
- userProperty
- classInfo
- checkConnectArgs
- checkConnectArgs
- qRemoveWhitespace
- qNormalizeType
- normalizedType
- normalizedSignature
- printMethodNotFoundWarning
- invokeMethod
- invokeMethodImpl
- invokeMethodImpl
- fromRelativeMethodIndex
- fromRelativeConstructorIndex
- signature
- name
- typesDataIndex
- rawReturnTypeName
- returnType
- parameterCount
- checkMethodMetaTypeConsistency
- parametersDataIndex
- parameterTypeInfo
- returnMetaTypeInterface
- parameterMetaTypeInterfaces
- parameterType
- getParameterTypes
- parameterTypeName
- parameterTypes
- parameterNames
- tag
- ownMethodIndex
- ownConstructorMethodIndex
- methodSignature
- name
- returnType
- returnMetaType
- parameterCount
- parameterType
- parameterMetaType
- getParameterTypes
- parameterTypes
- parameterTypeName
- parameterNames
- typeName
- tag
- attributes
- methodIndex
- relativeMethodIndex
- revision
- isConst
- access
- methodType
- fromSignalImpl
- invoke
- invokeImpl
- invokeImpl
- invokeOnGadget
- name
- enumName
- metaType
- keyCount
- key
- value
- isFlag
- isScoped
- scope
- isScopeMatch
- keyToValue
- valueToKey
- parseEnumFlags
- keysToValue
- join_reversed
- valueToKeys
- QMetaEnum
- index
- name
- typeName
- metaType
- index
- propertyIndex
- relativePropertyIndex
- isFlagType
- isEnumType
- hasStdCppSet
- isAlias
- registerPropertyType
- QMetaProperty
- getMetaPropertyData
- enumerator
- read
- write
- write
- reset
- bindable
- readOnGadget
- writeOnGadget
- writeOnGadget
- resetOnGadget
- isResettable
- isReadable
- hasNotifySignal
- notifySignal
- notifySignalIndex
- revision
- isWritable
- isDesignable
- isScriptable
- isStored
- isUser
- isConstant
- isFinal
- isRequired
- isBindable
- name
- value
- originalClone
Learn to use CMake with our Intro Training
Find out more