Example #1
0
    MethodParameters(int Index, const QMetaMethod &Method, int AllowedRequestTypes, const QString &ReturnType)
      : m_valid(false),
        m_index(Index),
        m_allowedRequestTypes(AllowedRequestTypes),
        m_returnType(ReturnType)
    {
        // statically initialise the list of unsupported types (either non-serialisable (QHash)
        // or nonsensical (pointer types)
        static QList<int> unsupportedtypes;
        static QList<int> unsupportedparameters;
        static bool initialised = false;

        if (!initialised)
        {
            // this list is probably incomplete
            initialised = true;
            unsupportedtypes << QMetaType::UnknownType;
            unsupportedtypes << QMetaType::VoidStar << QMetaType::QObjectStar << QMetaType::QVariantHash;
            unsupportedtypes << QMetaType::QRect << QMetaType::QRectF << QMetaType::QSize << QMetaType::QSizeF << QMetaType::QLine << QMetaType::QLineF << QMetaType::QPoint << QMetaType::QPointF;

            unsupportedparameters << unsupportedtypes;
            unsupportedparameters << QMetaType::QVariantMap << QMetaType::QStringList << QMetaType::QVariantList;
        }

        // the return type/value is first
        int returntype = QMetaType::type(Method.typeName());

        // discard slots with an unsupported return type
        if (unsupportedtypes.contains(returntype))
        {
            LOG(VB_GENERAL, LOG_ERR, QString("Method '%1' has unsupported return type '%2'").arg(Method.name().data()).arg(Method.typeName()));
            return;
        }

        // discard overly complicated slots not supported by QMetaMethod
        if (Method.parameterCount() > 10)
        {
            LOG(VB_GENERAL, LOG_ERR, QString("Method '%1' takes more than 10 parameters - ignoring").arg(Method.name().data()));
            return;
        }

        m_types.append(returntype > 0 ? returntype : 0);
        m_names.append(Method.name());

        QList<QByteArray> names = Method.parameterNames();
        QList<QByteArray> types = Method.parameterTypes();

        // add type/value for each method parameter
        for (int i = 0; i < names.size(); ++i)
        {
            int type = QMetaType::type(types[i]);

            // discard slots that use unsupported parameter types
            if (unsupportedparameters.contains(type))
            {
                LOG(VB_GENERAL, LOG_ERR, QString("Method '%1' has unsupported parameter type '%2'")
                    .arg(Method.name().data()).arg(types[i].data()));
                return;
            }

            m_names.append(names[i]);
            m_types.append(type);
        }

        m_valid = true;
    }
