tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtCore/qbytearray.h>
       
    43 #include <QtCore/qcoreapplication.h>
       
    44 #include <QtCore/qdatetime.h>
       
    45 #include <QtCore/qdebug.h>
       
    46 #include <QtCore/qfile.h>
       
    47 #include <QtCore/qstring.h>
       
    48 #include <QtCore/qstringlist.h>
       
    49 #include <QtCore/qtextstream.h>
       
    50 #include <QtCore/qset.h>
       
    51 
       
    52 #include <QtDBus/QtDBus>
       
    53 #include "private/qdbusmetaobject_p.h"
       
    54 #include "private/qdbusintrospection_p.h"
       
    55 
       
    56 #include <sys/types.h>
       
    57 #include <stdio.h>
       
    58 #include <stdlib.h>
       
    59 
       
    60 #ifdef Q_WS_WIN
       
    61 #include <process.h>
       
    62 #endif
       
    63 
       
    64 #define PROGRAMNAME     "qdbusxml2cpp"
       
    65 #define PROGRAMVERSION  "0.7"
       
    66 #define PROGRAMCOPYRIGHT "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)."
       
    67 
       
    68 #define ANNOTATION_NO_WAIT      "org.freedesktop.DBus.Method.NoReply"
       
    69 
       
    70 static QString globalClassName;
       
    71 static QString parentClassName;
       
    72 static QString proxyFile;
       
    73 static QString adaptorFile;
       
    74 static QString inputFile;
       
    75 static bool skipNamespaces;
       
    76 static bool verbose;
       
    77 static bool includeMocs;
       
    78 static QString commandLine;
       
    79 static QStringList includes;
       
    80 static QStringList wantedInterfaces;
       
    81 
       
    82 static const char help[] =
       
    83     "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n"
       
    84     "Produces the C++ code to implement the interfaces defined in the input file.\n"
       
    85     "\n"
       
    86     "Options:\n"
       
    87     "  -a <filename>    Write the adaptor code to <filename>\n"
       
    88     "  -c <classname>   Use <classname> as the class name for the generated classes\n"
       
    89     "  -h               Show this information\n"
       
    90     "  -i <filename>    Add #include to the output\n"
       
    91     "  -l <classname>   When generating an adaptor, use <classname> as the parent class\n"
       
    92     "  -m               Generate #include \"filename.moc\" statements in the .cpp files\n"
       
    93     "  -N               Don't use namespaces\n"
       
    94     "  -p <filename>    Write the proxy code to <filename>\n"
       
    95     "  -v               Be verbose.\n"
       
    96     "  -V               Show the program version and quit.\n"
       
    97     "\n"
       
    98     "If the file name given to the options -a and -p does not end in .cpp or .h, the\n"
       
    99     "program will automatically append the suffixes and produce both files.\n"
       
   100     "You can also use a colon (:) to separate the header name from the source file\n"
       
   101     "name, as in '-a filename_p.h:filename.cpp'.\n"
       
   102     "\n"
       
   103     "If you pass a dash (-) as the argument to either -p or -a, the output is written\n"
       
   104     "to the standard output\n";
       
   105 
       
   106 static const char includeList[] =
       
   107     "#include <QtCore/QByteArray>\n"
       
   108     "#include <QtCore/QList>\n"
       
   109     "#include <QtCore/QMap>\n"
       
   110     "#include <QtCore/QString>\n"
       
   111     "#include <QtCore/QStringList>\n"
       
   112     "#include <QtCore/QVariant>\n";
       
   113 
       
   114 static const char forwardDeclarations[] =
       
   115     "class QByteArray;\n"
       
   116     "template<class T> class QList;\n"
       
   117     "template<class Key, class Value> class QMap;\n"
       
   118     "class QString;\n"
       
   119     "class QStringList;\n"
       
   120     "class QVariant;\n";
       
   121 
       
   122 static void showHelp()
       
   123 {
       
   124     printf("%s", help);
       
   125     exit(0);
       
   126 }
       
   127 
       
   128 static void showVersion()
       
   129 {
       
   130     printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION);
       
   131     printf("D-Bus binding tool for Qt\n");
       
   132     exit(0);
       
   133 }
       
   134 
       
   135 static QString nextArg(QStringList &args, int i, char opt)
       
   136 {
       
   137     QString arg = args.value(i);
       
   138     if (arg.isEmpty()) {
       
   139         printf("-%c needs at least one argument\n", opt);
       
   140         exit(1);
       
   141     }
       
   142     return args.takeAt(i);
       
   143 }
       
   144 
       
   145 static void parseCmdLine(QStringList args)
       
   146 {
       
   147     args.takeFirst();
       
   148 
       
   149     commandLine = QLatin1String(PROGRAMNAME " ");
       
   150     commandLine += args.join(QLatin1String(" "));
       
   151 
       
   152     int i = 0;
       
   153     while (i < args.count()) {
       
   154 
       
   155         if (!args.at(i).startsWith(QLatin1Char('-'))) {
       
   156             ++i;
       
   157             continue;
       
   158         }
       
   159         QString arg = args.takeAt(i);
       
   160 
       
   161         char c = '\0';
       
   162         if (arg.length() == 2)
       
   163             c = arg.at(1).toLatin1();
       
   164         else if (arg == QLatin1String("--help"))
       
   165             c = 'h';
       
   166 
       
   167         switch (c) {
       
   168         case 'a':
       
   169             adaptorFile = nextArg(args, i, 'a');
       
   170             break;
       
   171 
       
   172         case 'c':
       
   173             globalClassName = nextArg(args, i, 'c');
       
   174             break;
       
   175 
       
   176         case 'v':
       
   177             verbose = true;
       
   178             break;
       
   179 
       
   180         case 'i':
       
   181             includes << nextArg(args, i, 'i');
       
   182             break;
       
   183 
       
   184         case 'l':
       
   185             parentClassName = nextArg(args, i, 'l');
       
   186             break;
       
   187 
       
   188         case 'm':
       
   189             includeMocs = true;
       
   190             break;
       
   191 
       
   192         case 'N':
       
   193             skipNamespaces = true;
       
   194             break;
       
   195 
       
   196         case '?':
       
   197         case 'h':
       
   198             showHelp();
       
   199             break;
       
   200 
       
   201         case 'V':
       
   202             showVersion();
       
   203             break;
       
   204 
       
   205         case 'p':
       
   206             proxyFile = nextArg(args, i, 'p');
       
   207             break;
       
   208 
       
   209         default:
       
   210             printf("unknown option: '%s'\n", qPrintable(arg));
       
   211             exit(1);
       
   212         }
       
   213     }
       
   214 
       
   215     if (!args.isEmpty())
       
   216         inputFile = args.takeFirst();
       
   217 
       
   218     wantedInterfaces << args;
       
   219 }
       
   220 
       
   221 static QDBusIntrospection::Interfaces readInput()
       
   222 {
       
   223     QFile input(inputFile);
       
   224     if (inputFile.isEmpty() || inputFile == QLatin1String("-"))
       
   225         input.open(stdin, QIODevice::ReadOnly);
       
   226     else
       
   227         input.open(QIODevice::ReadOnly);
       
   228 
       
   229     QByteArray data = input.readAll();
       
   230 
       
   231     // check if the input is already XML
       
   232     data = data.trimmed();
       
   233     if (data.startsWith("<!DOCTYPE ") || data.startsWith("<?xml") ||
       
   234         data.startsWith("<node") || data.startsWith("<interface"))
       
   235         // already XML
       
   236         return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data));
       
   237 
       
   238     fprintf(stderr, "Cannot process input: '%s'. Stop.\n", qPrintable(inputFile));
       
   239     exit(1);
       
   240 }
       
   241 
       
   242 static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces)
       
   243 {
       
   244     if (!wantedInterfaces.isEmpty()) {
       
   245         QDBusIntrospection::Interfaces::Iterator it = interfaces.begin();
       
   246         while (it != interfaces.end())
       
   247             if (!wantedInterfaces.contains(it.key()))
       
   248                 it = interfaces.erase(it);
       
   249             else
       
   250                 ++it;
       
   251     }
       
   252 }
       
   253 
       
   254 // produce a header name from the file name
       
   255 static QString header(const QString &name)
       
   256 {
       
   257     QStringList parts = name.split(QLatin1Char(':'));
       
   258     QString retval = parts.first();
       
   259 
       
   260     if (retval.isEmpty() || retval == QLatin1String("-"))
       
   261         return retval;
       
   262 
       
   263     if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) &&
       
   264         !retval.endsWith(QLatin1String(".cc")))
       
   265         retval.append(QLatin1String(".h"));
       
   266 
       
   267     return retval;
       
   268 }
       
   269 
       
   270 // produce a cpp name from the file name
       
   271 static QString cpp(const QString &name)
       
   272 {
       
   273     QStringList parts = name.split(QLatin1Char(':'));
       
   274     QString retval = parts.last();
       
   275 
       
   276     if (retval.isEmpty() || retval == QLatin1String("-"))
       
   277         return retval;
       
   278 
       
   279     if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) &&
       
   280         !retval.endsWith(QLatin1String(".cc")))
       
   281         retval.append(QLatin1String(".cpp"));
       
   282 
       
   283     return retval;
       
   284 }
       
   285 
       
   286 // produce a moc name from the file name
       
   287 static QString moc(const QString &name)
       
   288 {
       
   289     QString retval = header(name);
       
   290     if (retval.isEmpty())
       
   291         return retval;
       
   292 
       
   293     retval.truncate(retval.length() - 1); // drop the h in .h
       
   294     retval += QLatin1String("moc");
       
   295     return retval;
       
   296 }
       
   297 
       
   298 static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost)
       
   299 {
       
   300     ts << "/*" << endl
       
   301        << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << endl
       
   302        << " * Command line was: " << commandLine << endl
       
   303        << " *" << endl
       
   304        << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << endl
       
   305        << " *" << endl
       
   306        << " * This is an auto-generated file." << endl;
       
   307 
       
   308     if (changesWillBeLost)
       
   309         ts << " * Do not edit! All changes made to it will be lost." << endl;
       
   310     else
       
   311         ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << endl
       
   312            << " * before re-generating it." << endl;
       
   313 
       
   314     ts << " */" << endl
       
   315        << endl;
       
   316 
       
   317     return ts;
       
   318 }
       
   319 
       
   320 enum ClassType { Proxy, Adaptor };
       
   321 static QString classNameForInterface(const QString &interface, ClassType classType)
       
   322 {
       
   323     if (!globalClassName.isEmpty())
       
   324         return globalClassName;
       
   325 
       
   326     QStringList parts = interface.split(QLatin1Char('.'));
       
   327 
       
   328     QString retval;
       
   329     if (classType == Proxy)
       
   330         foreach (QString part, parts) {
       
   331             part[0] = part[0].toUpper();
       
   332             retval += part;
       
   333         }
       
   334     else {
       
   335         retval = parts.last();
       
   336         retval[0] = retval[0].toUpper();
       
   337     }
       
   338 
       
   339     if (classType == Proxy)
       
   340         retval += QLatin1String("Interface");
       
   341     else
       
   342         retval += QLatin1String("Adaptor");
       
   343 
       
   344     return retval;
       
   345 }
       
   346 
       
   347 static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection::Annotations &annotations, int paramId = -1, const char *direction = "Out")
       
   348 {
       
   349     int type = QDBusMetaType::signatureToType(signature.toLatin1());
       
   350     if (type == QVariant::Invalid) {
       
   351         QString annotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
       
   352         if (paramId >= 0)
       
   353             annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId);
       
   354         QString qttype = annotations.value(annotationName);
       
   355         if (!qttype.isEmpty())
       
   356             return qttype.toLatin1();
       
   357 
       
   358         fprintf(stderr, "Got unknown type `%s'\n", qPrintable(signature));
       
   359         fprintf(stderr, "You should add <annotation name=\"%s\" value=\"<type>\"/> to the XML description\n",
       
   360                 qPrintable(annotationName));
       
   361         exit(1);
       
   362     }
       
   363 
       
   364     return QVariant::typeToName(QVariant::Type(type));
       
   365 }
       
   366 
       
   367 static QString nonConstRefArg(const QByteArray &arg)
       
   368 {
       
   369     return QLatin1String(arg + " &");
       
   370 }
       
   371 
       
   372 static QString templateArg(const QByteArray &arg)
       
   373 {
       
   374     if (!arg.endsWith('>'))
       
   375         return QLatin1String(arg);
       
   376 
       
   377     return QLatin1String(arg + ' ');
       
   378 }
       
   379 
       
   380 static QString constRefArg(const QByteArray &arg)
       
   381 {
       
   382     if (!arg.startsWith('Q'))
       
   383         return QLatin1String(arg + ' ');
       
   384     else
       
   385         return QString( QLatin1String("const %1 &") ).arg( QLatin1String(arg) );
       
   386 }
       
   387 
       
   388 static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs,
       
   389                                 const QDBusIntrospection::Arguments &outputArgs =
       
   390                                 QDBusIntrospection::Arguments())
       
   391 {
       
   392     QStringList retval;
       
   393     for (int i = 0; i < inputArgs.count(); ++i) {
       
   394         const QDBusIntrospection::Argument &arg = inputArgs.at(i);
       
   395         QString name = arg.name;
       
   396         if (name.isEmpty())
       
   397             name = QString( QLatin1String("in%1") ).arg(i);
       
   398         while (retval.contains(name))
       
   399             name += QLatin1String("_");
       
   400         retval << name;
       
   401     }
       
   402     for (int i = 0; i < outputArgs.count(); ++i) {
       
   403         const QDBusIntrospection::Argument &arg = outputArgs.at(i);
       
   404         QString name = arg.name;
       
   405         if (name.isEmpty())
       
   406             name = QString( QLatin1String("out%1") ).arg(i);
       
   407         while (retval.contains(name))
       
   408             name += QLatin1String("_");
       
   409         retval << name;
       
   410     }
       
   411     return retval;
       
   412 }
       
   413 
       
   414 static void writeArgList(QTextStream &ts, const QStringList &argNames,
       
   415                          const QDBusIntrospection::Annotations &annotations,
       
   416                          const QDBusIntrospection::Arguments &inputArgs,
       
   417                          const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments())
       
   418 {
       
   419     // input args:
       
   420     bool first = true;
       
   421     int argPos = 0;
       
   422     for (int i = 0; i < inputArgs.count(); ++i) {
       
   423         const QDBusIntrospection::Argument &arg = inputArgs.at(i);
       
   424         QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In"));
       
   425 
       
   426         if (!first)
       
   427             ts << ", ";
       
   428         ts << type << argNames.at(argPos++);
       
   429         first = false;
       
   430     }
       
   431 
       
   432     argPos++;
       
   433 
       
   434     // output args
       
   435     // yes, starting from 1
       
   436     for (int i = 1; i < outputArgs.count(); ++i) {
       
   437         const QDBusIntrospection::Argument &arg = outputArgs.at(i);
       
   438         QString name = arg.name;
       
   439 
       
   440         if (!first)
       
   441             ts << ", ";
       
   442         ts << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out"))
       
   443            << argNames.at(argPos++);
       
   444         first = false;
       
   445     }
       
   446 }
       
   447 
       
   448 static QString propertyGetter(const QDBusIntrospection::Property &property)
       
   449 {
       
   450     QString getter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertyGetter"));
       
   451     if (getter.isEmpty()) {
       
   452         getter =  property.name;
       
   453         getter[0] = getter[0].toLower();
       
   454     }
       
   455     return getter;
       
   456 }
       
   457 
       
   458 static QString propertySetter(const QDBusIntrospection::Property &property)
       
   459 {
       
   460     QString setter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertySetter"));
       
   461     if (setter.isEmpty()) {
       
   462         setter = QLatin1String("set") + property.name;
       
   463         setter[3] = setter[3].toUpper();
       
   464     }
       
   465     return setter;
       
   466 }
       
   467 
       
   468 static QString stringify(const QString &data)
       
   469 {
       
   470     QString retval;
       
   471     int i;
       
   472     for (i = 0; i < data.length(); ++i) {
       
   473         retval += QLatin1Char('\"');
       
   474         for ( ; i < data.length() && data[i] != QLatin1Char('\n'); ++i)
       
   475             if (data[i] == QLatin1Char('\"'))
       
   476                 retval += QLatin1String("\\\"");
       
   477             else
       
   478                 retval += data[i];
       
   479         retval += QLatin1String("\\n\"\n");
       
   480     }
       
   481     return retval;
       
   482 }
       
   483 
       
   484 static void openFile(const QString &fileName, QFile &file)
       
   485 {
       
   486     if (fileName.isEmpty())
       
   487         return;
       
   488 
       
   489     bool isOk = false;
       
   490     if (fileName == QLatin1String("-")) {
       
   491         isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
       
   492     } else {
       
   493         file.setFileName(fileName);
       
   494         isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
       
   495     }
       
   496 
       
   497     if (!isOk)
       
   498         fprintf(stderr, "Unable to open '%s': %s\n", qPrintable(fileName),
       
   499                 qPrintable(file.errorString()));
       
   500 }
       
   501 
       
   502 static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
       
   503 {
       
   504     // open the file
       
   505     QString headerName = header(filename);
       
   506     QByteArray headerData;
       
   507     QTextStream hs(&headerData);
       
   508 
       
   509     QString cppName = cpp(filename);
       
   510     QByteArray cppData;
       
   511     QTextStream cs(&cppData);
       
   512 
       
   513     // write the header:
       
   514     writeHeader(hs, true);
       
   515     if (cppName != headerName)
       
   516         writeHeader(cs, false);
       
   517 
       
   518     // include guards:
       
   519     QString includeGuard;
       
   520     if (!headerName.isEmpty() && headerName != QLatin1String("-")) {
       
   521         includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_'));
       
   522         int pos = includeGuard.lastIndexOf(QLatin1Char('/'));
       
   523         if (pos != -1)
       
   524             includeGuard = includeGuard.mid(pos + 1);
       
   525     } else {
       
   526         includeGuard = QLatin1String("QDBUSXML2CPP_PROXY");
       
   527     }
       
   528     includeGuard = QString(QLatin1String("%1_%2"))
       
   529                    .arg(includeGuard)
       
   530                    .arg(QDateTime::currentDateTime().toTime_t());
       
   531     hs << "#ifndef " << includeGuard << endl
       
   532        << "#define " << includeGuard << endl
       
   533        << endl;
       
   534 
       
   535     // include our stuff:
       
   536     hs << "#include <QtCore/QObject>" << endl
       
   537        << includeList
       
   538        << "#include <QtDBus/QtDBus>" << endl;
       
   539 
       
   540     foreach (QString include, includes) {
       
   541         hs << "#include \"" << include << "\"" << endl;
       
   542         if (headerName.isEmpty())
       
   543             cs << "#include \"" << include << "\"" << endl;
       
   544     }
       
   545 
       
   546     hs << endl;
       
   547 
       
   548     if (cppName != headerName) {
       
   549         if (!headerName.isEmpty() && headerName != QLatin1String("-"))
       
   550             cs << "#include \"" << headerName << "\"" << endl << endl;
       
   551     }
       
   552 
       
   553     foreach (const QDBusIntrospection::Interface *interface, interfaces) {
       
   554         QString className = classNameForInterface(interface->name, Proxy);
       
   555 
       
   556         // comment:
       
   557         hs << "/*" << endl
       
   558            << " * Proxy class for interface " << interface->name << endl
       
   559            << " */" << endl;
       
   560         cs << "/*" << endl
       
   561            << " * Implementation of interface class " << className << endl
       
   562            << " */" << endl
       
   563            << endl;
       
   564 
       
   565         // class header:
       
   566         hs << "class " << className << ": public QDBusAbstractInterface" << endl
       
   567            << "{" << endl
       
   568            << "    Q_OBJECT" << endl;
       
   569 
       
   570         // the interface name
       
   571         hs << "public:" << endl
       
   572            << "    static inline const char *staticInterfaceName()" << endl
       
   573            << "    { return \"" << interface->name << "\"; }" << endl
       
   574            << endl;
       
   575 
       
   576         // constructors/destructors:
       
   577         hs << "public:" << endl
       
   578            << "    " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);" << endl
       
   579            << endl
       
   580            << "    ~" << className << "();" << endl
       
   581            << endl;
       
   582         cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << endl
       
   583            << "    : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << endl
       
   584            << "{" << endl
       
   585            << "}" << endl
       
   586            << endl
       
   587            << className << "::~" << className << "()" << endl
       
   588            << "{" << endl
       
   589            << "}" << endl
       
   590            << endl;
       
   591 
       
   592         // properties:
       
   593         foreach (const QDBusIntrospection::Property &property, interface->properties) {
       
   594             QByteArray type = qtTypeName(property.type, property.annotations);
       
   595             QString templateType = templateArg(type);
       
   596             QString constRefType = constRefArg(type);
       
   597             QString getter = propertyGetter(property);
       
   598             QString setter = propertySetter(property);
       
   599 
       
   600             hs << "    Q_PROPERTY(" << type << " " << property.name;
       
   601 
       
   602             // getter:
       
   603             if (property.access != QDBusIntrospection::Property::Write)
       
   604                 // it's readble
       
   605                 hs << " READ " << getter;
       
   606 
       
   607             // setter
       
   608             if (property.access != QDBusIntrospection::Property::Read)
       
   609                 // it's writeable
       
   610                 hs << " WRITE " << setter;
       
   611 
       
   612             hs << ")" << endl;
       
   613 
       
   614             // getter:
       
   615             if (property.access != QDBusIntrospection::Property::Write) {
       
   616                 hs << "    inline " << type << " " << getter << "() const" << endl
       
   617                     << "    { return qvariant_cast< " << type << " >(property(\""
       
   618                     << property.name << "\")); }" << endl;
       
   619             }
       
   620 
       
   621             // setter:
       
   622             if (property.access != QDBusIntrospection::Property::Read) {
       
   623                 hs << "    inline void " << setter << "(" << constRefArg(type) << "value)" << endl
       
   624                    << "    { setProperty(\"" << property.name
       
   625                    << "\", qVariantFromValue(value)); }" << endl;
       
   626             }
       
   627 
       
   628             hs << endl;
       
   629         }
       
   630 
       
   631         // methods:
       
   632         hs << "public Q_SLOTS: // METHODS" << endl;
       
   633         foreach (const QDBusIntrospection::Method &method, interface->methods) {
       
   634             bool isDeprecated = method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true");
       
   635             bool isNoReply =
       
   636                 method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true");
       
   637             if (isNoReply && !method.outputArgs.isEmpty()) {
       
   638                 fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n",
       
   639                         qPrintable(method.name), qPrintable(interface->name));
       
   640                 continue;
       
   641             }
       
   642 
       
   643             hs << "    inline "
       
   644                << (isDeprecated ? "Q_DECL_DEPRECATED " : "");
       
   645 
       
   646             if (isNoReply) {
       
   647                 hs << "Q_NOREPLY void ";
       
   648             } else {
       
   649                 hs << "QDBusPendingReply<";
       
   650                 for (int i = 0; i < method.outputArgs.count(); ++i)
       
   651                     hs << (i > 0 ? ", " : "")
       
   652                        << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out"));
       
   653                 hs << "> ";
       
   654             }
       
   655 
       
   656             hs << method.name << "(";
       
   657 
       
   658             QStringList argNames = makeArgNames(method.inputArgs);
       
   659             writeArgList(hs, argNames, method.annotations, method.inputArgs);
       
   660 
       
   661             hs << ")" << endl
       
   662                << "    {" << endl
       
   663                << "        QList<QVariant> argumentList;" << endl;
       
   664 
       
   665             if (!method.inputArgs.isEmpty()) {
       
   666                 hs << "        argumentList";
       
   667                 for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos)
       
   668                     hs << " << qVariantFromValue(" << argNames.at(argPos) << ')';
       
   669                 hs << ";" << endl;
       
   670             }
       
   671 
       
   672             if (isNoReply)
       
   673                 hs << "        callWithArgumentList(QDBus::NoBlock, "
       
   674                    <<  "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
       
   675             else
       
   676                 hs << "        return asyncCallWithArgumentList(QLatin1String(\""
       
   677                    << method.name << "\"), argumentList);" << endl;
       
   678 
       
   679             // close the function:
       
   680             hs << "    }" << endl;
       
   681 
       
   682             if (method.outputArgs.count() > 1) {
       
   683                 // generate the old-form QDBusReply methods with multiple incoming parameters
       
   684                 hs << "    inline "
       
   685                    << (isDeprecated ? "Q_DECL_DEPRECATED " : "")
       
   686                    << "QDBusReply<"
       
   687                    << templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out")) << "> ";
       
   688                 hs << method.name << "(";
       
   689 
       
   690                 QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
       
   691                 writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
       
   692 
       
   693                 hs << ")" << endl
       
   694                    << "    {" << endl
       
   695                    << "        QList<QVariant> argumentList;" << endl;
       
   696 
       
   697                 int argPos = 0;
       
   698                 if (!method.inputArgs.isEmpty()) {
       
   699                     hs << "        argumentList";
       
   700                     for (argPos = 0; argPos < method.inputArgs.count(); ++argPos)
       
   701                         hs << " << qVariantFromValue(" << argNames.at(argPos) << ')';
       
   702                     hs << ";" << endl;
       
   703                 }
       
   704 
       
   705                 hs << "        QDBusMessage reply = callWithArgumentList(QDBus::Block, "
       
   706                    <<  "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
       
   707 
       
   708                 argPos++;
       
   709                 hs << "        if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == "
       
   710                    << method.outputArgs.count() << ") {" << endl;
       
   711 
       
   712                 // yes, starting from 1
       
   713                 for (int i = 1; i < method.outputArgs.count(); ++i)
       
   714                     hs << "            " << argNames.at(argPos++) << " = qdbus_cast<"
       
   715                        << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out"))
       
   716                        << ">(reply.arguments().at(" << i << "));" << endl;
       
   717                 hs << "        }" << endl
       
   718                    << "        return reply;" << endl
       
   719                    << "    }" << endl;
       
   720             }
       
   721 
       
   722             hs << endl;
       
   723         }
       
   724 
       
   725         hs << "Q_SIGNALS: // SIGNALS" << endl;
       
   726         foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
       
   727             hs << "    ";
       
   728             if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
       
   729                 QLatin1String("true"))
       
   730                 hs << "Q_DECL_DEPRECATED ";
       
   731 
       
   732             hs << "void " << signal.name << "(";
       
   733 
       
   734             QStringList argNames = makeArgNames(signal.outputArgs);
       
   735             writeArgList(hs, argNames, signal.annotations, signal.outputArgs);
       
   736 
       
   737             hs << ");" << endl; // finished for header
       
   738         }
       
   739 
       
   740         // close the class:
       
   741         hs << "};" << endl
       
   742            << endl;
       
   743     }
       
   744 
       
   745     if (!skipNamespaces) {
       
   746         QStringList last;
       
   747         QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin();
       
   748         do
       
   749         {
       
   750             QStringList current;
       
   751             QString name;
       
   752             if (it != interfaces.constEnd()) {
       
   753                 current = it->constData()->name.split(QLatin1Char('.'));
       
   754                 name = current.takeLast();
       
   755             }
       
   756 
       
   757             int i = 0;
       
   758             while (i < current.count() && i < last.count() && current.at(i) == last.at(i))
       
   759                 ++i;
       
   760 
       
   761             // i parts matched
       
   762             // close last.arguments().count() - i namespaces:
       
   763             for (int j = i; j < last.count(); ++j)
       
   764                 hs << QString((last.count() - j - 1 + i) * 2, QLatin1Char(' ')) << "}" << endl;
       
   765 
       
   766             // open current.arguments().count() - i namespaces
       
   767             for (int j = i; j < current.count(); ++j)
       
   768                 hs << QString(j * 2, QLatin1Char(' ')) << "namespace " << current.at(j) << " {" << endl;
       
   769 
       
   770             // add this class:
       
   771             if (!name.isEmpty()) {
       
   772                 hs << QString(current.count() * 2, QLatin1Char(' '))
       
   773                    << "typedef ::" << classNameForInterface(it->constData()->name, Proxy)
       
   774                    << " " << name << ";" << endl;
       
   775             }
       
   776 
       
   777             if (it == interfaces.constEnd())
       
   778                 break;
       
   779             ++it;
       
   780             last = current;
       
   781         } while (true);
       
   782     }
       
   783 
       
   784     // close the include guard
       
   785     hs << "#endif" << endl;
       
   786 
       
   787     QString mocName = moc(filename);
       
   788     if (includeMocs && !mocName.isEmpty())
       
   789         cs << endl
       
   790            << "#include \"" << mocName << "\"" << endl;
       
   791 
       
   792     cs.flush();
       
   793     hs.flush();
       
   794 
       
   795     QFile file;
       
   796     openFile(headerName, file);
       
   797     file.write(headerData);
       
   798 
       
   799     if (headerName == cppName) {
       
   800         file.write(cppData);
       
   801     } else {
       
   802         QFile cppFile;
       
   803         openFile(cppName, cppFile);
       
   804         cppFile.write(cppData);
       
   805     }
       
   806 }
       
   807 
       
   808 static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
       
   809 {
       
   810     // open the file
       
   811     QString headerName = header(filename);
       
   812     QByteArray headerData;
       
   813     QTextStream hs(&headerData);
       
   814 
       
   815     QString cppName = cpp(filename);
       
   816     QByteArray cppData;
       
   817     QTextStream cs(&cppData);
       
   818 
       
   819     // write the headers
       
   820     writeHeader(hs, false);
       
   821     if (cppName != headerName)
       
   822         writeHeader(cs, true);
       
   823 
       
   824     // include guards:
       
   825     QString includeGuard;
       
   826     if (!headerName.isEmpty() && headerName != QLatin1String("-")) {
       
   827         includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_'));
       
   828         int pos = includeGuard.lastIndexOf(QLatin1Char('/'));
       
   829         if (pos != -1)
       
   830             includeGuard = includeGuard.mid(pos + 1);
       
   831     } else {
       
   832         includeGuard = QLatin1String("QDBUSXML2CPP_ADAPTOR");
       
   833     }
       
   834     includeGuard = QString(QLatin1String("%1_%2"))
       
   835                    .arg(includeGuard)
       
   836                    .arg(QDateTime::currentDateTime().toTime_t());
       
   837     hs << "#ifndef " << includeGuard << endl
       
   838        << "#define " << includeGuard << endl
       
   839        << endl;
       
   840 
       
   841     // include our stuff:
       
   842     hs << "#include <QtCore/QObject>" << endl;
       
   843     if (cppName == headerName)
       
   844         hs << "#include <QtCore/QMetaObject>" << endl
       
   845            << "#include <QtCore/QVariant>" << endl;
       
   846     hs << "#include <QtDBus/QtDBus>" << endl;
       
   847 
       
   848     foreach (QString include, includes) {
       
   849         hs << "#include \"" << include << "\"" << endl;
       
   850         if (headerName.isEmpty())
       
   851             cs << "#include \"" << include << "\"" << endl;
       
   852     }
       
   853 
       
   854     if (cppName != headerName) {
       
   855         if (!headerName.isEmpty() && headerName != QLatin1String("-"))
       
   856             cs << "#include \"" << headerName << "\"" << endl;
       
   857 
       
   858         cs << "#include <QtCore/QMetaObject>" << endl
       
   859            << includeList
       
   860            << endl;
       
   861         hs << forwardDeclarations;
       
   862     } else {
       
   863         hs << includeList;
       
   864     }
       
   865 
       
   866     hs << endl;
       
   867 
       
   868     QString parent = parentClassName;
       
   869     if (parentClassName.isEmpty())
       
   870         parent = QLatin1String("QObject");
       
   871 
       
   872     foreach (const QDBusIntrospection::Interface *interface, interfaces) {
       
   873         QString className = classNameForInterface(interface->name, Adaptor);
       
   874 
       
   875         // comment:
       
   876         hs << "/*" << endl
       
   877            << " * Adaptor class for interface " << interface->name << endl
       
   878            << " */" << endl;
       
   879         cs << "/*" << endl
       
   880            << " * Implementation of adaptor class " << className << endl
       
   881            << " */" << endl
       
   882            << endl;
       
   883 
       
   884         // class header:
       
   885         hs << "class " << className << ": public QDBusAbstractAdaptor" << endl
       
   886            << "{" << endl
       
   887            << "    Q_OBJECT" << endl
       
   888            << "    Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << endl
       
   889            << "    Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << endl
       
   890            << stringify(interface->introspection)
       
   891            << "        \"\")" << endl
       
   892            << "public:" << endl
       
   893            << "    " << className << "(" << parent << " *parent);" << endl
       
   894            << "    virtual ~" << className << "();" << endl
       
   895            << endl;
       
   896 
       
   897         if (!parentClassName.isEmpty())
       
   898             hs << "    inline " << parent << " *parent() const" << endl
       
   899                << "    { return static_cast<" << parent << " *>(QObject::parent()); }" << endl
       
   900                << endl;
       
   901 
       
   902         // constructor/destructor
       
   903         cs << className << "::" << className << "(" << parent << " *parent)" << endl
       
   904            << "    : QDBusAbstractAdaptor(parent)" << endl
       
   905            << "{" << endl
       
   906            << "    // constructor" << endl
       
   907            << "    setAutoRelaySignals(true);" << endl
       
   908            << "}" << endl
       
   909            << endl
       
   910            << className << "::~" << className << "()" << endl
       
   911            << "{" << endl
       
   912            << "    // destructor" << endl
       
   913            << "}" << endl
       
   914            << endl;
       
   915 
       
   916         hs << "public: // PROPERTIES" << endl;
       
   917         foreach (const QDBusIntrospection::Property &property, interface->properties) {
       
   918             QByteArray type = qtTypeName(property.type, property.annotations);
       
   919             QString constRefType = constRefArg(type);
       
   920             QString getter = propertyGetter(property);
       
   921             QString setter = propertySetter(property);
       
   922 
       
   923             hs << "    Q_PROPERTY(" << type << " " << property.name;
       
   924             if (property.access != QDBusIntrospection::Property::Write)
       
   925                 hs << " READ " << getter;
       
   926             if (property.access != QDBusIntrospection::Property::Read)
       
   927                 hs << " WRITE " << setter;
       
   928             hs << ")" << endl;
       
   929 
       
   930             // getter:
       
   931             if (property.access != QDBusIntrospection::Property::Write) {
       
   932                 hs << "    " << type << " " << getter << "() const;" << endl;
       
   933                 cs << type << " "
       
   934                    << className << "::" << getter << "() const" << endl
       
   935                    << "{" << endl
       
   936                    << "    // get the value of property " << property.name << endl
       
   937                    << "    return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << endl
       
   938                    << "}" << endl
       
   939                    << endl;
       
   940             }
       
   941 
       
   942             // setter
       
   943             if (property.access != QDBusIntrospection::Property::Read) {
       
   944                 hs << "    void " << setter << "(" << constRefType << "value);" << endl;
       
   945                 cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << endl
       
   946                    << "{" << endl
       
   947                    << "    // set the value of property " << property.name << endl
       
   948                    << "    parent()->setProperty(\"" << property.name << "\", qVariantFromValue(value";
       
   949                 if (constRefType.contains(QLatin1String("QDBusVariant")))
       
   950                     cs << ".variant()";
       
   951                 cs << "));" << endl
       
   952                    << "}" << endl
       
   953                    << endl;
       
   954             }
       
   955 
       
   956             hs << endl;
       
   957         }
       
   958 
       
   959         hs << "public Q_SLOTS: // METHODS" << endl;
       
   960         foreach (const QDBusIntrospection::Method &method, interface->methods) {
       
   961             bool isNoReply =
       
   962                 method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true");
       
   963             if (isNoReply && !method.outputArgs.isEmpty()) {
       
   964                 fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n",
       
   965                         qPrintable(method.name), qPrintable(interface->name));
       
   966                 continue;
       
   967             }
       
   968 
       
   969             hs << "    ";
       
   970             if (method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
       
   971                 QLatin1String("true"))
       
   972                 hs << "Q_DECL_DEPRECATED ";
       
   973 
       
   974             QByteArray returnType;
       
   975             if (isNoReply) {
       
   976                 hs << "Q_NOREPLY void ";
       
   977                 cs << "void ";
       
   978             } else if (method.outputArgs.isEmpty()) {
       
   979                 hs << "void ";
       
   980                 cs << "void ";
       
   981             } else {
       
   982                 returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out");
       
   983                 hs << returnType << " ";
       
   984                 cs << returnType << " ";
       
   985             }
       
   986 
       
   987             QString name = method.name;
       
   988             hs << name << "(";
       
   989             cs << className << "::" << name << "(";
       
   990 
       
   991             QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
       
   992             writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
       
   993             writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs);
       
   994 
       
   995             hs << ");" << endl; // finished for header
       
   996             cs << ")" << endl
       
   997                << "{" << endl
       
   998                << "    // handle method call " << interface->name << "." << method.name << endl;
       
   999 
       
  1000             // make the call
       
  1001             bool usingInvokeMethod = false;
       
  1002             if (parentClassName.isEmpty() && method.inputArgs.count() <= 10
       
  1003                 && method.outputArgs.count() <= 1)
       
  1004                 usingInvokeMethod = true;
       
  1005 
       
  1006             if (usingInvokeMethod) {
       
  1007                 // we are using QMetaObject::invokeMethod
       
  1008                 if (!returnType.isEmpty())
       
  1009                     cs << "    " << returnType << " " << argNames.at(method.inputArgs.count())
       
  1010                        << ";" << endl;
       
  1011 
       
  1012                 static const char invoke[] = "    QMetaObject::invokeMethod(parent(), \"";
       
  1013                 cs << invoke << name << "\"";
       
  1014 
       
  1015                 if (!method.outputArgs.isEmpty())
       
  1016                     cs << ", Q_RETURN_ARG("
       
  1017                        << qtTypeName(method.outputArgs.at(0).type, method.annotations,
       
  1018                                      0, "Out")
       
  1019                        << ", "
       
  1020                        << argNames.at(method.inputArgs.count())
       
  1021                        << ")";
       
  1022 
       
  1023                 for (int i = 0; i < method.inputArgs.count(); ++i)
       
  1024                     cs << ", Q_ARG("
       
  1025                        << qtTypeName(method.inputArgs.at(i).type, method.annotations,
       
  1026                                      i, "In")
       
  1027                        << ", "
       
  1028                        << argNames.at(i)
       
  1029                        << ")";
       
  1030 
       
  1031                 cs << ");" << endl;
       
  1032 
       
  1033                 if (!returnType.isEmpty())
       
  1034                     cs << "    return " << argNames.at(method.inputArgs.count()) << ";" << endl;
       
  1035             } else {
       
  1036                 if (parentClassName.isEmpty())
       
  1037                     cs << "    //";
       
  1038                 else
       
  1039                     cs << "    ";
       
  1040 
       
  1041                 if (!method.outputArgs.isEmpty())
       
  1042                     cs << "return ";
       
  1043 
       
  1044                 if (parentClassName.isEmpty())
       
  1045                     cs << "static_cast<YourObjectType *>(parent())->";
       
  1046                 else
       
  1047                     cs << "parent()->";
       
  1048                 cs << name << "(";
       
  1049 
       
  1050                 int argPos = 0;
       
  1051                 bool first = true;
       
  1052                 for (int i = 0; i < method.inputArgs.count(); ++i) {
       
  1053                     cs << (first ? "" : ", ") << argNames.at(argPos++);
       
  1054                     first = false;
       
  1055                 }
       
  1056                 ++argPos;           // skip retval, if any
       
  1057                 for (int i = 1; i < method.outputArgs.count(); ++i) {
       
  1058                     cs << (first ? "" : ", ") << argNames.at(argPos++);
       
  1059                     first = false;
       
  1060                 }
       
  1061 
       
  1062                 cs << ");" << endl;
       
  1063             }
       
  1064             cs << "}" << endl
       
  1065                << endl;
       
  1066         }
       
  1067 
       
  1068         hs << "Q_SIGNALS: // SIGNALS" << endl;
       
  1069         foreach (const QDBusIntrospection::Signal &signal, interface->signals_) {
       
  1070             hs << "    ";
       
  1071             if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) ==
       
  1072                 QLatin1String("true"))
       
  1073                 hs << "Q_DECL_DEPRECATED ";
       
  1074 
       
  1075             hs << "void " << signal.name << "(";
       
  1076 
       
  1077             QStringList argNames = makeArgNames(signal.outputArgs);
       
  1078             writeArgList(hs, argNames, signal.annotations, signal.outputArgs);
       
  1079 
       
  1080             hs << ");" << endl; // finished for header
       
  1081         }
       
  1082 
       
  1083         // close the class:
       
  1084         hs << "};" << endl
       
  1085            << endl;
       
  1086     }
       
  1087 
       
  1088     // close the include guard
       
  1089     hs << "#endif" << endl;
       
  1090 
       
  1091     QString mocName = moc(filename);
       
  1092     if (includeMocs && !mocName.isEmpty())
       
  1093         cs << endl
       
  1094            << "#include \"" << mocName << "\"" << endl;
       
  1095 
       
  1096     cs.flush();
       
  1097     hs.flush();
       
  1098 
       
  1099     QFile file;
       
  1100     openFile(headerName, file);
       
  1101     file.write(headerData);
       
  1102 
       
  1103     if (headerName == cppName) {
       
  1104         file.write(cppData);
       
  1105     } else {
       
  1106         QFile cppFile;
       
  1107         openFile(cppName, cppFile);
       
  1108         cppFile.write(cppData);
       
  1109     }
       
  1110 }
       
  1111 
       
  1112 int main(int argc, char **argv)
       
  1113 {
       
  1114     QCoreApplication app(argc, argv);
       
  1115     parseCmdLine(app.arguments());
       
  1116 
       
  1117     QDBusIntrospection::Interfaces interfaces = readInput();
       
  1118     cleanInterfaces(interfaces);
       
  1119 
       
  1120     if (!proxyFile.isEmpty() || adaptorFile.isEmpty())
       
  1121         writeProxy(proxyFile, interfaces);
       
  1122 
       
  1123     if (!adaptorFile.isEmpty())
       
  1124         writeAdaptor(adaptorFile, interfaces);
       
  1125 
       
  1126     return 0;
       
  1127 }
       
  1128 
       
  1129 /*!
       
  1130     \page qdbusxml2cpp.html
       
  1131     \title QtDBus XML compiler (qdbusxml2cpp)
       
  1132     \keyword qdbusxml2cpp
       
  1133 
       
  1134     The QtDBus XML compiler is a tool that can be used to parse interface descriptions and produce
       
  1135     static code representing those interfaces, which can then be used to make calls to remote
       
  1136     objects or implement said interfaces.
       
  1137 
       
  1138     \c qdbusxml2dcpp has two modes of operation, that correspond to the two possible outputs it can
       
  1139     produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++
       
  1140     header and a source file, which are meant to be edited and adapted to your needs.
       
  1141 
       
  1142     The \c qdbusxml2dcpp tool is not meant to be run every time you compile your
       
  1143     application. Instead, it's meant to be used when developing the code or when the interface
       
  1144     changes.
       
  1145 
       
  1146     The adaptor classes generated by \c qdbusxml2cpp are just a skeleton that must be completed. It
       
  1147     generates, by default, calls to slots with the same name on the object the adaptor is attached
       
  1148     to. However, you may modify those slots or the property accessor functions to suit your needs.
       
  1149 */