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