void Converter::convertOutputMessage( const Port&, const Message &message, KODE::Class &newClass ) { Message::Part part = message.parts().first(); // signal QString messageName = message.name(); messageName[ 0 ] = messageName[ 0 ].lower(); KODE::Function respSignal( messageName, "void", KODE::Function::Signal ); /** If one output message is used by two input messages, don't define it twice. */ if ( newClass.hasFunction( respSignal.name() ) ) return; const Message::Part::List parts = message.parts(); Message::Part::List::ConstIterator it; for ( it = parts.begin(); it != parts.end(); ++it ) { QStringList headers = mTypeMapper.header( (*it).type() ); for ( uint i = 0; i < headers.count(); ++i ) if ( !headers[ i ].isEmpty() ) newClass.addHeaderInclude( headers[ i ] ); respSignal.addArgument( mTypeMapper.argument( "value", (*it).type() ) ); } newClass.addFunction( respSignal ); // slot KODE::Function respSlot( messageName + "Slot", "void", KODE::Function::Slot | KODE::Function::Private ); respSlot.addArgument( "const QString &xml" ); KODE::Code code; code += "QDomDocument doc;"; code += "QString errorMsg;"; code += "int column, row;"; code.newLine(); code += "qDebug( \"%s\", xml.latin1() );"; code.newLine(); code += "if ( !doc.setContent( xml, true, &errorMsg, &row, &column ) ) {"; code.indent(); code += "qDebug( \"Unable to parse xml: %s (%d:%d)\", errorMsg.latin1(), row, column );"; code += "return;"; code.unindent(); code += "}"; code.newLine(); code += mTypeMapper.type( part.type() ) + "* value = new " + mTypeMapper.type( part.type() ) + ";"; code += "QDomElement envelope = doc.documentElement();"; code += "QDomElement body = envelope.firstChild().toElement();"; code += "QDomElement method = body.firstChild().toElement();"; code += "Serializer::demarshal( method.firstChild().toElement(), value );"; code.newLine(); code += "emit " + respSignal.name() + "( value );"; respSlot.setBody( code ); newClass.addFunction( respSlot ); }
void Converter::generateServerMethod(KODE::Code &code, const Binding &binding, const Operation &operation, KODE::Class &newClass, bool first) { const QString requestVarName = "_request"; const QString responseVarName = "_response"; const Message message = mWSDL.findMessage(operation.input().message()); Message outputMessage; if (operation.operationType() != Operation::OneWayOperation) { outputMessage = mWSDL.findMessage(operation.output().message()); } const QString operationName = operation.name(); const QString methodName = mNameMapper.escape(lowerlize(operationName)); KODE::Function virtualMethod(methodName); virtualMethod.setVirtualMode(KODE::Function::PureVirtual); QString condition = "method == \"" + operationName + "\""; if (binding.type() == Binding::SOAPBinding) { const SoapBinding soapBinding(binding.soapBinding()); const SoapBinding::Operation op = soapBinding.operations().value(operation.name()); if (!op.action().isEmpty()) { condition += " || _soapAction == \"" + op.action() + "\""; } } code += QString(first ? "" : "else ") + "if (" + condition + ") {"; code.indent(); QStringList inputVars; const Part::List parts = message.parts(); for (int partNum = 0; partNum < parts.count(); ++partNum) { const Part part = parts.at(partNum); const QString lowerName = lowerlize(part.name()); const QString argType = mTypeMap.localType(part.type(), part.element()); //qDebug() << "localInputType" << part.type().qname() << part.element().qname() << "->" << argType; if (argType != "void") { const QString varName = mNameMapper.escape(lowerName); code += argType + ' ' + varName + ";" + COMMENT; QString soapValueVarName = requestVarName; if (soapStyle(binding) == SoapBinding::RPCStyle) { // RPC comes with a wrapper element, dig into it here soapValueVarName = "val"; if (partNum > 0) { soapValueVarName += QString::number(partNum + 1); } code += QString::fromLatin1("const KDSoapValue %1 = %2.childValues().at(%3);").arg(soapValueVarName, requestVarName).arg(partNum) + COMMENT; } // what if there's more than one? code.addBlock(demarshalVar(part.type(), part.element(), varName, argType, soapValueVarName, false, false)); inputVars += varName; newClass.addIncludes(mTypeMap.headerIncludes(part.type()), mTypeMap.forwardDeclarationsForElement(part.element())); virtualMethod.addArgument(mTypeMap.localInputType(part.type(), part.element()) + ' ' + varName); } } const Part::List outParts = outputMessage.parts(); if (outParts.count() > 1) { qWarning("ERROR: multiple output parameters are not supported (operation %s) - please file" "an issue on github with your wsdl file", qPrintable(operation.name())); virtualMethod.setReturnType("void /*UNSUPPORTED*/"); } else if (outParts.isEmpty()) { code += lowerlize(operationName) + '(' + inputVars.join(", ") + ");"; virtualMethod.setReturnType("void"); } else { QString retType; QString retInputType; //bool isBuiltin = false; //bool isComplex = false; Part retPart; Q_FOREACH (const Part &outPart, outParts /* only one */) { retType = mTypeMap.localType(outPart.type(), outPart.element()); retInputType = mTypeMap.localInputType(outPart.type(), outPart.element()); //isBuiltin = mTypeMap.isBuiltinType( outPart.type(), outPart.element() ); //isComplex = mTypeMap.isComplexType( outPart.type(), outPart.element() ); retPart = outPart; } const QString methodCall = methodName + '(' + inputVars.join(", ") + ')'; if (retType == "void") { code += methodCall + ";" + COMMENT; } else { code += retType + " ret = " + methodCall + ";" + COMMENT; } code += "if (!hasFault()) {"; code.indent(); // TODO factorize with same code in next method if (soapStyle(binding) == SoapBinding::DocumentStyle) { code.addBlock(serializePart(retPart, "ret", responseVarName, false)); } else { code += QString("KDSoapValue wrapper(\"%1\", QVariant(), \"%2\");").arg(outputMessage.name()).arg(outputMessage.nameSpace()); code.addBlock(serializePart(retPart, "ret", "wrapper.childValues()", true)); code += responseVarName + " = wrapper;"; } code.unindent(); code += "}"; Q_ASSERT(!retType.isEmpty()); virtualMethod.setReturnType(retType); newClass.addIncludes(mTypeMap.headerIncludes(retPart.type()), mTypeMap.forwardDeclarationsForElement(retPart.element())); generateDelayedReponseMethod(methodName, retInputType, retPart, newClass, binding, outputMessage); }
void Converter::convertServerService() { Q_FOREACH (const Service &service, mWSDL.definitions().services()) { Q_ASSERT(!service.name().isEmpty()); QSet<QName> uniqueBindings = mWSDL.uniqueBindings(service); Q_FOREACH (const QName &bindingName, uniqueBindings) { //qDebug() << "binding" << bindingName; const Binding binding = mWSDL.findBinding(bindingName); QString className = KODE::Style::className(service.name()); QString nameSpace; if (uniqueBindings.count() > 1) { // Multiple bindings: use Service::Binding as classname. nameSpace = className; className = KODE::Style::className(bindingName.localName()); } className += "ServerBase"; KODE::Class serverClass(className, nameSpace); serverClass.addBaseClass(mQObject); serverClass.addBaseClass(mKDSoapServerObjectInterface); if (!Settings::self()->exportDeclaration().isEmpty()) { serverClass.setExportDeclaration(Settings::self()->exportDeclaration()); } serverClass.setNameSpace(Settings::self()->nameSpace()); // Files included in the header serverClass.addHeaderInclude("QtCore/QObject"); serverClass.addHeaderInclude("KDSoapServer/KDSoapServerObjectInterface.h"); serverClass.addDeclarationMacro("Q_OBJECT"); serverClass.addDeclarationMacro("Q_INTERFACES(KDSoapServerObjectInterface)"); KODE::Function processRequestMethod(QString::fromLatin1("processRequest"), QString::fromLatin1("void")); processRequestMethod.addArgument("const KDSoapMessage &_request"); processRequestMethod.addArgument("KDSoapMessage &_response"); processRequestMethod.addArgument("const QByteArray& _soapAction"); KODE::Code body; const QString responseNs = mWSDL.definitions().targetNamespace(); body.addLine("setResponseNamespace(QLatin1String(\"" + responseNs + "\"));" + COMMENT); body.addLine("const QByteArray method = _request.name().toLatin1();"); PortType portType = mWSDL.findPortType(binding.portTypeName()); //qDebug() << portType.name(); bool first = true; const Operation::List operations = portType.operations(); Q_FOREACH (const Operation &operation, operations) { const Operation::OperationType opType = operation.operationType(); switch (opType) { case Operation::OneWayOperation: case Operation::RequestResponseOperation: // the standard case case Operation::SolicitResponseOperation: case Operation::NotificationOperation: generateServerMethod(body, binding, operation, serverClass, first); break; } first = false; } if (!first) { body += "else {"; body.indent(); } body += "KDSoapServerObjectInterface::processRequest(_request, _response, _soapAction);" + COMMENT; if (!first) { body.unindent(); body += "}"; } processRequestMethod.setBody(body); serverClass.addFunction(processRequestMethod); mClasses.addClass(serverClass); } } }
KODE::Code ElementArgumentSerializer::generate() const { Q_ASSERT(!mLocalVarName.isEmpty()); Q_ASSERT(!mOutputVarName.isEmpty()); const QString varAndMethodBefore = mOutputVarName + (mAppend ? QLatin1String(".append(") : QLatin1String(" = ")); const QString varAndMethodAfter = mAppend ? QString::fromLatin1(")") : QString(); KODE::Code block; // for debugging, add this: //block += "// type: " + type.qname() + " element:" + elementType.qname(); //if ( name.localName() == "..." ) // qDebug() << "appendElementArg:" << name << "type=" << type << "isBuiltin=" << mTypeMap.isBuiltinType(type) << "isQualified=" << isQualified; if ( mTypeMap.isTypeAny( mType ) ) { block += QLatin1String("if (!") + mLocalVarName + QLatin1String(".isNull()) {"); block.indent(); block += varAndMethodBefore + mLocalVarName + varAndMethodAfter + QLatin1String(";") + COMMENT; block.unindent(); block += "}"; } else { const QName actualType = mType.isEmpty() ? mElementType : mType; const QString typeArgs = namespaceString(actualType.nameSpace()) + QLatin1String(", QString::fromLatin1(\"") + actualType.localName() + QLatin1String("\")"); const bool isComplex = mTypeMap.isComplexType( mType, mElementType ); const bool isPolymorphic = mTypeMap.isPolymorphic( mType, mElementType ); if ( mAppend && mOmitIfEmpty ) { if ( mUsePointer ) { block += "if (" + mLocalVarName + ") {"; } else { block += "if (!" + mLocalVarName + "_nil) {"; } block.indent(); } if ( isComplex ) { const QString op = (isPolymorphic || mUsePointer) ? "->" : "."; block += QLatin1String("KDSoapValue ") + mValueVarName + QLatin1Char('(') + mLocalVarName + op + QLatin1String("serialize(") + mNameArg + QLatin1String("));") + COMMENT; } else { if ( mTypeMap.isBuiltinType( mType, mElementType ) ) { const QString qtTypeName = mTypeMap.localType( mType, mElementType ); const QString value = mTypeMap.serializeBuiltin( mType, mElementType, mLocalVarName, qtTypeName ); block += QLatin1String("KDSoapValue ") + mValueVarName + QLatin1String("(" )+ mNameArg + QLatin1String(", ") + value + QLatin1String(", ") + typeArgs + QLatin1String(");") + COMMENT; } else { block += QLatin1String("KDSoapValue ") + mValueVarName + QLatin1String("(") + mNameArg + QLatin1String(", ") + mLocalVarName + QLatin1String(".serialize(), ") + typeArgs + QLatin1String(");") + COMMENT; } } if ( !mNameNamespace.isEmpty() ) block += mValueVarName + QLatin1String(".setNamespaceUri(") + mNameNamespace + QLatin1String(");"); if ( mIsQualified ) block += mValueVarName + QLatin1String(".setQualified(true);"); if ( mNillable ) block += mValueVarName + QLatin1String(".setNillable(true);"); if ( mAppend && mOmitIfEmpty ) { // omit empty children (testcase: MSExchange, no <ParentFolderIds/>) block += "if (!" + mValueVarName + ".isNil())"; } block += varAndMethodBefore + mValueVarName + varAndMethodAfter + QLatin1String(";") + COMMENT; if ( mAppend && mOmitIfEmpty ) { block.unindent(); block += "}"; } } return block; }
void Converter::generateServerMethod(KODE::Code& code, const Binding& binding, const Operation& operation, KODE::Class &newClass, bool first) { const Message message = mWSDL.findMessage( operation.input().message() ); Message outputMessage; if (operation.operationType() != Operation::OneWayOperation) { outputMessage = mWSDL.findMessage( operation.output().message() ); } const QString operationName = operation.name(); const QString methodName = mNameMapper.escape( lowerlize( operationName ) ); KODE::Function virtualMethod(methodName); virtualMethod.setVirtualMode(KODE::Function::PureVirtual); QString condition = "method == \"" + operationName + "\""; if ( binding.type() == Binding::SOAPBinding ) { const SoapBinding soapBinding( binding.soapBinding() ); const SoapBinding::Operation op = soapBinding.operations().value( operation.name() ); if (!op.action().isEmpty()) { condition += "|| soapAction == \"" + op.action() + "\""; } } code += QString(first ? "" : "else ") + "if (" + condition + ") {"; code.indent(); QStringList inputVars; const Part::List parts = message.parts(); if (parts.count() > 1) { qWarning("ERROR: multiple input parameters are not supported - please report this with your wsdl file to [email protected]"); } Q_FOREACH( const Part& part, parts ) { const QString lowerName = lowerlize( part.name() ); const QString argType = mTypeMap.localType( part.type(), part.element() ); //qDebug() << "localInputType" << part.type().qname() << part.element().qname() << "->" << argType; if ( argType != "void" ) { const QString varName = mNameMapper.escape( lowerName ); code += argType + ' ' + varName + ";" + COMMENT; QString soapValueVarName = "request"; if (soapStyle(binding) == SoapBinding::RPCStyle) { // RPC comes with a wrapper element, dig into it here code += QLatin1String("const KDSoapValue val = request.childValues().first();") + COMMENT; soapValueVarName = "val"; } // what if there's more than one? code.addBlock( demarshalVar( part.type(), part.element(), varName, argType, soapValueVarName ) ); inputVars += varName; newClass.addIncludes( mTypeMap.headerIncludes( part.type() ) ); virtualMethod.addArgument( mTypeMap.localInputType( part.type(), part.element() ) + ' ' + varName ); } } const Part::List outParts = outputMessage.parts(); if (outParts.count() > 1) { qWarning("ERROR: multiple output parameters are not supported (operation %s) - please report" " this with your wsdl file to [email protected]", qPrintable(operation.name())); virtualMethod.setReturnType("void /*UNSUPPORTED*/"); } else if (outParts.isEmpty()) { code += operationName + '(' + inputVars.join(", ") + ");"; virtualMethod.setReturnType("void"); } else { QString retType; QString retInputType; //bool isBuiltin = false; //bool isComplex = false; Part retPart; Q_FOREACH( const Part& outPart, outParts /* only one */ ) { retType = mTypeMap.localType( outPart.type(), outPart.element() ); retInputType = mTypeMap.localInputType( outPart.type(), outPart.element() ); //isBuiltin = mTypeMap.isBuiltinType( outPart.type(), outPart.element() ); //isComplex = mTypeMap.isComplexType( outPart.type(), outPart.element() ); retPart = outPart; } const QString methodCall = methodName + '(' + inputVars.join(", ") + ')'; if (retType == "void") { code += methodCall + ";" + COMMENT; } else { code += retType + " ret = " + methodCall + ";" + COMMENT; } code += "if (!hasFault()) {"; code.indent(); bool qualified; const QName elemName = elementNameForPart( retPart, &qualified ); if (soapStyle(binding) == SoapBinding::RPCStyle) { code += QString("KDSoapValue wrapper(\"%1\", QVariant());").arg(outputMessage.name()); code.addBlock( serializeElementArg( retPart.type(), retPart.element(), elemName, "ret", "wrapper.childValues()", true, qualified ) ); code += "response = wrapper;"; } else { code.addBlock( serializeElementArg( retPart.type(), retPart.element(), elemName, "ret", "response", false, qualified ) ); } code.unindent(); code += "}"; Q_ASSERT(!retType.isEmpty()); virtualMethod.setReturnType(retType); generateDelayedReponseMethod(methodName, retInputType, retPart, newClass, binding, outputMessage); }
void Converter::convertSimpleType( const XSD::SimpleType *type ) { const QString typeName( mTypeMap.localType( type->qualifiedName() ) ); KODE::Class newClass( typeName ); newClass.addInclude( QString(), "Serializer" ); KODE::Code ctorBody; KODE::Code dtorBody; QString classDocumentation; if ( type->subType() == XSD::SimpleType::TypeRestriction ) { /** Use setter and getter method for enums as well. */ if ( type->facetType() & XSD::SimpleType::ENUM ) { classDocumentation = "This class is a wrapper for an enumeration.\n"; QStringList enums = type->facetEnums(); for ( int i = 0; i < enums.count(); ++i ) enums[ i ] = escapeEnum( enums[ i ] ); newClass.addEnum( KODE::Enum( "Type", enums ) ); classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the enum directly (e.g. someMethod( " + newClass.name() + "::" + enums.first() + " ))."; // member variables KODE::MemberVariable variable( "type", "Type" ); newClass.addMemberVariable( variable ); // setter method KODE::Function setter( "setType", "void" ); setter.addArgument( "Type type" ); setter.setBody( variable.name() + " = type;" ); // getter method KODE::Function getter( "type", upperlize( newClass.name() ) + "::Type" ); getter.setBody( "return " + variable.name() + ';' ); getter.setConst( true ); // convenience constructor KODE::Function conctor( upperlize( newClass.name() ) ); conctor.addArgument( "const " + upperlize( newClass.name() ) + "::Type &type" ); KODE::Code code; code += variable.name() + " = type;"; conctor.setBody( code ); // type operator KODE::Function op( "operator const " + upperlize( newClass.name() ) + "::Type" ); op.setBody( "return " + variable.name() + ';' ); op.setConst( true ); newClass.addFunction( conctor ); newClass.addFunction( setter ); newClass.addFunction( getter ); newClass.addFunction( op ); } /** A class can't derive from basic types (e.g. int or unsigned char), so we add setter and getter methods to set the value of this class. */ if ( type->baseTypeName() != XmlAnyType && !type->baseTypeName().isEmpty() && !(type->facetType() & XSD::SimpleType::ENUM) ) { classDocumentation = "This class encapsulates an basic type.\n"; const QName baseName = type->baseTypeName(); const QString typeName = mTypeMap.localType( baseName ); classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the value directly (e.g. someMethod( (" + typeName + "*)value ))."; // include header newClass.addIncludes( QStringList(), mTypeMap.forwardDeclarations( baseName ) ); // member variables KODE::MemberVariable variable( "value", typeName + '*' ); newClass.addMemberVariable( variable ); ctorBody += variable.name() + " = 0;"; dtorBody += "delete " + variable.name() + "; " + variable.name() + " = 0;"; // setter method KODE::Function setter( "setValue", "void" ); setter.addArgument( typeName + " *value" ); KODE::Code setterBody; setterBody += createRangeCheckCode( type, "(*value)", newClass ); setterBody.newLine(); setterBody += "if ( !rangeOk )"; setterBody.indent(); setterBody += "qDebug( \"Invalid range in " + newClass.name() + "::" + setter.name() + "()\" );"; setterBody.unindent(); setterBody.newLine(); setterBody += variable.name() + " = value;"; setter.setBody( setterBody ); // getter method KODE::Function getter( "value", typeName + '*' ); getter.setBody( "return " + variable.name() + ';' ); getter.setConst( true ); // convenience constructor KODE::Function conctor( upperlize( newClass.name() ) ); conctor.addArgument( typeName + " *value" ); KODE::Code code; code += createRangeCheckCode( type, "(*value)", newClass ); code.newLine(); code += "if ( !rangeOk )"; code.indent(); code += "qDebug( \"Invalid range in " + newClass.name() + "::" + conctor.name() + "()\" );"; code.unindent(); code.newLine(); code += variable.name() + " = value;"; conctor.setBody( code ); if ( typeName == "QString" ) { KODE::Function charctor( upperlize( newClass.name() ) ); charctor.addArgument( "const char *charValue" ); KODE::Code code; code += "QString *value = new QString( charValue );"; code += createRangeCheckCode( type, "(*value)", newClass ); code.newLine(); code += "if ( !rangeOk )"; code.indent(); code += "qDebug( \"Invalid range in " + newClass.name() + "::" + charctor.name() + "()\" );"; code.unindent(); code.newLine(); code += variable.name() + " = value;"; charctor.setBody( code ); newClass.addFunction( charctor ); } // type operator KODE::Function op( "operator const " + typeName + '*' ); op.setBody( "return " + variable.name() + ';' ); op.setConst( true ); newClass.addFunction( conctor ); newClass.addFunction( op ); newClass.addFunction( setter ); newClass.addFunction( getter ); } } else if ( type->subType() == XSD::SimpleType::TypeList ) { classDocumentation = "This class encapsulates a list type."; newClass.addHeaderInclude( "QList" ); const QName baseName = type->listTypeName(); const QString typeName = mTypeMap.localType( baseName ); // include header newClass.addIncludes( QStringList(), mTypeMap.forwardDeclarations( baseName ) ); // member variables KODE::MemberVariable variable( "entries", "QList<" + typeName + "*>*" ); newClass.addMemberVariable( variable ); ctorBody += variable.name() + " = 0;"; dtorBody += "qDeleteAll( *" + variable.name() + " );"; dtorBody += variable.name() + "->clear();"; dtorBody += "delete " + variable.name() + "; " + variable.name() + " = 0;"; // setter method KODE::Function setter( "setEntries", "void" ); setter.addArgument( "QList<" + typeName + "*> *entries" ); setter.setBody( variable.name() + " = entries;" ); // getter method KODE::Function getter( "entries", "QList<" + typeName + "*>*" ); getter.setBody( "return " + variable.name() + ';' ); getter.setConst( true ); newClass.addFunction( setter ); newClass.addFunction( getter ); } if ( !type->documentation().isEmpty() ) newClass.setDocs( type->documentation().simplified() ); else newClass.setDocs( classDocumentation ); createSimpleTypeSerializer( type ); KODE::Function ctor( upperlize( newClass.name() ) ); ctor.setBody( ctorBody ); newClass.addFunction( ctor ); KODE::Function dtor( '~' + upperlize( newClass.name() ) ); dtor.setBody( dtorBody ); newClass.addFunction( dtor ); mClasses.append( newClass ); }
void Converter::createTransportClass() { KODE::Class transport( "Transport" ); transport.addBaseClass( mQObject ); transport.addHeaderInclude( "qobject.h" ); transport.addHeaderInclude( "kio/job.h" ); transport.addInclude( "kdebug.h" ); KODE::MemberVariable url( "url", "QString" ); transport.addMemberVariable( url ); KODE::MemberVariable slotDataVar( "data", "QByteArray" ); transport.addMemberVariable( slotDataVar ); // ctor KODE::Function ctor( "Transport" ); ctor.addArgument( "const QString &url" ); ctor.setBody( url.name() + " = url;" ); transport.addFunction( ctor ); // query KODE::Function query( "query", "void" ); query.addArgument( "const QString &xml" ); KODE::Code queryCode; queryCode += slotDataVar.name() + ".truncate( 0 );"; queryCode.newLine(); queryCode += "QByteArray postData;"; queryCode += "QDataStream stream( postData, IO_WriteOnly );"; queryCode += "stream.writeRawBytes( xml.utf8(), xml.utf8().length() );"; queryCode.newLine(); queryCode += "KIO::TransferJob* job = KIO::http_post( KURL( " + url.name() + " ), postData, false );"; queryCode += "if ( !job ) {"; queryCode.indent(); queryCode += "kdWarning() << \"Unable to create KIO job for \" << " + url.name() + " << endl;"; queryCode += "return;"; queryCode.unindent(); queryCode += "}"; queryCode.newLine(); queryCode += "job->addMetaData( \"UserAgent\", \"KWSDL\" );"; queryCode += "job->addMetaData( \"content-type\", \"Content-Type: text/xml; charset=utf-8\" );"; queryCode.newLine(); queryCode += "connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );"; queryCode += "connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );"; query.setBody( queryCode ); transport.addFunction( query ); // signal KODE::Function result( "result", "void", KODE::Function::Signal ); result.addArgument( "const QString &xml" ); transport.addFunction( result ); // data slot KODE::Function slotData( "slotData", "void", KODE::Function::Private | KODE::Function::Slot ); slotData.addArgument( "KIO::Job*" ); slotData.addArgument( "const QByteArray &data" ); KODE::Code slotDataCode; slotDataCode += "unsigned int oldSize = " + slotDataVar.name() + ".size();"; slotDataCode += slotDataVar.name() + ".resize( oldSize + data.size() );"; slotDataCode += "memcpy( " + slotDataVar.name() + ".data() + oldSize, data.data(), data.size() );"; slotData.setBody( slotDataCode ); transport.addFunction( slotData ); // result slot KODE::Function slotResult( "slotResult", "void", KODE::Function::Private | KODE::Function::Slot ); slotResult.addArgument( "KIO::Job* job" ); KODE::Code slotResultCode; slotResultCode += "if ( job->error() != 0 ) {"; slotResultCode.indent(); slotResultCode += "kdWarning() << \"Error occurred \" << job->errorText() << endl;"; slotResultCode += "kdWarning() << " + slotDataVar.name() + " << endl;"; slotResultCode += "return;"; slotResultCode.unindent(); slotResultCode += "}"; slotResultCode.newLine(); slotResultCode += "emit result( QString::fromUtf8( " + slotDataVar.name() + ".data(), " + slotDataVar.name() + ".size() ) );"; slotResult.setBody( slotResultCode ); transport.addFunction( slotResult ); mClasses.append( transport ); }
void Converter::convertSimpleType(const XSD::SimpleType *type, const XSD::SimpleType::List &simpleTypeList) { const QString typeName(mTypeMap.localType(type->qualifiedName())); //qDebug() << "convertSimpleType:" << type->qualifiedName() << typeName; KODE::Class newClass; newClass.setNamespaceAndName(typeName); if (!Settings::self()->exportDeclaration().isEmpty()) { newClass.setExportDeclaration(Settings::self()->exportDeclaration()); } newClass.setNameSpace(Settings::self()->nameSpace()); QString classDocumentation; switch (type->subType()) { case XSD::SimpleType::TypeRestriction: { /** Use setter and getter method for enums as well. */ if (type->facetType() & XSD::SimpleType::ENUM) { classDocumentation = "This class is a wrapper for an enumeration.\n"; NameMapper nameMapper; QStringList enums = type->facetEnums(); for (int i = 0; i < enums.count(); ++i) { enums[ i ] = nameMapper.escape(escapeEnum(enums[ i ])); } newClass.addEnum(KODE::Enum("Type", enums)); classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the enum directly. Example:\n" + "someMethod(" + newClass.name() + "::" + enums.first() + ")."; // member variables KODE::MemberVariable variable("type", "Type"); variable.setInitializer("Type(0)"); newClass.addMemberVariable(variable); // setter method KODE::Function setter("setType", "void"); setter.addArgument("Type type"); setter.setBody(variable.name() + " = type;"); // getter method KODE::Function getter("type", newClass.qualifiedName() + "::Type"); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument("const Type &type"); KODE::Code code; code += variable.name() + " = type;"; conctor.setBody(code); // type operator KODE::Function op("operator Type"); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(conctor); newClass.addFunction(setter); newClass.addFunction(getter); newClass.addFunction(op); } /** A class can't derive from basic types (e.g. int or unsigned char), so we add setter and getter methods to set the value of this class. */ if (type->baseTypeName() != XmlAnyType && !type->baseTypeName().isEmpty() && !(type->facetType() & XSD::SimpleType::ENUM)) { classDocumentation = "This class encapsulates a simple type.\n"; const QName baseName = type->baseTypeName(); const QString baseTypeName = mTypeMap.localType(baseName); Q_ASSERT(!baseTypeName.isEmpty()); QList<QName> parentBasicTypes; parentBasicTypes.append(baseName); QName currentType = baseName; Q_FOREVER { const XSD::SimpleType simpleType = simpleTypeList.simpleType(currentType); if (!simpleType.isNull() && simpleType.isRestriction()) { currentType = simpleType.baseTypeName(); parentBasicTypes.append(currentType); continue; } break; } classDocumentation += "Whenever you have to pass an object of type " + newClass.name() + " you can also pass the value directly as a " + mTypeMap.localType(currentType) + '.'; // include header newClass.addIncludes(QStringList(), mTypeMap.forwardDeclarations(baseName)); newClass.addHeaderIncludes(mTypeMap.headerIncludes(baseName)); // member variables KODE::MemberVariable variable("value", baseTypeName); addVariableInitializer(variable); newClass.addMemberVariable(variable); // setter method KODE::Function setter("setValue", "void"); const QString inputType = mTypeMap.localInputType(baseName, QName()); setter.addArgument(inputType + " value"); KODE::Code setterBody; if (type->facetType() != XSD::SimpleType::NONE) { const XSD::SimpleType baseSimpleType = simpleTypeList.simpleType(baseName); setterBody += createRangeCheckCode(type, baseTypeName, "value", newClass, baseSimpleType); setterBody.newLine(); setterBody += "if (!rangeOk)"; setterBody.indent(); setterBody += "qDebug( \"Invalid range in " + newClass.name() + "::" + setter.name() + "()\" );"; setterBody.unindent(); setterBody.newLine(); } setterBody += variable.name() + " = value;"; // ### call setValue in base class? setter.setBody(setterBody); newClass.addFunction(setter); // getter method KODE::Function getter("value", baseTypeName); getter.setBody("return " + variable.name() + ';'); getter.setConst(true); newClass.addFunction(getter); // convenience constructor KODE::Function conctor(newClass.name()); conctor.addArgument(inputType + " value"); conctor.addBodyLine("setValue(value);"); newClass.addFunction(conctor); // even more convenient constructor, for the case of multiple-level simple-type restrictions //qDebug() << typeName << ": baseName=" << baseName << "further up:" << parentBasicTypes; if (parentBasicTypes.count() > 1) { parentBasicTypes.removeLast(); // the top-most one is in "currentType", so it's the input arg. KODE::Function baseCtor(conctor.name()); baseCtor.addArgument(mTypeMap.localInputType(currentType, QName()) + " value"); QString beginLine = "setValue("; QString endLine = ")"; Q_FOREACH (const QName &base, parentBasicTypes) { beginLine += mTypeMap.localType(base) + '('; endLine += ')'; } baseCtor.addBodyLine(beginLine + "value" + endLine + ';'); newClass.addFunction(baseCtor); } // type operator KODE::Function op("operator " + baseTypeName); op.setBody("return " + variable.name() + ';'); op.setConst(true); newClass.addFunction(op); }
void Converter::createKDETransport() { KODE::Class transport( "Transport" ); transport.addBaseClass( mQObject ); transport.addHeaderInclude( "QObject" ); transport.addHeaderInclude( "kio/job.h" ); transport.addInclude( "kdebug.h" ); KODE::MemberVariable url( "url", "QString" ); transport.addMemberVariable( url ); KODE::MemberVariable slotDataVar( "data", "QByteArray" ); transport.addMemberVariable( slotDataVar ); // ctor KODE::Function ctor( "Transport" ); ctor.addArgument( "const QString &url" ); ctor.setBody( url.name() + " = url;" ); transport.addFunction( ctor ); // query KODE::Function query( "query", "void" ); query.addArgument( "const QString &xml" ); query.addArgument( "const QString &header" ); KODE::Code queryCode; queryCode += slotDataVar.name() + ".truncate( 0 );"; queryCode.newLine(); queryCode += "QByteArray postData;"; queryCode += "QDataStream stream( &postData, QIODevice::WriteOnly );"; queryCode += "stream.writeRawData( xml.toUtf8(), xml.toUtf8().length() );"; queryCode.newLine(); queryCode += "KIO::TransferJob* job = KIO::http_post( KUrl( " + url.name() + " ), postData, KIO::HideProgressInfo );"; queryCode += "if ( !job ) {"; queryCode.indent(); queryCode += "kWarning() << \"Unable to create KIO job for \" <<" + url.name() +";"; queryCode += "return;"; queryCode.unindent(); queryCode += '}'; queryCode.newLine(); queryCode += "job->addMetaData( \"UserAgent\", \"KWSDL\" );"; queryCode += "job->addMetaData( \"content-type\", \"Content-Type: application/xml; charset=utf-8\" );"; queryCode += "if ( !header.isEmpty() ) {"; queryCode.indent(); queryCode += "job->addMetaData( \"customHTTPHeader\", \"SOAPAction:\" + header );"; queryCode.unindent(); queryCode += '}'; queryCode.newLine(); queryCode += "connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );"; queryCode += "connect( job, SIGNAL( result( KJob* ) ), this, SLOT( slotResult( KJob* ) ) );"; query.setBody( queryCode ); transport.addFunction( query ); // signal KODE::Function result( "result", "void", KODE::Function::Signal ); result.addArgument( "const QString &xml" ); KODE::Function error( "error", "void", KODE::Function::Signal ); error.addArgument( "const QString &msg" ); transport.addFunction( result ); transport.addFunction( error ); // data slot KODE::Function slotData( "slotData", "void", KODE::Function::Private | KODE::Function::Slot ); slotData.addArgument( "KIO::Job*" ); slotData.addArgument( "const QByteArray &data" ); KODE::Code slotDataCode; slotDataCode += "unsigned int oldSize = " + slotDataVar.name() + ".size();"; slotDataCode += slotDataVar.name() + ".resize( oldSize + data.size() );"; slotDataCode += "memcpy( " + slotDataVar.name() + ".data() + oldSize, data.data(), data.size() );"; slotData.setBody( slotDataCode ); transport.addFunction( slotData ); // result slot KODE::Function slotResult( "slotResult", "void", KODE::Function::Private | KODE::Function::Slot ); slotResult.addArgument( "KJob* job" ); KODE::Code slotResultCode; slotResultCode += "if ( job->error() != 0 ) {"; slotResultCode.indent(); slotResultCode += "emit error( job->errorText() );"; slotResultCode += "return;"; slotResultCode.unindent(); slotResultCode += '}'; slotResultCode.newLine(); slotResultCode += "emit result( QString::fromUtf8( " + slotDataVar.name() + ".data(), " + slotDataVar.name() + ".size() ) );"; slotResult.setBody( slotResultCode ); transport.addFunction( slotResult ); mClasses.append( transport ); }
void Converter::createQtTransport() { KODE::Class transport( "Transport" ); transport.addBaseClass( mQObject ); transport.addHeaderInclude( "QBuffer" ); transport.addHeaderInclude( "QByteArray" ); transport.addHeaderInclude( "QObject" ); transport.addHeaderInclude( "QHttp" ); transport.addHeaderInclude( "QUrl" ); // member variables KODE::MemberVariable bufferVar( "buffer", "QBuffer" ); transport.addMemberVariable( bufferVar ); KODE::MemberVariable dataVar( "data", "QByteArray" ); transport.addMemberVariable( dataVar ); KODE::MemberVariable httpVar( "http", "QHttp*" ); transport.addMemberVariable( httpVar ); KODE::MemberVariable urlVar( "url", "QUrl" ); transport.addMemberVariable( urlVar ); KODE::MemberVariable idVar( "id", "int" ); transport.addMemberVariable( idVar ); // functions KODE::Function ctor( "Transport" ); ctor.addArgument( "const QString &url" ); ctor.addInitializer( "QObject( 0 )" ); ctor.addInitializer( urlVar.name() + "( url )" ); KODE::Function query( "query", "void" ); query.addArgument( "const QString &message" ); query.addArgument( "const QString &headerStr" ); KODE::Function resultSignal( "result", "void", KODE::Function::Signal ); resultSignal.addArgument( "const QString &result" ); KODE::Function errorSignal( "error", "void", KODE::Function::Signal ); errorSignal.addArgument( "const QString &msg" ); KODE::Function finishedSlot( "finished", "void", KODE::Function::Slot | KODE::Function::Private ); finishedSlot.addArgument( "int id" ); finishedSlot.addArgument( "bool errorOccurred" ); // codes KODE::Code code; code += "QUrl server( url );"; code.newLine(); code += httpVar.name() + " = new QHttp( this );"; code += httpVar.name() + "->setHost( server.host(), server.port( 80 ) );"; code.newLine(); code += "connect( " + httpVar.name() + ", SIGNAL( requestFinished( int, bool ) ), this, SLOT( " + finishedSlot.name() + "( int, bool ) ) );"; ctor.setBody( code ); code.clear(); code += dataVar.name() + ".clear();"; code += bufferVar.name() + ".setBuffer( &" + dataVar.name() + " );"; code.newLine(); code += "QHttpRequestHeader header;"; code += "header.setRequest( \"POST\", " + urlVar.name() + ".path() );"; code += "header.addValue( \"Connection\", \"Keep-Alive\" );"; code += "header.addValue( \"Content-Type\", \"application/xml; charset=utf-8\" );"; code += "header.addValue( \"Host\", QUrl( " + urlVar.name() + " ).host() );"; code.newLine(); code += "if ( !headerStr.isEmpty() )"; code.indent(); code += "header.addValue( \"SOAPAction\", headerStr );"; code.unindent(); code.newLine(); code += "QUrl server( " + urlVar.name() + " );"; code += "if ( server.port( 80 ) != 80 )"; code.indent(); code += "header.setValue( \"Host\", server.host() + \":\" + QString::number( server.port() ) );"; code.unindent(); code += "else"; code.indent(); code += "header.setValue( \"Host\", server.host() );"; code.unindent(); code.newLine(); code += idVar.name() + " = " + httpVar.name() + "->request( header, message.toUtf8(), &" + bufferVar.name() + " );"; query.setBody( code ); code.clear(); code += "if ( id != " + idVar.name() + " )"; code.indent(); code += "return;"; code.unindent(); code.newLine(); code += "if ( errorOccurred )"; code.indent(); code += "emit " + errorSignal.name() + "( " + httpVar.name() + "->errorString() );"; code.unindent(); code += "else"; code.indent(); code += "emit " + resultSignal.name() + "( QString::fromUtf8( " + dataVar.name() + " ) );"; code.unindent(); finishedSlot.setBody( code ); transport.addFunction( ctor ); transport.addFunction( query ); transport.addFunction( resultSignal ); transport.addFunction( errorSignal ); transport.addFunction( finishedSlot ); mClasses.append( transport ); }
int create(KCmdLineArgs *args) { KODE::Printer p; if(args->isSet("warning")) p.setCreationWarning(true); bool createKioslave = args->isSet("create-kioslave"); bool createMain = args->isSet("create-main"); QString filename = args->getOption("filename"); if(createMain) { if(filename.isEmpty()) { kdError() << "Error: No file name given." << endl; return 1; } if(filename.endsWith(".cpp")) { filename = filename.left(filename.length() - 4); } } else { if(!args->isSet("classname")) { kdError() << "Error: No class name given." << endl; return 1; } } QString className = args->getOption("classname"); QString protocol; if(createKioslave) { if(!args->isSet("protocol")) { protocol = className.lower(); kdWarning() << "Warning: No protocol for kioslave given. Assuming '" << protocol << "'" << endl; } else { protocol = args->getOption("protocol"); } } KODE::File file; file.setProject(args->getOption("project")); QString authorEmail = args->getOption("author-email"); QString authorName; KABC::Addressee a; if(authorEmail.isEmpty()) { a = KABC::StdAddressBook::self()->whoAmI(); authorEmail = a.preferredEmail(); } else { KABC::Addressee::List as = KABC::StdAddressBook::self()->findByEmail(authorEmail); if(as.isEmpty()) { kdDebug() << "Unable to find '" << authorEmail << "' in address book." << endl; } else { a = as.first(); } } if(!a.isEmpty()) { authorName = a.realName(); } if(!authorEmail.isEmpty()) { file.addCopyright(QDate::currentDate().year(), authorName, authorEmail); } KODE::License l; if(args->isSet("gpl")) l = KODE::License(KODE::License::GPL); if(args->isSet("lgpl")) l = KODE::License(KODE::License::LGPL); l.setQtException(args->isSet("qt-exception")); file.setLicense(l); file.setNameSpace(args->getOption("namespace")); if(createMain) { file.addInclude("kaboutdata.h"); file.addInclude("kapplication.h"); file.addInclude("kdebug"); file.addInclude("klocale"); file.addInclude("kcmdlineargs"); KODE::Code code; code += "static const KCmdLineOptions options[] ="; code += "{"; code += " { \"verbose\", \"Verbose output\", 0 },"; code += " KCmdLineLastOption"; code += "};"; file.addFileCode(code); KODE::Function main("main", "int"); main.addArgument("int argc"); main.addArgument("char **argv"); code.clear(); code += "KAboutData aboutData(\"test\",\"Test\",\"0.1\");"; code += "KCmdLineArgs::init(argc,argv,&aboutData);"; code += "KCmdLineArgs::addCmdLineOptions( options );"; code += ""; code += "KApplication app;"; code += ""; code += "KCmdLineArgs *args = KCmdLineArgs::parsedArgs();"; code += ""; code += "Q_UNUSED( args );"; main.setBody(code); file.addFileFunction(main); file.setFilename(filename); p.printImplementation(file, false); return 0; } KODE::Class c(className); if(args->isSet("create-dialog")) { c.addBaseClass(KODE::Class("KDialogBase")); c.addInclude("kdialogbase.h"); } else if(createKioslave) { c.setDocs("This class implements a kioslave for ..."); c.addBaseClass(KODE::Class("SlaveBase", "KIO")); c.addHeaderInclude("kio/slavebase.h"); KODE::Function get("get", "void"); get.addArgument("const KURL &url"); KODE::Code code; code += "kdDebug(7000) << \"" + className + "::get()\" << endl;"; code += "kdDebug(7000) << \" URL: \" << url.url() << endl;"; code += "#if 1"; code += "kdDebug(7000) << \" Path: \" << url.path() << endl;"; code += "kdDebug(7000) << \" Query: \" << url.query() << endl;"; code += "kdDebug(7000) << \" Protocol: \" << url.protocol() << endl;"; code += "kdDebug(7000) << \" Filename: \" << url.filename() << endl;"; code += "#endif"; code.newLine(); code += "mimeType( \"text/plain\" );"; code.newLine(); code += "QCString str( \"Hello!\" );"; code += "data( str );"; code.newLine(); code += "finished();"; code.newLine(); code += "kdDebug(7000) << \"" + className + "CgiProtocol::get() done\" << endl;"; get.setBody(code); c.addFunction(get); c.addInclude("kinstance.h"); c.addInclude("kdebug.h"); c.addInclude("sys/types.h"); c.addInclude("unistd.h"); c.addInclude("stdlib.h"); KODE::Function main("kdemain", "int"); main.addArgument("int argc"); main.addArgument("char **argv"); code.clear(); code += "KInstance instance( \"kio_" + protocol + "\" );"; code += ""; code += "kdDebug(7000) << \"Starting kio_" + protocol + "(pid: \" << getpid() << \")\" << endl;"; code += ""; code += "if (argc != 4) {"; code.indent(); code += "fprintf( stderr, \"Usage: kio_" + protocol + " protocol domain-socket1 domain-socket2\\n\");"; code += "exit( -1 );"; code.unindent(); code += "}"; code += ""; code += className + " slave( argv[2], argv[3] );"; code += "slave.dispatchLoop();"; code += ""; code += "return 0;"; main.setBody(code); file.addFileFunction(main); file.addExternCDeclaration(p.functionSignature(main)); } KODE::Function constructor(className); if(args->isSet("singleton")) { constructor.setAccess(KODE::Function::Private); KODE::Function self("self", className + " *"); self.setStatic(true); KODE::Code code; code += "if ( !mSelf ) {"; code += " selfDeleter.setObject( mSelf, new " + className + "() );"; code += "}"; code += "return mSelf;"; self.setBody(code); c.addFunction(self); KODE::MemberVariable selfVar("mSelf", className + " *", true); selfVar.setInitializer("0"); c.addMemberVariable(selfVar); KODE::Variable staticDeleter("selfDeleter", "KStaticDeleter<" + className + ">", true); file.addFileVariable(staticDeleter); file.addInclude("kstaticdeleter.h"); } if(createKioslave) { constructor.addArgument("const QCString &pool"); constructor.addArgument("const QCString &app"); constructor.addInitializer("SlaveBase( \"" + protocol + "\", pool, app )"); } c.addFunction(constructor); file.insertClass(c); p.printHeader(file); p.printImplementation(file); if(createKioslave) { // Write automake Makefile KODE::AutoMakefile am; am.addEntry("INCLUDES", "$(all_includes)"); am.newLine(); am.addEntry("noinst_HEADERS", className.lower() + ".h"); am.newLine(); am.addEntry("METASOURCES", "AUTO"); am.newLine(); am.addEntry("kdelnkdir", "$(kde_servicesdir)"); am.addEntry("kdelnk_DATA", protocol + ".protocol"); KODE::AutoMakefile::Target t("kde_module_LTLIBRARIES", "kio_" + protocol + ".la"); t.setSources(className.lower() + ".cpp"); t.setLibAdd("$(LIB_KIO)"); t.setLdFlags("$(all_libraries) -module $(KDE_PLUGIN)"); am.addTarget(t); p.printAutoMakefile(am); // Write protocol file QString protocolFilename = protocol + ".protocol"; QFileInfo fi(protocolFilename); protocolFilename = fi.absFilePath(); KSaveFile::backupFile(protocolFilename, QString::null, ".backup"); QFile::remove(protocolFilename); KSimpleConfig protocolFile(protocolFilename); protocolFile.setGroup("Protocol"); protocolFile.writeEntry("exec", "kio_" + protocol); protocolFile.writeEntry("protocol", protocol); protocolFile.writeEntry("input", "none"); protocolFile.writeEntry("output", "filesystem"); protocolFile.writeEntry("reading", "true"); protocolFile.writeEntry("DocPath", "kioslave/" + protocol + ".html"); protocolFile.sync(); } return 0; }