Example #2
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 = mp.userType();
            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 = QMetaType::typeName(typeId);
                retval += QString::fromLatin1(">\n      <annotation name=\"org.qtproject.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);

        bool isSignal;
        if (mm.methodType() == QMetaMethod::Signal)
            // adding a signal
            isSignal = true;
        else if (mm.access() == QMetaMethod::Public && (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method))
            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)) &&
                          !(flags & (QDBusConnection::ExportScriptableInvokables | QDBusConnection::ExportNonScriptableInvokables))))
            continue;           // we're not exporting any slots or invokables

        QString xml = QString::fromLatin1("    <%1 name=\"%2\">\n")
                      .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
                      .arg(QString::fromLatin1(mm.name()));

        // check the return type first
        int typeId = mm.returnType();
        if (typeId != QMetaType::UnknownType && typeId != QMetaType::Void) {
            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=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n")
                        .arg(typeNameToXml(QMetaType::typeName(typeId)));
            } else {
                qWarning() << "Unsupported return type" << typeId << QMetaType::typeName(typeId) << "in method" << mm.name();
                continue;
            }
        }
        else if (typeId == QMetaType::UnknownType) {
            qWarning() << "Invalid return type in method" << mm.name();
            continue;           // wasn't a valid type
        }

        QList<QByteArray> names = mm.parameterNames();
        QVector<int> types;
        QString errorMsg;
        int inputCount = qDBusParametersForMethod(mm, types, errorMsg);
        if (inputCount == -1) {
            qWarning() << "Skipped method" << mm.name() << ":" << qPrintable(errorMsg);
            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 = QMetaType::typeName(types.at(j));
                xml += QString::fromLatin1("      <annotation name=\"org.qtproject.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
                       .arg(isOutput ? QLatin1String("Out") : QLatin1String("In"))
                       .arg(isOutput && !isSignal ? j - inputCount : j - 1)
                       .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_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);
}
Example #4
0
QVariantMap JsonHandler::introspect(QMetaMethod::MethodType type)
{
    QVariantMap data;
    for (int i = 0; i < metaObject()->methodCount(); ++i) {
        QMetaMethod method = metaObject()->method(i);

        if (method.methodType() != type) {
            continue;
        }

        switch (method.methodType()) {
        case QMetaMethod::Method: {
            if (!m_descriptions.contains(method.name()) || !m_params.contains(method.name()) || !m_returns.contains(method.name())) {
                continue;
            }
            qCDebug(dcJsonRpc) << "got method" << method.name();
            QVariantMap methodData;
            methodData.insert("description", m_descriptions.value(method.name()));
            methodData.insert("params", m_params.value(method.name()));
            methodData.insert("returns", m_returns.value(method.name()));
            data.insert(name() + "." + method.name(), methodData);
            break;
        }
        case QMetaMethod::Signal: {
            if (!m_descriptions.contains(method.name()) || !m_params.contains(method.name())) {
                continue;
            }
            if (QString(method.name()).contains(QRegExp("^[A-Z]"))) {
                qCDebug(dcJsonRpc) << "got signal" << method.name();
                QVariantMap methodData;
                methodData.insert("description", m_descriptions.value(method.name()));
                methodData.insert("params", m_params.value(method.name()));
                data.insert(name() + "." + method.name(), methodData);
            }
            break;
        default:
            ;;// Nothing to do for slots
        }
        }
    }
    return data;
}
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;
}
Example #6
0
int GoValueMetaObject::metaCall(QMetaObject::Call c, int idx, void **a)
{
    switch (c) {
    case QMetaObject::ReadProperty:
    case QMetaObject::WriteProperty:
        {
            // TODO Cache propertyOffset, methodOffset, and qmlEngine results?
            if (idx < propertyOffset()) {
                return value->qt_metacall(c, idx, a);
            }
            GoMemberInfo *memberInfo = valuePriv->typeInfo->fields;
            for (int i = 0; i < valuePriv->typeInfo->fieldsLen; i++) {
                if (memberInfo->metaIndex == idx) {
                    if (c == QMetaObject::ReadProperty) {
                        DataValue result;
                        hookGoValueReadField(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, &result);
                        QVariant *out = reinterpret_cast<QVariant *>(a[0]);
                        unpackDataValue(&result, out);
                    } else {
                        DataValue assign;
                        QVariant *in = reinterpret_cast<QVariant *>(a[0]);
                        packDataValue(in, &assign);
                        hookGoValueWriteField(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, &assign);
                    }
                    return -1;
                }
                memberInfo++;
            }
            QMetaProperty prop = property(idx);
            qWarning() << "Property" << prop.name() << "not found!?";
            break;
        }
    case QMetaObject::InvokeMetaMethod:
        {
            if (idx < methodOffset()) {
                return value->qt_metacall(c, idx, a);
            }
            GoMemberInfo *memberInfo = valuePriv->typeInfo->methods;
            for (int i = 0; i < valuePriv->typeInfo->methodsLen; i++) {
                if (memberInfo->metaIndex == idx) {
                    // args[0] is the result if any.
                    DataValue args[1 + MaxParams];
                    for (int i = 1; i < memberInfo->numIn+1; i++) {
                        packDataValue(reinterpret_cast<QVariant *>(a[i]), &args[i]);
                    }
                    hookGoValueCallMethod(qmlEngine(value), valuePriv->addr, memberInfo->reflectIndex, args);
                    if (memberInfo->numOut > 0) {
                        unpackDataValue(&args[0], reinterpret_cast<QVariant *>(a[0]));
                    }
                    return -1;
                }
                memberInfo++;
            }
            QMetaMethod m = method(idx);
            qWarning() << "Method" << m.name() << "not found!?";
            break;
        }
    default:
        break; // Unhandled.
    }
    return -1;
}
Example #7
0
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, 
                  const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
{
    // Set classname
    builder.setClassName(ignoreEnd->className());

    // Clone Q_CLASSINFO
    for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
        QMetaClassInfo info = mo->classInfo(ii);

        int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
        if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
            // Skip 
        } else {
            builder.addClassInfo(info.name(), info.value());
        }
    }

    // Clone Q_PROPERTY
    for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
        QMetaProperty property = mo->property(ii);

        int otherIndex = ignoreEnd->indexOfProperty(property.name());
        if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
            builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
            // Skip 
        } else {
            builder.addProperty(property);
        }
    }

    // Clone Q_METHODS
    for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
        QMetaMethod method = mo->method(ii);

        // More complex - need to search name
        QByteArray name = method.name();


        bool found = false;

        for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); 
             !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
             ++ii) {

            QMetaMethod other = ignoreEnd->method(ii);

            found = name == other.name();
        }

        QMetaMethodBuilder m = builder.addMethod(method);
        if (found) // SKIP
            m.setAccess(QMetaMethod::Private);
    }

    // Clone Q_ENUMS
    for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
        QMetaEnum enumerator = mo->enumerator(ii);

        int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
        if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
            // Skip 
        } else {
            builder.addEnumerator(enumerator);
        }
    }
}
QString AsemanQtTools::exportItem(const QString &module, int major, int minor, const QString &component, bool store)
{
    QString result;
    aseman_qt_tools_indexCache << component;

    QMetaObject meta = T::staticMetaObject;
    QString inherits = fixType(meta.superClass()? meta.superClass()->className() : "");
    bool isModel = component.toLower().contains("model");

    result += QString("# %1\n\n").arg(component);

    QString headers;
    headers += QString(" * [Component details](#component-details)\n");

    QString details = QString("\n### Component details:\n\n");
    details += QString("|Detail|Value|\n"
                       "|------|-----|\n");
    details += QString("|%1|%2 %3.%4|\n").arg("Import").arg(module).arg(major).arg(minor);
    details += QString("|%1|<font color='#074885'>%2</font>|\n").arg("Component").arg(component);
    details += QString("|%1|<font color='#074885'>%2</font>|\n").arg("C++ class").arg(meta.className());
    details += QString("|%1|<font color='#074885'>%2</font>|\n").arg("Inherits").arg(inherits);
    details += QString("|%1|<font color='#074885'>%2</font>|\n").arg("Model").arg(isModel?"Yes":"No");

    QString resultProperties;
    QStringList propertiesSignals;
    for(int i=0; i<meta.propertyCount(); i++)
    {
        QMetaProperty property = meta.property(i);
        const QString &propertyName = property.name();
        const QString &propertyType = fixType(property.typeName());
        propertiesSignals << property.notifySignal().name();

        QString text = QString("* <font color='#074885'><b>%1</b></font>: %2").arg(propertyName).arg(propertyType);
        if(!property.isWritable())
            text += " (readOnly)";

        text += "\n";
        if(meta.propertyOffset()<=i)
            resultProperties += text;
    }

    QString enumResults;
    for(int i=meta.enumeratorOffset(); i<meta.enumeratorCount(); i++)
    {
        QMetaEnum enumerator = meta.enumerator(i);
        const QString &enumName = enumerator.name();

        enumResults += QString("\n##### %1\n\n").arg(enumName);
        enumResults += QString("|Key|Value|\n"
                               "|---|-----|\n");

        for(int j=0; j<enumerator.keyCount(); j++)
            enumResults += QString("|%1|%2|\n").arg(enumerator.key(j)).arg(enumerator.value(j));
    }

    QString resultSlots;
    QString resultSignals;
    for(int i=meta.methodOffset(); i<meta.methodCount(); i++)
    {
        QMetaMethod method = meta.method(i);
        if(method.access() != QMetaMethod::Public)
            continue;

        const QString &methodName = method.name();
        if(propertiesSignals.contains(methodName))
            continue;

        const QString &methodType = fixType(method.typeName());

        QString args;
        const QList<QByteArray> &paramNames = method.parameterNames();
        const QList<QByteArray> &paramTypes = method.parameterTypes();
        for(int j=0; j<paramNames.count(); j++)
        {
            if(j != 0)
                args += ", ";

            args += fixType(paramTypes[j]) + " " + paramNames[j];
        }

        QString text = QString(" * %1 <font color='#074885'><b>%2</b></font>(%3)\n").arg(methodType).arg(methodName).arg(args);
        switch(static_cast<int>(method.methodType()))
        {
        case QMetaMethod::Slot:
            resultSlots += text;
            break;
        case QMetaMethod::Signal:
            resultSignals += text;
            break;
        }
    }

    if(!resultProperties.isEmpty())
    {
        headers += QString(" * [Normal Properties](#normal-properties)\n");
        resultProperties = QString("\n### Normal Properties\n\n") + resultProperties;
    }
    if(!enumResults.isEmpty())
    {
        headers += QString(" * [Enumerator](#enumerator)\n");
        enumResults = QString("\n### Enumerator\n\n") + enumResults;
    }
    if(!resultSlots.isEmpty())
    {
        headers += QString(" * [Methods](#methods)\n");
        resultSlots = QString("\n### Methods\n\n") + resultSlots;
    }
    if(!resultSignals.isEmpty())
    {
        headers += QString(" * [Signals](#signals)\n");
        resultSignals = QString("\n### Signals\n\n") + resultSignals;
    }
    if(isModel)
        headers += QString(" * [Roles](#roles)\n");

    result += headers + "\n";
    result += details + "\n";
    result += resultProperties + "\n";
    result += resultSlots + "\n";
    result += resultSignals + "\n";
    result += enumResults + "\n";

    if(!store)
        return result;

    QString path = aseman_qt_tools_destination + "/" + component.toLower() + ".md";
    QFile file(path);
    if(!file.open(QFile::WriteOnly))
        return result;

    file.write(result.toUtf8());
    file.close();
    return result;
}