Qt

 view release on metacpan or  search on metacpan

qtdbus/tools/qdbusxml2perl/qdbusxml2perl.cpp  view on Meta::CPAN

**
** $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 <QtCore/qbytearray.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qset.h>

#include <QtDBus/QtDBus>
#include "qdbusmetaobject_p.h"
#include "qdbusintrospection_p.h"

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef Q_WS_WIN
#include <process.h>
#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 <filename>    Write the adaptor code to <filename>\n"
    "  -A <package>     Use <package> as the package for the generated adaptor\n"
    "  -h               Show this information\n"
    "  -i <filename>    Add #include to the output\n"
    "  -l <classname>   When generating an adaptor, use <classname> as the parent class\n"
    "  -m               Generate #include \"filename.moc\" statements in the .cpp files\n"
    "  -N               Don't use namespaces\n"
    "  -p <filename>    Write the proxy code to <filename>\n"
    "  -P <package>     Use <package> 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 T> class QList;\n"
    "template<class Key, class Value> 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);
}

qtdbus/tools/qdbusxml2perl/qdbusxml2perl.cpp  view on Meta::CPAN

        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<QVariant> 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

qtdbus/tools/qdbusxml2perl/qdbusxml2perl.cpp  view on Meta::CPAN

           << "}" << 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.



( run in 3.646 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )