QVariant ObjectMethodModel::metaData(const QModelIndex &index, const QMetaMethod &method, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::prettyMethodSignature(method); } if (index.column() == 1) { switch (method.methodType()) { case QMetaMethod::Method: return tr("Method"); case QMetaMethod::Constructor: return tr("Constructor"); case QMetaMethod::Slot: return tr("Slot"); case QMetaMethod::Signal: return tr("Signal"); default: return tr("Unknown"); } } if (index.column() == 2) { switch (method.access()) { case QMetaMethod::Public: return tr("Public"); case QMetaMethod::Protected: return tr("Protected"); case QMetaMethod::Private: return tr("Private"); default: return tr("Unknown"); } } } else if (role == Qt::ToolTipRole) { QString tt = Util::prettyMethodSignature(method); tt += tr("\nTag: %1\n").arg(qstrlen(method.tag()) > 0 ? method.tag() : tr("<none>")); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) tt += tr("Revision: %1").arg(method.revision()); #endif return tt; } else if (role == ObjectMethodModelRole::MetaMethod) { return QVariant::fromValue(method); } else if (role == ObjectMethodModelRole::MetaMethodType) { return QVariant::fromValue(method.methodType()); } else if (role == ObjectMethodModelRole::MethodSignature) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return method.signature(); #else return method.methodSignature(); #endif } return QVariant(); }
void listInterface(const QString &service, const QString &path, const QString &interface) { QDBusInterfacePtr iface(*connection, service, path, interface); if (!iface->isValid()) { QDBusError err(iface->lastError()); fprintf(stderr, "Interface '%s' not available in object %s at %s:\n%s (%s)\n", qPrintable(interface), qPrintable(path), qPrintable(service), qPrintable(err.name()), qPrintable(err.message())); exit(1); } const QMetaObject *mo = iface->metaObject(); // properties for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) { QMetaProperty mp = mo->property(i); printf("property "); if (mp.isReadable() && mp.isWritable()) printf("readwrite"); else if (mp.isReadable()) printf("read"); else printf("write"); printf(" %s %s.%s\n", mp.typeName(), qPrintable(interface), mp.name()); } // methods (signals and slots) for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); QByteArray signature = mm.signature(); signature.truncate(signature.indexOf('(')); printf("%s %s%s%s %s.%s(", mm.methodType() == QMetaMethod::Signal ? "signal" : "method", mm.tag(), *mm.tag() ? " " : "", *mm.typeName() ? mm.typeName() : "void", qPrintable(interface), signature.constData()); QList<QByteArray> types = mm.parameterTypes(); QList<QByteArray> names = mm.parameterNames(); bool first = true; for (int i = 0; i < types.count(); ++i) { printf("%s%s", first ? "" : ", ", types.at(i).constData()); if (!names.at(i).isEmpty()) printf(" %s", names.at(i).constData()); first = false; } printf(")\n"); } }
QVariant ObjectMethodModel::metaData(const QModelIndex &index, const QMetaMethod &method, int role) const { if (role == Qt::DisplayRole && index.column() == 0) { return Util::prettyMethodSignature(method); } else if (role == ObjectMethodModelRole::MetaMethod) { return QVariant::fromValue(method); } else if (role == ObjectMethodModelRole::MetaMethodType && index.column() == 1) { return QVariant::fromValue(method.methodType()); } else if (role == ObjectMethodModelRole::MethodAccess && index.column() == 2) { return QVariant::fromValue(method.access()); } else if (role == ObjectMethodModelRole::MethodSignature && index.column() == 0) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return method.signature(); #else return method.methodSignature(); #endif } else if (role == ObjectMethodModelRole::MethodTag && index.column() == 0 && qstrlen(method.tag())) { return method.tag(); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) } else if (role == ObjectMethodModelRole::MethodRevision && index.column() == 0) { return method.revision(); #endif } else if (role == ObjectMethodModelRole::MethodIssues && index.column() == 0) { const QMetaObject *mo = m_metaObject; while (mo->methodOffset() > index.row()) mo = mo->superClass(); const auto r = QMetaObjectValidator::checkMethod(mo, method); return r == QMetaObjectValidatorResult::NoIssue ? QVariant() : QVariant::fromValue(r); } return QVariant(); }
bool action_method::validate_action_method(const QMetaMethod &meta_method) { auto meta_object = meta_method.enclosingMetaObject(); if (!meta_object) throw exception::invalid_action{std::string{"action does not have enclosing meta object: "} + "?::" + meta_method.methodSignature().data()}; if (meta_method.methodType() == QMetaMethod::Signal) throw exception::invalid_action{std::string{"action is signal: "} + meta_object->className() + "::" + meta_method.methodSignature().data()}; if (meta_method.methodType() == QMetaMethod::Constructor) throw exception::invalid_action{std::string{"action is constructor: "} + meta_object->className() + "::" + meta_method.methodSignature().data()}; if (!is_action_init_tag(meta_method.tag()) && !is_action_done_tag(meta_method.tag())) throw exception::invalid_action{std::string{"action does not have valid tag: "} + meta_object->className() + "::" + meta_method.methodSignature().data()}; if (meta_method.parameterCount() != 0) throw exception::invalid_action{std::string{"invalid parameter count: "} + meta_object->className() + "::" + meta_method.methodSignature().data()}; return true; }
QVariant ObjectMethodModel::metaData(const QModelIndex &index, const QMetaMethod &method, int role) const { if (role == Qt::DisplayRole) { if (index.column() == 0) { return Util::prettyMethodSignature(method); } if (index.column() == 1) { switch (method.methodType()) { case QMetaMethod::Method: return tr("Method"); case QMetaMethod::Constructor: return tr("Constructor"); case QMetaMethod::Slot: return tr("Slot"); case QMetaMethod::Signal: return tr("Signal"); default: return tr("Unknown"); } } if (index.column() == 2) { switch (method.access()) { case QMetaMethod::Public: return tr("Public"); case QMetaMethod::Protected: return tr("Protected"); case QMetaMethod::Private: return tr("Private"); default: return tr("Unknown"); } } if (index.column() == 3) { return method.tag(); } #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) if (index.column() == 4) { return QString::number(method.revision()); } #endif } else if (role == ObjectMethodModelRole::MetaMethod) { return QVariant::fromValue(method); } else if (role == ObjectMethodModelRole::MetaMethodType) { return QVariant::fromValue(method.methodType()); } else if (role == ObjectMethodModelRole::MethodSignature) { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return method.signature(); #else return method.methodSignature(); #endif } return QVariant(); }
/*! Places a call to the remote method specified by \a method on this interface, using \a args as arguments. This function returns the message that was received as a reply, which can be a normal QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call failed). The \a mode parameter specifies how this call should be placed. If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this call produced. Normally, you should place calls using call(). \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy: other method calls and signals may be delivered before this function returns, as well as other Qt queued signals and events. \threadsafe */ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode, const QString& method, const QList<QVariant>& args) { Q_D(QDBusAbstractInterface); if (!d->isValid || !d->canMakeCalls()) return QDBusMessage::createError(d->lastError); QString m = method; // split out the signature from the method int pos = method.indexOf(QLatin1Char('.')); if (pos != -1) m.truncate(pos); if (mode == QDBus::AutoDetect) { // determine if this a sync or async call mode = QDBus::Block; const QMetaObject *mo = metaObject(); QByteArray match = m.toLatin1(); for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); if (mm.name() == match) { // found a method with the same name as what we're looking for // hopefully, nobody is overloading asynchronous and synchronous methods with // the same name QList<QByteArray> tags = QByteArray(mm.tag()).split(' '); if (tags.contains("Q_NOREPLY")) mode = QDBus::NoBlock; break; } } } // qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path(); QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m); QDBusMessagePrivate::setParametersValidated(msg, true); msg.setArguments(args); QDBusMessage reply = d->connection.call(msg, mode, d->timeout); if (thread() == QThread::currentThread()) d->lastError = QDBusError(reply); // will clear if reply isn't an error // ensure that there is at least one element if (reply.arguments().isEmpty()) reply << QVariant(); return reply; }
void tst_QQmlMetaObject::method() { QFETCH(QString, testFile); QFETCH(QString, signature); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(int, returnType); QFETCH(QString, returnTypeName); QFETCH(QList<int>, parameterTypes); QFETCH(QList<QByteArray>, parameterTypeNames); QFETCH(QList<QByteArray>, parameterNames); QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypeNames.size(), parameterNames.size()); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != 0); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != 0); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); QMetaMethod method = mo->method(mo->methodOffset()); QCOMPARE(method.methodType(), methodType); QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); QCOMPARE(method.access(), QMetaMethod::Public); QString computedName = signature.left(signature.indexOf('(')); QCOMPARE(QString::fromUtf8(method.name()), computedName); QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(method.tag(), ""); QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName); QCOMPARE(method.returnType(), returnType); delete object; }
void tst_QMetaMethod::method() { QFETCH(QByteArray, signature); QFETCH(int, returnType); QFETCH(QByteArray, returnTypeName); QFETCH(QList<int>, parameterTypes); QFETCH(QList<QByteArray>, parameterTypeNames); QFETCH(QList<QByteArray>, parameterNames); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(QMetaMethod::Access, access); QVERIFY(parameterTypes.size() == parameterTypeNames.size()); QVERIFY(parameterTypes.size() == parameterNames.size()); const QMetaObject *mo = &MethodTestObject::staticMetaObject; int index = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(signature) : mo->indexOfMethod(signature); QVERIFY(index != -1); QMetaMethod method = (methodType == QMetaMethod::Constructor) ? mo->constructor(index) : mo->method(index); QVERIFY(method.isValid()); QCOMPARE(method.methodType(), methodType); QCOMPARE(method.access(), access); QVERIFY(!method.methodSignature().isEmpty()); if (method.methodSignature() != signature) { // QMetaMethod should always produce a semantically equivalent signature int signatureIndex = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(method.methodSignature()) : mo->indexOfMethod(method.methodSignature()); QCOMPARE(signatureIndex, index); } QByteArray computedName = signature.left(signature.indexOf('(')); QCOMPARE(method.name(), computedName); QCOMPARE(method.tag(), ""); QCOMPARE(method.returnType(), returnType); QVERIFY(method.typeName() != 0); if (QByteArray(method.typeName()) != returnTypeName) { // QMetaMethod should always produce a semantically equivalent typename QCOMPARE(QMetaType::type(method.typeName()), QMetaType::type(returnTypeName)); } if (method.parameterTypes() != parameterTypeNames) { // QMetaMethod should always produce semantically equivalent typenames QList<QByteArray> actualTypeNames = method.parameterTypes(); QCOMPARE(actualTypeNames.size(), parameterTypeNames.size()); for (int i = 0; i < parameterTypeNames.size(); ++i) { QCOMPARE(QMetaType::type(actualTypeNames.at(i)), QMetaType::type(parameterTypeNames.at(i))); } } QCOMPARE(method.parameterNames(), parameterNames); QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); { QVector<int> actualParameterTypes(parameterTypes.size()); method.getParameterTypes(actualParameterTypes.data()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i)); } // Bogus indexes QCOMPARE(method.parameterType(-1), 0); QCOMPARE(method.parameterType(parameterTypes.size()), 0); }
static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset) { QString retval; // start with properties: if (flags & (QDBusConnection::ExportScriptableProperties | QDBusConnection::ExportNonScriptableProperties)) { for (int i = propOffset; i < mo->propertyCount(); ++i) { static const char *accessvalues[] = {0, "read", "write", "readwrite"}; QMetaProperty mp = mo->property(i); if (!((mp.isScriptable() && (flags & QDBusConnection::ExportScriptableProperties)) || (!mp.isScriptable() && (flags & QDBusConnection::ExportNonScriptableProperties)))) continue; int access = 0; if (mp.isReadable()) access |= 1; if (mp.isWritable()) access |= 2; int typeId = qDBusNameToTypeId(mp.typeName()); if (!typeId) continue; const char *signature = QDBusMetaType::typeToSignature(typeId); if (!signature) continue; retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"") .arg(QLatin1String(mp.name())) .arg(QLatin1String(signature)) .arg(QLatin1String(accessvalues[access])); if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { const char *typeName = QVariant::typeToName(QVariant::Type(typeId)); retval += QString::fromLatin1(">\n <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n") .arg(typeNameToXml(typeName)); } else { retval += QLatin1String("/>\n"); } } } // now add methods: for (int i = methodOffset; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); QByteArray signature = mm.signature(); int paren = signature.indexOf('('); bool isSignal; if (mm.methodType() == QMetaMethod::Signal) // adding a signal isSignal = true; else if (mm.methodType() == QMetaMethod::Slot && mm.access() == QMetaMethod::Public) isSignal = false; else continue; // neither signal nor public slot if (isSignal && !(flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals))) continue; // we're not exporting any signals if (!isSignal && !(flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots))) continue; // we're not exporting any slots QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n") .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")) .arg(QLatin1String(signature.left(paren))); // check the return type first int typeId = qDBusNameToTypeId(mm.typeName()); if (typeId) { const char *typeName = QDBusMetaType::typeToSignature(typeId); if (typeName) { xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n") .arg(typeNameToXml(typeName)); // do we need to describe this argument? if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid) xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n") .arg(typeNameToXml(mm.typeName())); } else continue; } else if (*mm.typeName()) continue; // wasn't a valid type QList<QByteArray> names = mm.parameterNames(); QList<int> types; int inputCount = qDBusParametersForMethod(mm, types); if (inputCount == -1) continue; // invalid form if (isSignal && inputCount + 1 != types.count()) continue; // signal with output arguments? if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message) continue; // signal with QDBusMessage argument? if (isSignal && mm.attributes() & QMetaMethod::Cloned) continue; // cloned signal? int j; bool isScriptable = mm.attributes() & QMetaMethod::Scriptable; for (j = 1; j < types.count(); ++j) { // input parameter for a slot or output for a signal if (types.at(j) == QDBusMetaTypeId::message) { isScriptable = true; continue; } QString name; if (!names.at(j - 1).isEmpty()) name = QString::fromLatin1("name=\"%1\" ").arg(QLatin1String(names.at(j - 1))); bool isOutput = isSignal || j > inputCount; const char *signature = QDBusMetaType::typeToSignature(types.at(j)); xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n") .arg(name) .arg(QLatin1String(signature)) .arg(isOutput ? QLatin1String("out") : QLatin1String("in")); // do we need to describe this argument? if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { const char *typeName = QVariant::typeToName( QVariant::Type(types.at(j)) ); xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n") .arg(isOutput ? QLatin1String("Out") : QLatin1String("In")) .arg(isOutput ? j - 1 : j - inputCount) .arg(typeNameToXml(typeName)); } } int wantedMask; if (isScriptable) wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals : QDBusConnection::ExportScriptableSlots; else wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals : QDBusConnection::ExportNonScriptableSlots; if ((flags & wantedMask) != wantedMask) continue; if (qDBusCheckAsyncTag(mm.tag())) // add the no-reply annotation xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\"" " value=\"true\"/>\n"); retval += xml; retval += QString::fromLatin1(" </%1>\n") .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")); } return retval; }
void tst_QQmlMetaObject::property() { QFETCH(QString, testFile); QFETCH(QByteArray, cppTypeName); QFETCH(int, cppType); QFETCH(bool, isDefault); QFETCH(QVariant, expectedValue); QFETCH(bool, isWritable); QFETCH(QVariant, newValue); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != 0); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != 0); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount()); QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1); QMetaProperty prop = mo->property(mo->propertyOffset()); QCOMPARE(prop.name(), "test"); QCOMPARE(QByteArray(prop.typeName()), cppTypeName); if (prop.userType() < QMetaType::User) QCOMPARE(prop.type(), QVariant::Type(cppType)); else QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), cppType); QVERIFY(!prop.isConstant()); QVERIFY(!prop.isDesignable()); QVERIFY(!prop.isEnumType()); QVERIFY(!prop.isFinal()); QVERIFY(!prop.isFlagType()); QVERIFY(prop.isReadable()); QVERIFY(!prop.isResettable()); QVERIFY(prop.isScriptable()); QVERIFY(!prop.isStored()); QVERIFY(!prop.isUser()); QVERIFY(prop.isValid()); QCOMPARE(prop.isWritable(), isWritable); QCOMPARE(mo->classInfoOffset(), mo->superClass()->classInfoCount()); QCOMPARE(mo->classInfoCount(), mo->superClass()->classInfoCount() + (isDefault ? 1 : 0)); if (isDefault) { QMetaClassInfo info = mo->classInfo(mo->classInfoOffset()); QCOMPARE(info.name(), "DefaultProperty"); QCOMPARE(info.value(), "test"); } QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); // the signal QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Public); QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList<QByteArray>()); QCOMPARE(signal.parameterNames(), QList<QByteArray>()); QCOMPARE(signal.tag(), ""); QCOMPARE(signal.typeName(), "void"); QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); if (expectedValue.isValid()) QCOMPARE(prop.read(object), expectedValue); else QVERIFY(prop.read(object).isValid()); QCOMPARE(changedSpy.count(), 0); if (isWritable) { QVERIFY(prop.write(object, newValue)); QCOMPARE(changedSpy.count(), 1); QCOMPARE(prop.read(object), newValue); } else { QVERIFY(!prop.write(object, prop.read(object))); QCOMPARE(changedSpy.count(), 0); } delete object; }