/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "qdbusmetaobject_p.h" #include "qdbusintrospection_p.h" #include #include #include #ifdef Q_WS_WIN #include #endif #define PROGRAMNAME "qdbusxml2cpp" #define PROGRAMVERSION "0.7" #define PROGRAMCOPYRIGHT "Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)." #define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" static QString adaptorPackage; static QString proxyPackage; static QString parentClassName; static QString proxyFile; static QString adaptorFile; static QString inputFile; static bool skipNamespaces; static bool verbose; static bool includeMocs; static QString commandLine; static QStringList includes; static QStringList wantedInterfaces; static const char help[] = "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n" "Produces the C++ code to implement the interfaces defined in the input file.\n" "\n" "Options:\n" " -a Write the adaptor code to \n" " -A Use as the package for the generated adaptor\n" " -h Show this information\n" " -i Add #include to the output\n" " -l When generating an adaptor, use as the parent class\n" " -m Generate #include \"filename.moc\" statements in the .cpp files\n" " -N Don't use namespaces\n" " -p Write the proxy code to \n" " -P Use as the package for the generated proxy\n" " -v Be verbose.\n" " -V Show the program version and quit.\n" "\n" "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" "program will automatically append the suffixes and produce both files.\n" "You can also use a colon (:) to separate the header name from the source file\n" "name, as in '-a filename_p.h:filename.cpp'.\n" "\n" "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" "to the standard output\n"; static const char forwardDeclarations[] = "class QByteArray;\n" "template class QList;\n" "template class QMap;\n" "class QString;\n" "class QStringList;\n" "class QVariant;\n"; static void showHelp() { printf("%s", help); exit(0); } static void showVersion() { printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION); printf("D-Bus binding tool for Qt\n"); exit(0); } static QString nextArg(QStringList &args, int i, char opt) { QString arg = args.value(i); if (arg.isEmpty()) { printf("-%c needs at least one argument\n", opt); exit(1); } return args.takeAt(i); } static void parseCmdLine(QStringList args) { args.takeFirst(); commandLine = QLatin1String(PROGRAMNAME " "); commandLine += args.join(QLatin1String(" ")); int i = 0; while (i < args.count()) { if (!args.at(i).startsWith(QLatin1Char('-'))) { ++i; continue; } QString arg = args.takeAt(i); char c = '\0'; if (arg.length() == 2) c = arg.at(1).toLatin1(); else if (arg == QLatin1String("--help")) c = 'h'; else if (arg == QLatin1String("--adaptorPackage")) c = 'A'; else if (arg == QLatin1String("--proxyPackage")) c = 'P'; switch (c) { case 'a': adaptorFile = nextArg(args, i, 'a'); break; case 'A': adaptorPackage = nextArg(args, i, 'A'); break; case 'v': verbose = true; break; case 'i': includes << nextArg(args, i, 'i'); break; case 'l': parentClassName = nextArg(args, i, 'l'); break; case 'm': includeMocs = true; break; case 'N': skipNamespaces = true; break; case '?': case 'h': showHelp(); break; case 'V': showVersion(); break; case 'p': proxyFile = nextArg(args, i, 'p'); break; case 'P': proxyPackage = nextArg(args, i, 'P'); break; default: printf("unknown option: '%s'\n", qPrintable(arg)); exit(1); } } if (!args.isEmpty()) inputFile = args.takeFirst(); wantedInterfaces << args; } static QDBusIntrospection::Interfaces readInput() { QFile input(inputFile); if (inputFile.isEmpty() || inputFile == QLatin1String("-")) input.open(stdin, QIODevice::ReadOnly); else input.open(QIODevice::ReadOnly); QByteArray data = input.readAll(); // check if the input is already XML data = data.trimmed(); if (data.startsWith("= 0) annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId); QString qttype = annotations.value(annotationName); if (!qttype.isEmpty()) return qttype.toLatin1(); fprintf(stderr, "Got unknown type `%s'\n", qPrintable(signature)); fprintf(stderr, "You should add \"/> to the XML description\n", qPrintable(annotationName)); exit(1); } return QVariant::typeToName(QVariant::Type(type)); } static QString nonConstRefArg(const QByteArray &arg) { return QLatin1String(arg + " &"); } static QString templateArg(const QByteArray &arg) { if (!arg.endsWith('>')) return QLatin1String(arg); return QLatin1String(arg + ' '); } static QString constRefArg(const QByteArray &arg) { if (!arg.startsWith('Q')) return QLatin1String(arg + ' '); else return QString( QLatin1String("const %1 &") ).arg( QLatin1String(arg) ); } static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) { QStringList retval; for (int i = 0; i < inputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = inputArgs.at(i); QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("in%1") ).arg(i); while (retval.contains(name)) name += QLatin1String("_"); retval << name; } for (int i = 0; i < outputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = outputArgs.at(i); QString name = arg.name; if (name.isEmpty()) name = QString( QLatin1String("out%1") ).arg(i); while (retval.contains(name)) name += QLatin1String("_"); retval << name; } return retval; } static void writeArgTypesList(QTextStream &ts, const QStringList &/*argNames*/, const QDBusIntrospection::Annotations &annotations, const QDBusIntrospection::Arguments &inputArgs, const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) { // input args: bool first = true; int argPos = 0; for (int i = 0; i < inputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = inputArgs.at(i); QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In")); if (!first) ts << ", "; ts << "'" << type << "'"; first = false; } argPos++; // output args // yes, starting from 1 for (int i = 1; i < outputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = outputArgs.at(i); QString name = arg.name; if (!first) ts << ", "; ts << "'" << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out")) << "'"; first = false; } } static void writeArgList(QTextStream &ts, const QStringList &argNames, const QDBusIntrospection::Annotations &/*annotations*/, const QDBusIntrospection::Arguments &inputArgs, const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) { // input args: bool first = true; int argPos = 0; for (int i = 0; i < inputArgs.count(); ++i) { if (!first) ts << ", "; ts << "$" << argNames.at(argPos++); first = false; } argPos++; // output args // yes, starting from 1 for (int i = 1; i < outputArgs.count(); ++i) { if (!first) ts << ", "; ts << "$" << argNames.at(argPos++); first = false; } } static QString propertyGetter(const QDBusIntrospection::Property &property) { QString getter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertyGetter")); if (getter.isEmpty()) { getter = property.name; getter[0] = getter[0].toLower(); } return getter; } static QString propertySetter(const QDBusIntrospection::Property &property) { QString setter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertySetter")); if (setter.isEmpty()) { setter = QLatin1String("set") + property.name; setter[3] = setter[3].toUpper(); } return setter; } static QString stringify(const QString &data) { QString retval; int i; for (i = 0; i < data.length(); ++i) { retval += QLatin1Char('\"'); for ( ; i < data.length() && data[i] != QLatin1Char('\n'); ++i) if (data[i] == QLatin1Char('\"')) retval += QLatin1String("\\\""); else retval += data[i]; retval += QLatin1String("\\n\" .\n"); } return retval; } static void openFile(const QString &fileName, QFile &file) { if (fileName.isEmpty()) return; bool isOk = false; if (fileName == QLatin1String("-")) { isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text); } else { file.setFileName(fileName); isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); } if (!isOk) fprintf(stderr, "Unable to open '%s': %s\n", qPrintable(fileName), qPrintable(file.errorString())); } static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) { // open the file QString headerName = pm(filename); QString cppName = pm(filename); QString perlName = pm(filename); QByteArray headerData; QTextStream hs(&headerData); QByteArray cppData; QTextStream cs(&cppData); // write the header: writeHeader(hs, true); if (cppName != headerName) writeHeader(cs, false); foreach (QString include, includes) { hs << "use " << include << ";" << endl; } hs << endl; foreach (const QDBusIntrospection::Interface *interface, interfaces) { QString className = classNameForInterface(interface->name, Proxy); // comment: hs << "#" << endl << "# Proxy class for interface " << interface->name << endl << "#" << endl; cs << "#" << endl << "# Implementation of interface class " << className << endl << "#" << endl << endl; // class header: hs << "package " << className << ";" << endl; hs << "use strict;" << endl; hs << "use warnings;" << endl; hs << "use QtCore4;" << endl; hs << "use QtDBus4;" << endl; hs << "use QtCore4::isa qw( Qt::DBusAbstractInterface )" << ";" << endl << endl; // the interface name cs << "sub staticInterfaceName" << endl << "{" << endl << " return \'" << interface->name << "\';" << endl << "}" << endl << endl; // constructors/destructors: cs << "sub NEW" << endl << "{" << endl << " my ($class, $service, $path, $connection, $parent) = @_;" << endl << " $class->SUPER::NEW($service, $path, staticInterfaceName(), $connection, $parent);" << endl << "}" << endl << endl; // properties: foreach (const QDBusIntrospection::Property &property, interface->properties) { QByteArray type = qtTypeName(property.type, property.annotations); QString templateType = templateArg(type); QString constRefType = constRefArg(type); QString getter = propertyGetter(property); QString setter = propertySetter(property); hs << " Q_PROPERTY(" << type << " " << property.name; // getter: if (property.access != QDBusIntrospection::Property::Write) // it's readble hs << " READ " << getter; // setter if (property.access != QDBusIntrospection::Property::Read) // it's writeable hs << " WRITE " << setter; hs << ")" << endl; // getter: if (property.access != QDBusIntrospection::Property::Write) { hs << " inline " << type << " " << getter << "() const" << endl << " { return qvariant_cast< " << type << " >(property(\"" << property.name << "\")); }" << endl; } // setter: if (property.access != QDBusIntrospection::Property::Read) { hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl << " { setProperty(\"" << property.name << "\", qVariantFromValue(value)); }" << endl; } hs << endl; } // methods: if ( interface->methods.size() > 0 ) { hs << "use QtCore4::slots # METHODS" << endl; foreach (const QDBusIntrospection::Method &method, interface->methods) { bool isDeprecated = method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true"); bool isNoReply = method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); if (isNoReply && !method.outputArgs.isEmpty()) { fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", qPrintable(method.name), qPrintable(interface->name)); continue; } hs << " '"; if (!isNoReply) { hs << "QDBusPendingReply<"; for (int i = 0; i < method.outputArgs.count(); ++i) hs << (i > 0 ? ", " : "") << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")); hs << "> "; } hs << method.name << "' => ["; cs << "sub " << method.name << endl << "{" << endl; QStringList argNames = makeArgNames(method.inputArgs); if ( argNames.size() > 0 ) cs << " my ("; writeArgTypesList(hs, argNames, method.annotations, method.inputArgs); writeArgList(cs, argNames, method.annotations, method.inputArgs); hs << "]," << endl; if ( argNames.size() > 0 ) cs << ") = @_;" << endl; cs << " my $argumentList = [];" << endl; if (!method.inputArgs.isEmpty()) { cs << " push @{$argumentList}"; for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos) cs << ", Qt::qVariantFromValue($" << argNames.at(argPos) << ')'; cs << ";" << endl; } if (isNoReply) cs << " callWithArgumentList(Qt::DBus::NoBlock(), " << "'" << method.name << "', $argumentList);" << endl; else cs << " return asyncCallWithArgumentList('" << method.name << "', $argumentList);" << endl; // close the function: cs << "}" << endl; if (method.outputArgs.count() > 1) { // generate the old-form QDBusReply methods with multiple incoming parameters hs << " inline " << (isDeprecated ? "Q_DECL_DEPRECATED " : "") << "QDBusReply<" << templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out")) << "> "; hs << method.name << "("; QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); hs << ")" << endl << " {" << endl << " QList argumentList;" << endl; int argPos = 0; if (!method.inputArgs.isEmpty()) { hs << " argumentList"; for (argPos = 0; argPos < method.inputArgs.count(); ++argPos) hs << " << qVariantFromValue(" << argNames.at(argPos) << ')'; hs << ";" << endl; } hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, " << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl; argPos++; hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == " << method.outputArgs.count() << ") {" << endl; // yes, starting from 1 for (int i = 1; i < method.outputArgs.count(); ++i) hs << " " << argNames.at(argPos++) << " = qdbus_cast<" << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")) << ">(reply.arguments().at(" << i << "));" << endl; hs << " }" << endl << " return reply;" << endl << " }" << endl; } } hs << " ;" << endl << endl; } if ( interface->signals_.size() > 0 ) { hs << "use QtCore4::signals # SIGNALS" << endl; foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { hs << " "; if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true")) hs << "Q_DECL_DEPRECATED "; hs << signal.name << "("; QStringList argNames = makeArgNames(signal.outputArgs); writeArgList(hs, argNames, signal.annotations, signal.outputArgs); hs << ");" << endl; // finished for header } hs << " ;" << endl << endl; } // close the class: cs << "1;" << endl << endl; } QString mocName = moc(filename); if (includeMocs && !mocName.isEmpty()) cs << endl << "#include \"" << mocName << "\"" << endl; cs.flush(); hs.flush(); QFile file; openFile(perlName, file); file.write(headerData); file.write(cppData); } static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) { QString headerName = pm(filename); QString cppName = pm(filename); QString perlName = pm(filename); QByteArray headerData; QTextStream hs(&headerData); QByteArray cppData; QTextStream cs(&cppData); // write the headers writeHeader(hs, false); QString parent = parentClassName; if (parentClassName.isEmpty()) parent = QLatin1String("Qt::Object"); foreach (const QDBusIntrospection::Interface *interface, interfaces) { QString className = classNameForInterface(interface->name, Adaptor); // comment: hs << "#" << endl << "# Adaptor class for interface " << interface->name << endl << "#" << endl; cs << "#" << endl << "# Implementation of adaptor class " << className << endl << "#" << endl << endl; // include our stuff: hs << "package " << className << ";" << endl; hs << "use strict;" << endl; hs << "use warnings;" << endl; hs << "use QtCore4;" << endl; hs << "use QtDBus4;" << endl; hs << "use QtCore4::isa qw( Qt::DBusAbstractAdaptor )" << ";" << endl << endl; // class header: hs << "use QtCore4::classinfo" << endl << " 'D-Bus Interface' => '" << interface->name << "'," << endl << " 'D-Bus Introspection' => '' ." << endl << stringify(interface->introspection) << " '';" << endl << endl; foreach (QString include, includes) { hs << "use " << include << ";\n" << endl; } // constructor/destructor cs << "sub NEW" << endl << "{" << endl << " # constructor" << endl << " my ( $class, $parent, $data ) = @_;" << endl << " $class->SUPER::NEW($parent);" << endl << " if ( defined $data ) {" << endl << " this->{data} = $data;" << endl << " } else {" << endl << " this->{data} = $parent;" << endl << " }" << endl << " this->setAutoRelaySignals(1);" << endl << "}" << endl << endl; /* PerlQt4 does not currently support QProperties foreach (const QDBusIntrospection::Property &property, interface->properties) { QByteArray type = qtTypeName(property.type, property.annotations); QString constRefType = constRefArg(type); QString getter = propertyGetter(property); QString setter = propertySetter(property); hs << " Q_PROPERTY(" << type << " " << property.name; if (property.access != QDBusIntrospection::Property::Write) hs << " READ " << getter; if (property.access != QDBusIntrospection::Property::Read) hs << " WRITE " << setter; hs << ")" << endl; // getter: if (property.access != QDBusIntrospection::Property::Write) { hs << " " << type << " " << getter << "() const;" << endl; cs << type << " " << className << "::" << getter << "() const" << endl << "{" << endl << " // get the value of property " << property.name << endl << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << endl << "}" << endl << endl; } // setter if (property.access != QDBusIntrospection::Property::Read) { hs << " void " << setter << "(" << constRefType << "value);" << endl; cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << endl << "{" << endl << " // set the value of property " << property.name << endl << " parent()->setProperty(\"" << property.name << "\", qVariantFromValue(value"; if (constRefType.contains(QLatin1String("QDBusVariant"))) cs << ".variant()"; cs << "));" << endl << "}" << endl << endl; } hs << endl; } */ if ( interface->methods.size() > 0 ) { hs << "use QtCore4::slots # METHODS" << endl << " public => 1," << endl; foreach (const QDBusIntrospection::Method &method, interface->methods) { bool isNoReply = method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); if (isNoReply && !method.outputArgs.isEmpty()) { fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", qPrintable(method.name), qPrintable(interface->name)); continue; } hs << " '"; //if (method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == //QLatin1String("true")) //hs << "Q_DECL_DEPRECATED "; QByteArray returnType; cs << "sub "; if (!isNoReply && !method.outputArgs.isEmpty()) { returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out"); hs << returnType << " "; } QString name = method.name; hs << name << "' => ["; cs << name << endl << "{" << endl; QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); if ( argNames.size() > 0 ) cs << " my ("; writeArgTypesList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs); hs << "]," << endl; if ( argNames.size() > 0 ) cs << ") = @_;" << endl; cs << " # handle method call " << interface->name << "." << method.name << endl; // make the call bool usingInvokeMethod = false; if (parentClassName.isEmpty() && method.inputArgs.count() <= 10 && method.outputArgs.count() <= 1) usingInvokeMethod = true; if ( 0 ) { /* Can't use invokeMethod() since we can't create QGenericArguments if (usingInvokeMethod) { // we are using QMetaObject::invokeMethod if (!returnType.isEmpty()) cs << " " << returnType << " " << argNames.at(method.inputArgs.count()) << ";" << endl; static const char invoke[] = " Qt::MetaObject::invokeMethod(this->parent(), '"; cs << invoke << name << "'"; if (!method.outputArgs.isEmpty()) cs << ", Q_RETURN_ARG(" << qtTypeName(method.outputArgs.at(0).type, method.annotations, 0, "Out") << ", " << argNames.at(method.inputArgs.count()) << ")"; for (int i = 0; i < method.inputArgs.count(); ++i) cs << ", " << "$" << argNames.at(i); cs << ");" << endl; if (!returnType.isEmpty()) cs << " return $" << argNames.at(method.inputArgs.count()) << ";" << endl; } */ } else { //if (parentClassName.isEmpty()) //cs << " //"; //else cs << " "; if (!method.outputArgs.isEmpty()) cs << "return "; cs << "this->{data}->"; cs << name << "("; int argPos = 0; bool first = true; for (int i = 0; i < method.inputArgs.count(); ++i) { cs << (first ? "" : ", ") << "$" << argNames.at(argPos++); first = false; } ++argPos; // skip retval, if any for (int i = 1; i < method.outputArgs.count(); ++i) { cs << (first ? "" : ", ") << argNames.at(argPos++); first = false; } cs << ");" << endl; } cs << "}" << endl << endl; } hs << " ;" << endl; } if ( interface->signals_.size() > 0 ) { hs << "use QtCore4::signals # SIGNALS" << endl << " public => 1," << endl; foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { hs << " '"; //if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == //QLatin1String("true")) //hs << "Q_DECL_DEPRECATED "; hs << signal.name << "' => ["; QStringList argNames = makeArgNames(signal.outputArgs); writeArgTypesList(hs, argNames, signal.annotations, signal.outputArgs); hs << "]," << endl; } hs << " ;" << endl; } hs << endl; } cs << "1;" << endl; cs.flush(); hs.flush(); QFile file; openFile(perlName, file); file.write(headerData); file.write(cppData); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); parseCmdLine(app.arguments()); QDBusIntrospection::Interfaces interfaces = readInput(); cleanInterfaces(interfaces); if (!proxyFile.isEmpty() || adaptorFile.isEmpty()) writeProxy(proxyFile, interfaces); if (!adaptorFile.isEmpty()) writeAdaptor(adaptorFile, interfaces); return 0; } /*! \page qdbusxml2cpp.html \title QtDBus XML compiler (qdbusxml2cpp) \keyword qdbusxml2cpp The QtDBus XML compiler is a tool that can be used to parse interface descriptions and produce static code representing those interfaces, which can then be used to make calls to remote objects or implement said interfaces. \c qdbusxml2dcpp has two modes of operation, that correspond to the two possible outputs it can produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++ header and a source file, which are meant to be edited and adapted to your needs. The \c qdbusxml2dcpp tool is not meant to be run every time you compile your application. Instead, it's meant to be used when developing the code or when the interface changes. The adaptor classes generated by \c qdbusxml2cpp are just a skeleton that must be completed. It generates, by default, calls to slots with the same name on the object the adaptor is attached to. However, you may modify those slots or the property accessor functions to suit your needs. */