static QVariantMap readAllProperties(QObject *object, int flags) { QVariantMap result; const QMetaObject *mo = object->metaObject(); // QObject has properties, so don't start from 0 for (int i = QObject::staticMetaObject.propertyCount(); i < mo->propertyCount(); ++i) { QMetaProperty mp = mo->property(i); // is it readable? if (!mp.isReadable()) continue; // is it a registered property? int typeId = qDBusNameToTypeId(mp.typeName()); if (!typeId) continue; const char *signature = QDBusMetaType::typeToSignature(typeId); if (!signature) continue; // is this property visible from the outside? if ((mp.isScriptable() && flags & QDBusConnection::ExportScriptableProperties) || (!mp.isScriptable() && flags & QDBusConnection::ExportNonScriptableProperties)) { // yes, it's visible QVariant value = mp.read(object); if (value.isValid()) result.insert(QString::fromLatin1(mp.name()), value); } } return result; }
static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value, int propFlags = QDBusConnection::ExportAllProperties) { const QMetaObject *mo = obj->metaObject(); int pidx = mo->indexOfProperty(property_name); if (pidx == -1) { // this object has no property by that name return PropertyNotFound; } QMetaProperty mp = mo->property(pidx); // check if this property is exported bool isScriptable = mp.isScriptable(); if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable) return PropertyNotFound; if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable) return PropertyNotFound; // we found our property // do we have the right type? int id = mp.type(); if (id == QVariant::UserType) { // dynamic type id = qDBusNameToTypeId(mp.typeName()); if (id == -1) { // type not registered? qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'", mp.typeName(), mo->className(), property_name.constData()); return PropertyWriteFailed; } } if (id != 0xff && value.userType() == QDBusMetaTypeId::argument) { // we have to demarshall before writing void *null = 0; QVariant other(id, null); if (!QDBusMetaType::demarshall(qvariant_cast<QDBusArgument>(value), id, other.data())) { qWarning("QDBusConnection: type `%s' (%d) is not registered with QtDBus. " "Use qDBusRegisterMetaType to register it", mp.typeName(), id); return PropertyWriteFailed; } value = other; } // the property type here should match return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed; }
// calculates the metatypes for the method // the slot must have the parameters in the following form: // - zero or more value or const-ref parameters of any kind // - zero or one const ref of QDBusMessage // - zero or more non-const ref parameters // No parameter may be a template. // this function returns -1 if the parameters don't match the above form // this function returns the number of *input* parameters, including the QDBusMessage one if any // this function does not check the return type, so metaTypes[0] is always 0 and always present // metaTypes.count() >= retval + 1 in all cases // // sig must be the normalised signature for the method int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes) { QDBusMetaTypeId::init(); QList<QByteArray> parameterTypes = mm.parameterTypes(); metaTypes.clear(); metaTypes.append(0); // return type int inputCount = 0; bool seenMessage = false; QList<QByteArray>::ConstIterator it = parameterTypes.constBegin(); QList<QByteArray>::ConstIterator end = parameterTypes.constEnd(); for ( ; it != end; ++it) { const QByteArray &type = *it; if (type.endsWith('*')) { //qWarning("Could not parse the method '%s'", mm.signature()); // pointer? return -1; } if (type.endsWith('&')) { QByteArray basictype = type; basictype.truncate(type.length() - 1); int id = qDBusNameToTypeId(basictype); if (id == 0) { //qWarning("Could not parse the method '%s'", mm.signature()); // invalid type in method parameter list return -1; } else if (QDBusMetaType::typeToSignature(id) == 0) return -1; metaTypes.append( id ); seenMessage = true; // it cannot appear anymore anyways continue; } if (seenMessage) { // && !type.endsWith('&') //qWarning("Could not parse the method '%s'", mm.signature()); // non-output parameters after message or after output params return -1; // not allowed } int id = qDBusNameToTypeId(type); if (id == 0) { //qWarning("Could not parse the method '%s'", mm.signature()); // invalid type in method parameter list return -1; } if (id == QDBusMetaTypeId::message) seenMessage = true; else if (QDBusMetaType::typeToSignature(id) == 0) return -1; metaTypes.append(id); ++inputCount; } return inputCount; }
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; }