Example #1
0
static KODE::Code createRangeCheckCode( const XSD::SimpleType *type, const QString &variableName, KODE::Class &parentClass )
{
    KODE::Code code;
    code += "bool rangeOk = true;";
    code.newLine();

    // TODO
    /*
      WhiteSpaceType facetWhiteSpace() const;
      int facetTotalDigits() const;
      int facetFractionDigits() const;
    */

    if ( type->facetType() & XSD::SimpleType::MININC )
        code += "rangeOk = rangeOk && (" + variableName + " >= " + QString::number( type->facetMinimumInclusive() ) + ");";
    if ( type->facetType() & XSD::SimpleType::MINEX )
        code += "rangeOk = rangeOk && (" + variableName + " > " + QString::number( type->facetMinimumExclusive() ) + ");";
    if ( type->facetType() & XSD::SimpleType::MAXINC )
        code += "rangeOk = rangeOk && (" + variableName + " <= " + QString::number( type->facetMaximumInclusive() ) + ");";
    if ( type->facetType() & XSD::SimpleType::MINEX )
        code += "rangeOk = rangeOk && (" + variableName + " < " + QString::number( type->facetMaximumExclusive() ) + ");";

    if ( type->facetType() & XSD::SimpleType::LENGTH )
        code += "rangeOk = rangeOk && (" + variableName + ".length() == " + QString::number( type->facetLength() ) + ");";
    if ( type->facetType() & XSD::SimpleType::MINLEN )
        code += "rangeOk = rangeOk && (" + variableName + ".length() >= " + QString::number( type->facetMinimumLength() ) + ");";
    if ( type->facetType() & XSD::SimpleType::MAXLEN )
        code += "rangeOk = rangeOk && (" + variableName + ".length() <= " + QString::number( type->facetMaximumLength() ) + ");";
    if ( type->facetType() & XSD::SimpleType::PATTERN ) {
        code += "QRegExp exp( \"" + type->facetPattern() + "\" );";
        code += "rangeOk = rangeOk && exp.exactMatch( " + variableName + " );";

        parentClass.addInclude( "QRegExp" );
    }

    return code;
}
void Converter::convertComplexType(const XSD::ComplexType *type)
{
    // An empty type is still useful, in document mode: it serializes the element name
    //if ( type->isEmpty() )
    //    return;

    // Skip the Array types we added in Parser::init...
    if (NSManager::soapEncNamespaces().contains(type->nameSpace())) {
        return;
    }

    const QString className(mTypeMap.localType(type->qualifiedName()));
    KODE::Class newClass;
    newClass.setNamespaceAndName(className);
    if (!Settings::self()->exportDeclaration().isEmpty()) {
        newClass.setExportDeclaration(Settings::self()->exportDeclaration());
    }

    newClass.setUseSharedData(true, QLatin1String("d_ptr") /*avoid clash with possible d() method */);

    const bool doDebug = (qgetenv("KDSOAP_TYPE_DEBUG").toInt());
    if (doDebug) {
        qDebug() << "Generating complex type" << className;
    }

    // subclass handling
    if (!type->baseTypeName().isEmpty()) {   // this class extends something
        /**
         * A class can't subclass basic type (e.g. int, unsigned char), so we
         * add setValue() and value() methods to access the base type.
         *
         * In fact, let's do the same with string
         */
        if (type->baseTypeName().localName() == QLatin1String("Array")) {
            // this is handled in the attribute section
        } else {
            const QName baseName = type->baseTypeName();
            const QString typeName = mTypeMap.localType(baseName);
            const QString inputTypeName = mTypeMap.localInputType(baseName, QName());

            // include header
            newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName));
            newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName));

            if (mTypeMap.isComplexType(baseName)) {
                newClass.addBaseClass(typeName);
            } else {
                const QString variableName = generateMemberVariable("value", typeName, inputTypeName, newClass, XSD::Attribute::Required, false, false);

                // convenience constructor
                KODE::Function conctor(upperlize(newClass.name()));
                conctor.addArgument(inputTypeName + QLatin1String(" value"));
                conctor.setBody(variableName + QLatin1String(" = value;"));

                // type operator
                KODE::Function op(QLatin1String("operator ") + typeName);
                op.setBody(QLatin1String("return ") + variableName + QLatin1Char(';'));
                op.setConst(true);

                newClass.addFunction(conctor);
                newClass.addFunction(op);
            }
        }
    }

    if (!type->documentation().isEmpty()) {
        newClass.setDocs(type->documentation().simplified());
    }

    QVector<QString> seenElements;

    // elements in the complex type
    const XSD::Element::List elements = type->elements();
    Q_FOREACH (const XSD::Element &elemIt, elements) {

        if (elemIt.type().isEmpty()) {
            qDebug() << "ERROR: Element from" << *type << "with no type:" << elemIt << "(skipping)";
            Q_ASSERT(false);
            continue;
        }

        // When having <choice>
        //                <sequence>A,B(opt)</sequence>
        //                B
        //                <sequence>C,B(opt)</sequence>
        //             </choice>
        // we don't want to emit setB() three times, that's not valid C++
        // (testcase in wsdl_document.wsdl TestRepeatedChildren)
        if (seenElements.contains(elemIt.name())) {
            continue;
        }
        seenElements.append(elemIt.name());

        QString typeName = mTypeMap.localType(elemIt.type());
        Q_ASSERT(!typeName.isEmpty());

        if (typeName != QLatin1String("void")) { // void means empty element, probably just here for later extensions (testcase: SetPasswordResult in salesforce)
            QString inputTypeName = mTypeMap.localInputType(elemIt.type(), QName());

            bool isList = false;
            if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) {
                QString itemType = mTypeMap.isPolymorphic(elemIt.type()) ? pointerStorageType(typeName) : typeName;
                typeName = listTypeFor(itemType, newClass);
                inputTypeName = QLatin1String("const ") + typeName + QLatin1String("&");
                isList = true;
            }
            if (type->isArray()) {
                QString arrayTypeName = mTypeMap.localType(type->arrayType());
                Q_ASSERT(!arrayTypeName.isEmpty());
                if (mTypeMap.isPolymorphic(type->arrayType())) {
                    arrayTypeName = pointerStorageType(arrayTypeName);
                }
                //qDebug() << "array of" << attribute.arrayType() << "->" << arrayTypeName;
                typeName = listTypeFor(arrayTypeName, newClass);
                if (!mTypeMap.isBasicType(type->arrayType())) {
                    newClass.addInclude(QString(), arrayTypeName); // add forward declaration
                }
                newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList"));
                inputTypeName = QLatin1String("const ") + typeName + QLatin1Char('&');
                isList = true;
            }

            XSD::Attribute::AttributeUse use = isElementOptional(elemIt) ? XSD::Attribute::Optional : XSD::Attribute::Required;
            const bool polymorphic = isElementPolymorphic(elemIt, mTypeMap, isList);
            const bool usePointer = usePointerForElement(elemIt, newClass, mTypeMap, isList);
            generateMemberVariable(KODE::Style::makeIdentifier(elemIt.name()), typeName, inputTypeName, newClass, use, usePointer, polymorphic);
        }

        // include header
        newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(elemIt.type()));
        newClass.addHeaderIncludes(mTypeMap.headerIncludes(elemIt.type()));
        if (elemIt.maxOccurs() > 1 || elemIt.compositor().maxOccurs() > 1) {
            newClass.addHeaderIncludes(QStringList() << QLatin1String("QtCore/QList"));
        }
    }

    // attributes in the complex type
    XSD::Attribute::List attributes = type->attributes();
    Q_FOREACH (const XSD::Attribute &attribute, attributes) {
        QString typeName, inputTypeName;

        typeName = mTypeMap.localType(attribute.type());
        if (typeName.isEmpty()) {
            qDebug() << "ERROR: attribute with unknown type:" << attribute.name() << attribute.type() << "in" << typeName;
        }
        inputTypeName = mTypeMap.localInputType(attribute.type(), QName());
        //qDebug() << "Attribute" << attribute.name();

        generateMemberVariable(KODE::Style::makeIdentifier(attribute.name()), typeName, inputTypeName, newClass, attribute.attributeUse(), false, false);

        // include header
        newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(attribute.type()));
        newClass.addHeaderIncludes(mTypeMap.headerIncludes(attribute.type()));
    }