view generator/metainfogenerator.cpp @ 282:256ab6cb8e85

Signals look-up andNew syntax for connect. The old one will not work from now on. This will allow for the signals overload. Although changes are done for both D1 and D2 versions, D1 won't work because of compiler bugs. I am tired of waiting for fixes.
author eldar
date Fri, 16 Oct 2009 02:43:59 +0000
parents 1349940724eb
children
line wrap: on
line source

/****************************************************************************
**
** Copyright (C) 1992-2008 Nokia. All rights reserved.
**
** This file is part of Qt Jambi.
**
** * 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 General Public License Usage
* Alternatively, this file may be used under the terms of the GNU
* General Public License versions 2.0 or 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 GNU General Public Licensing requirements will be met:
* http://www.fsf.org/licensing/licenses/info/GPLv2.html and
* http://www.gnu.org/copyleft/gpl.html.  In addition, as a special
* exception, Nokia gives you certain additional rights. These rights
* are described in the Nokia Qt GPL Exception version 1.2, included in
* the file GPL_EXCEPTION.txt in this package.
* 
* Qt for Windows(R) Licensees
* As a special exception, Nokia, as the sole copyright holder for Qt
* Designer, grants users of the Qt/Eclipse Integration plug-in the
* right for the Qt/Eclipse Integration to link to functionality
* provided by Qt Designer and its related libraries.
*
*
* If you are unsure which license is appropriate for your use, please
* contact the sales department at qt-sales@nokia.com.

**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "metainfogenerator.h"
#include "reporthandler.h"
#include "cppimplgenerator.h"
#include "fileout.h"

#include <QDir>
#include <QMetaType>

MetaInfoGenerator::MetaInfoGenerator(PriGenerator *pri):
    DGenerator(),
    priGenerator(pri)

{
    setFilenameStub("metainfo");
}

QString MetaInfoGenerator::subDirectoryForPackage(const QString &package, OutputDirectoryType type) const
{
    switch (type) {
    case CppDirectory:
        return "cpp/" + QString(package).replace(".", "_") + "/";
    case JavaDirectory:
        return QString(package).replace(".", "/");
    default:
        return QString(); // kill nonsense warnings
    }
}

QString MetaInfoGenerator::subDirectoryForClass(const AbstractMetaClass *cls, OutputDirectoryType type) const
{
    Q_ASSERT(cls);
    return subDirectoryForPackage(cls->package(), type);
}

void MetaInfoGenerator::generate()
{
    buildSkipList();
    writeCppFile();
    writeHeaderFile();
    writeLibraryInitializers();
}

bool MetaInfoGenerator::shouldGenerate(const TypeEntry *entry) const
{
    return entry != 0 && !entry->isNamespace() && !entry->isEnum() && (entry->codeGeneration() & TypeEntry::GenerateCpp);
}

bool MetaInfoGenerator::shouldGenerate(const AbstractMetaClass *cls) const
{
    return (!cls->isInterface() && cls->typeEntry()->isValue() && !cls->isNamespace()
            && !cls->isAbstract() && (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateCpp));
}

QString MetaInfoGenerator::fileNameForClass(const AbstractMetaClass *) const
{
    return filenameStub() + ".cpp";
}

void MetaInfoGenerator::write(QTextStream &, const AbstractMetaClass *)
{
    // not used
}

bool MetaInfoGenerator::generated(const AbstractMetaClass *cls) const
{
    return generatedMetaInfo(cls->package());
}

bool MetaInfoGenerator::generatedMetaInfo(const QString &package) const
{
    return (m_skip_list.value(package, 0x0) & GeneratedMetaInfo);
}

bool MetaInfoGenerator::generatedJavaClasses(const QString &package) const
{
    return (m_skip_list.value(package, 0x0) & GeneratedJavaClasses);
}

static void metainfo_write_name_list(QTextStream &s, const char *var_name, const QList<QString> &strs,
                                     int offset, int skip)
{
    s << "static const char *" << var_name << "[] = {" << endl;
    for (int i=offset; i<strs.size(); i += skip) {
        s << "    \"" << strs.at(i).toLatin1() << "\"";
        if (i < strs.size() - 1)
            s << ",";
        s << endl;
    }
    s << "};" << endl << endl;
}

void MetaInfoGenerator::writeEnums(QTextStream &s, const QString &package)
{
    TypeEntryHash entries = TypeDatabase::instance()->allEntries();
    TypeEntryHash::iterator it;

    QList<QString> strs;
    for (it=entries.begin(); it!=entries.end(); ++it) {
        QList<TypeEntry *> entries = it.value();
        foreach (TypeEntry *entry, entries) {
            if ((entry->isFlags() || entry->isEnum()) && entry->javaPackage() == package) {
                EnumTypeEntry *eentry = entry->isEnum() ? static_cast<EnumTypeEntry *>(entry) : static_cast<FlagsTypeEntry *>(entry)->originator();

                // The Qt flags names should map to the enum names, this is
                // required for the designer plugin to find the enum type of
                // a flags type since this functionality is not available in
                // Qt. This may be a little bit inconsistent, but it saves
                // us making yet another hash table for lookups. If it causes
                // problems, make a new one for this particular purpose.
                strs.append((eentry->javaPackage().isEmpty() ? QString() : eentry->javaPackage().replace('.', '/')  + "/")
                            + eentry->javaQualifier() + "$" + eentry->targetLangName());
                strs.append(entry->isFlags() ? static_cast<FlagsTypeEntry *>(entry)->originalName() : entry->qualifiedCppName());
            }
        }
    }

    Q_ASSERT(strs.size() % 2 == 0);

    s << "static int enum_count = " << (strs.size() / 2) << ";" << endl;
    if (strs.size() > 0) {
        metainfo_write_name_list(s, "enumJavaNames", strs, 0, 2);
        metainfo_write_name_list(s, "enumCppNames", strs, 1, 2);
    } else {
        s << "static const char **enumCppNames = 0;" << endl
          << "static const char **enumJavaNames = 0;" << endl;
    }
}

void MetaInfoGenerator::writeSignalsAndSlots(QTextStream &s, const QString &package)
{
    AbstractMetaClassList classes = this->classes();

    QList<QString> strs;
    foreach (AbstractMetaClass *cls, classes) {
        if (cls->package() == package) {
            AbstractMetaFunctionList functions = cls->functions();
            foreach (AbstractMetaFunction *f, functions) {
                if (f->implementingClass() == cls && (f->isSignal() || f->isSlot())) {

                    AbstractMetaArgumentList arguments = f->arguments();
                    int numOverloads = arguments.size();
                    for (int i=arguments.size()-1; i>=0; --i) {
                        if (arguments.at(i)->defaultValueExpression().isEmpty()) {
                            numOverloads = arguments.size() - i - 1;
                            break;
                        }
                    }

                    for (int i=0; i<=numOverloads; ++i) {
                        Option option = Option(SkipAttributes | SkipReturnType | SkipName);
                        QString qtName;
                        {

                            QTextStream qtNameStream(&qtName);
                            CppGenerator::writeFunctionSignature(qtNameStream, f, 0, QString(),
                                Option(option | OriginalName | NormalizeAndFixTypeSignature | OriginalTypeDescription),
                                QString(), QStringList(), arguments.size() - i);
                        }
                        qtName = f->implementingClass()->qualifiedCppName() + "::" + qtName;
                        qtName = QMetaObject::normalizedSignature(qtName.toLatin1().constData());

                        QString javaFunctionName = functionSignature(f, 0, 0, option, arguments.size() - (f->isSignal() ? 0 : i));
                        QString javaObjectName = f->isSignal()
                                                ? f->name()
                                                : javaFunctionName;

                        javaFunctionName = f->implementingClass()->fullName() + "." + javaFunctionName;
                        javaObjectName   = f->implementingClass()->fullName() + "." + javaObjectName;

                        QString javaSignature = "(";
                        for (int j=0; j < (arguments.size() - (f->isSignal() ? 0 : i)); ++j)  {
                            AbstractMetaArgument *arg = arguments.at(j);
                            javaSignature += jni_signature(arg->type(), SlashesAndStuff);
                        }
                        javaSignature += ")" + jni_signature(f->type(), SlashesAndStuff);

                        strs.append(qtName);
                        strs.append(javaFunctionName);
                        strs.append(javaObjectName);
                        strs.append(javaSignature);
                    }
                }
            }
        }
    }

    Q_ASSERT(strs.size() % 4 == 0);

    s << "static int sns_count = " << (strs.size() / 4) << ";" << endl;
    if (strs.size() > 0) {
        metainfo_write_name_list(s, "qtNames", strs, 0, 4);
        metainfo_write_name_list(s, "javaFunctionNames", strs, 1, 4);
        metainfo_write_name_list(s, "javaObjectNames", strs, 2, 4);
        metainfo_write_name_list(s, "javaSignatures", strs, 3, 4);
    } else {
        s << "static const char **qtNames = 0;" << endl
          << "static const char **javaFunctionNames = 0;" << endl
          << "static const char **javaObjectNames = 0;" << endl
          << "static const char **javaSignatures = 0;" << endl;
    }
}

void MetaInfoGenerator::writeRegisterSignalsAndSlots(QTextStream &s)
{
    s << "    for (int i=0;i<sns_count; ++i) {" << endl
      << "        registerQtToJava(qtNames[i], javaFunctionNames[i]);" << endl
      << "        if (getQtName(javaObjectNames[i]).length() < QByteArray(qtNames[i]).size())" << endl
      << "            registerJavaToQt(javaObjectNames[i], qtNames[i]);" << endl
      << "        registerJavaSignature(qtNames[i], javaSignatures[i]);" << endl
      << "    }" << endl;
}

void MetaInfoGenerator::writeRegisterEnums(QTextStream &s)
{
    s << "    for (int i=0;i<enum_count; ++i) {" << endl
      << "        registerQtToJava(enumCppNames[i], enumJavaNames[i]);" << endl
      << "        registerJavaToQt(enumJavaNames[i], enumCppNames[i]);" << endl
      << "    }" << endl;
}

void MetaInfoGenerator::buildSkipList()
{
    AbstractMetaClassList classList = classes();
    foreach (AbstractMetaClass *cls, classList) {
        if (!m_skip_list.contains(cls->package()))
            m_skip_list[cls->package()] = 0x0;

        if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateCpp)
            m_skip_list[cls->package()] |= GeneratedMetaInfo;

        if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)
            m_skip_list[cls->package()] |= GeneratedJavaClasses;
    }
}

QStringList MetaInfoGenerator::writePolymorphicHandler(QTextStream &s, const QString &package,
                                                       const AbstractMetaClassList &classes)
{
    QStringList handlers;
    foreach (AbstractMetaClass *cls, classes) {
        const ComplexTypeEntry *centry = cls->typeEntry();
        if (!centry->isPolymorphicBase())
            continue;

        AbstractMetaClassList classList = this->classes();
        bool first = true;
        foreach (AbstractMetaClass *clazz, classList) {
            if (clazz->package() == package && clazz->inheritsFrom(cls)) {
                if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) {
                    // On first find, open the function
                    if (first) {
                        first = false;

                        QString handler = jni_signature(cls->fullName(), Underscores);
                        handlers.append(handler);

                        s << "static bool polymorphichandler_" << handler
                          << "(const void *ptr, char **class_name, char **package)" << endl
                          << "{" << endl
                          << "    Q_ASSERT(ptr != 0);" << endl
                          << "    " << cls->qualifiedCppName() << " *object = ("
                          << cls->qualifiedCppName() << " *)ptr;" << endl;
                    }

                    // For each, add case label
                    s << "    if ("
                      << clazz->typeEntry()->polymorphicIdValue().replace("%1", "object")
                      << ") {" << endl
                      << "        *class_name = \"" << clazz->name() << "\";" << endl
                      << "        *package    = \"" << clazz->package().replace(".", "/") << "/\";" << endl
                      << "        return true;" << endl
                      << "    }" << endl;
                } else {
                    QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set")
                        .arg(clazz->name())
                        .arg(cls->name());

                    ReportHandler::warning(warning);
                }
            }
        }

        // Close the function if it has been opened
        if (!first) {
            s << "    return false;" << endl
              << "}" << endl;
        }
    }

    return handlers;
}

#if defined(QTJAMBI_DEBUG_TOOLS)
void MetaInfoGenerator::writeNameLiteral(QTextStream &s, const TypeEntry *entry, const QString &fileName)
{
    static QSet<QString> used;

    if (!used.contains(fileName + ":" + entry->name())) {
        s << "char __name_" << QString(entry->name()).replace(':', '_').replace(' ', '_') << "[] = \"" << entry->name() << "\";" << endl;
        used.insert(fileName + ":" + entry->name());
    }
}
#endif

void MetaInfoGenerator::writeCppFile()
{
    TypeEntryHash entries = TypeDatabase::instance()->allEntries();
    TypeEntryHash::iterator it;

    AbstractMetaClassList classes_with_polymorphic_id;
    AbstractMetaClassList classList = classes();
    QHash<QString, FileOut *> fileHash;

    // Seems continue is not supported by our foreach loop, so
    foreach (AbstractMetaClass *cls, classList) {

        FileOut *f = fileHash.value(cls->package(), 0);
        if (f == 0 && generated(cls)) {
            f = new FileOut(outputDirectory() + "/" + subDirectoryForClass(cls, CppDirectory) + "/" + cppFilename());

            writeIncludeStatements(f->stream, classList, cls->package());
            f->stream << endl;

#if defined(QTJAMBI_DEBUG_TOOLS)
            // Write the generic destructors and constructors
            f->stream << "template <typename T, const char *NAME>" << endl
                        << "void genericDestructor(void *t)" << endl
                        << "{" << endl
                        << "    delete (T *) t;" << endl
                        << "    qtjambi_increase_destructorFunctionCalledCount(QString::fromLatin1(NAME));" << endl
                        << "}" << endl << endl
                        << "template <typename T>" << endl
                        << "void *genericConstructor(const void *t)" << endl
                        << "{" << endl
                        << "    if (!t)" << endl
                        << "        return new T;" << endl
                        << "    return new T(*reinterpret_cast<const T *>(t));" << endl
                        << "}" << endl;
#endif


            fileHash.insert(cls->package(), f);

            priGenerator->addSource(cls->package(), cppFilename());
        }

        if (!(cls->attributes() & AbstractMetaAttributes::Fake)) {
            if (f != 0) {
                if (cls->typeEntry()->isObject()
                    && !cls->typeEntry()->isQObject()
                    && !cls->isInterface()) {
                    writeDestructors(f->stream, cls);
                }
                writeCustomStructors(f->stream, cls->typeEntry());
            }

            if (cls->typeEntry()->isPolymorphicBase())
                classes_with_polymorphic_id.append(cls);
        }

#if defined(QTJAMBI_DEBUG_TOOLS)
        if (cls->typeEntry()->isValue() && shouldGenerate(cls->typeEntry()))
            writeNameLiteral(f->stream, cls->typeEntry(), f->name());
#endif
    }

    QHash<QString, QStringList> handlers_to_register;
    foreach (QString package, fileHash.keys()) {
        FileOut *f = fileHash.value(package, 0);
        if (f != 0) {
            writeSignalsAndSlots(f->stream, package);
            writeEnums(f->stream, package);
            handlers_to_register[package] = writePolymorphicHandler(f->stream, package, classes_with_polymorphic_id);
        }
    }

    // Primitive types must be added to all packages, in case the other packages are
    // not referenced from the generated code.
    foreach (FileOut *f, fileHash.values()) {
        for (it=entries.begin(); it!=entries.end(); ++it) {
            QList<TypeEntry *> entries = it.value();
            foreach (TypeEntry *entry, entries) {
                if (shouldGenerate(entry) && entry->isPrimitive()) {
                    writeCustomStructors(f->stream, entry);
#if defined(QTJAMBI_DEBUG_TOOLS)
                    writeNameLiteral(f->stream, entry, f->name());
#endif
                }
            }
        }

        // Initialization function: Registers meta types
        writeInitializationFunctionName(f->stream, fileHash.key(f, ""), true);
        f->stream << endl << "{" << endl;
        for (it=entries.begin(); it!=entries.end(); ++it) {
            QList<TypeEntry *> entries = it.value();
            foreach (TypeEntry *entry, entries) {
                if (entry &&
                    ( (shouldGenerate(entry) && entry->isPrimitive())
                    || entry->isString()
                    || entry->isChar())) {
                        writeInitialization(f->stream, entry, 0);
                    }
            }
        }
        writeRegisterSignalsAndSlots(f->stream);
        writeRegisterEnums(f->stream);
    }

    foreach (AbstractMetaClass *cls, classList) {
        FileOut *f = fileHash.value(cls->package(), 0);

        if (f != 0) {
            writeInitialization(f->stream, cls->typeEntry(), cls, shouldGenerate(cls));
        }
    }

    foreach (QString package, fileHash.keys()) {
        FileOut *f = fileHash.value(package, 0);
        if (f != 0) {
            foreach (QString handler, handlers_to_register.value(package, QStringList())) {
                f->stream << "    qtjambi_register_polymorphic_id(\"" << handler << "\","
                         << "polymorphichandler_" << handler << ");" << endl;
            }

            f->stream << "}" << endl << endl;
            if( f->done() )
                ++m_num_generated_written;
            ++m_num_generated;

            delete f;
        }
    }
}

void MetaInfoGenerator::writeHeaderFile()
{
    AbstractMetaClassList classList = classes();
    QHash<QString, bool> fileHash;

    foreach (AbstractMetaClass *cls, classList) {
        bool hasGenerated = fileHash.value(cls->package(), false);
        if (!hasGenerated && generated(cls)) {
            FileOut file(outputDirectory() + "/" + subDirectoryForClass(cls, CppDirectory) + "/" + headerFilename());
            file.stream << "#ifndef " << filenameStub().toUpper() << "_H" << endl;
            file.stream << "#define " << filenameStub().toUpper() << "_H" << endl << endl;
            writeInitializationFunctionName(file.stream, cls->package(), true);
            file.stream << ";" << endl << "#endif" << endl << endl;

            fileHash.insert(cls->package(), true);

            priGenerator->addHeader(cls->package(), headerFilename());

            if( file.done() )
                ++m_num_generated_written;
            ++m_num_generated;
        }
    }
}

void MetaInfoGenerator::writeCodeBlock(QTextStream &s, const QString &code)
{
    QStringList lines = code.split('\n');
    QString indent;
    foreach (QString str, lines) {
        s << "    " << indent << str.trimmed() << endl;
        if (!str.trimmed().endsWith(";") && !str.trimmed().isEmpty())
            indent = "    ";
        else
            indent = "";
    }
}

const AbstractMetaClass* MetaInfoGenerator::lookupClassWithPublicDestructor(const AbstractMetaClass *cls)
{
    while (cls != 0) {
        if (cls->hasPublicDestructor()) {
            return cls;
        } else {
            cls = cls->baseClass();
        }
    }
    return 0;
}

void MetaInfoGenerator::writeDestructors(QTextStream &s, const AbstractMetaClass *cls)
{
    // We can only delete classes with public destructors
    const AbstractMetaClass *clsWithPublicDestructor = lookupClassWithPublicDestructor(cls);
    if(clsWithPublicDestructor != 0) {
        const ComplexTypeEntry *entry = cls->typeEntry();
        if ((entry->codeGeneration() & TypeEntry::GenerateCode) != 0) {
            s   << "void destructor_" << entry->javaPackage().replace(".", "_")  << "_"
                << entry->lookupName().replace(".", "_").replace("$", "_") << "(void *ptr)" << endl
                << "{" << endl
                << "    delete reinterpret_cast<" << clsWithPublicDestructor->qualifiedCppName() << " *>(ptr);" << endl;

#if defined(QTJAMBI_DEBUG_TOOLS)
            s   << "    qtjambi_increase_destructorFunctionCalledCount(QString::fromLatin1(\"" << cls->name() << "\"));" << endl;
#endif

            s   << "}" << endl << endl;
        }
    }
}

void MetaInfoGenerator::writeCustomStructors(QTextStream &s, const TypeEntry *entry)
{
    if (!entry->preferredConversion())
        return ;

    CustomFunction customConstructor = entry->customConstructor();
    CustomFunction customDestructor = entry->customDestructor();

    if (!customConstructor.name.isEmpty() && !customDestructor.name.isEmpty()) {
        s << "// Custom constructor and destructor for " << entry->qualifiedCppName() << endl
          << "static void *" << customConstructor.name << "("
          << "const " << entry->qualifiedCppName() << " *" << customConstructor.param_name
          << ")" << endl
          << "{" << endl;
        writeCodeBlock(s, customConstructor.code());
        s << "}" << endl << endl;

        s << "static void " << customDestructor.name << "("
          << "const " << entry->qualifiedCppName() << " *" << customDestructor.param_name
          << ")" << endl
          << "{" << endl;
        writeCodeBlock(s, customDestructor.code());
        s << "}" << endl << endl;
    }
}

static void generateInitializer(QTextStream &s, const QString &package, CodeSnip::Position pos)
{
    QList<CodeSnip> snips =
        ((TypeSystemTypeEntry *) TypeDatabase::instance()->findType(package))->snips;

    foreach (const CodeSnip &snip, snips)
        if (snip.position == pos)
            s << snip.code();
}

void MetaInfoGenerator::writeLibraryInitializers()
{
    // from cppimplgenerator.cpp
    extern QString jni_function_signature(QString package,
                                          QString class_name,
                                          const QString &function_name,
                                          const QString &return_type,
                                          const QString &mangled_arguments = QString(),
                                          uint options = CppImplGenerator::StandardJNISignature);

    // We need to generate a library initializer in Java for all packages
    // that have generated classes in Java, and in C++ for all packages
    // that have generated metainfo.

    QList<QString> known_packages = m_skip_list.keys();
    foreach (QString package, known_packages) {
        if (generatedMetaInfo(package)) { // write cpp file

            FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, CppDirectory) + "/qtjambi_libraryinitializer.cpp");

            QString signature = jni_function_signature(package, "QtJambi_LibraryInitializer",
                                                   "__qt_initLibrary", "void");
            QTextStream &s = fileOut.stream;
            s << "#include \"metainfo.h\"" << endl
              << "#include \"qtjambi_global.h\"" << endl << endl
              << signature << "(JNIEnv *, jclass)" << endl
              << "{" << endl
              << "    ";
            writeInitializationFunctionName(s, package, false);
            s << ";" << endl
              << "}" << endl << endl;

            priGenerator->addSource(package, "qtjambi_libraryinitializer.cpp");

            if( fileOut.done() )
                ++m_num_generated_written;
            ++m_num_generated;
        }

        if (generatedJavaClasses(package)) {

            FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, JavaDirectory) + "/QtJambi_LibraryInitializer.java");

            QTextStream &s = fileOut.stream;
            s << "package " << package << ";" << endl << endl
              << "class QtJambi_LibraryInitializer" << endl
              << "{" << endl
              << "    static {" << endl;

            generateInitializer(s, package, CodeSnip::Beginning);

            s << "        qt.Utilities.loadJambiLibrary(\""
              << QString(package).replace(".", "_") << "\");" << endl;

            if (generatedMetaInfo(package))
              s << "        __qt_initLibrary();" << endl;

            generateInitializer(s, package, CodeSnip::End);

            s << "    }" << endl;

            if (generatedMetaInfo(package))
              s << "    private native static void __qt_initLibrary();" << endl;

            s << "    static void init() { };" << endl
              << "}" << endl << endl;

            if( fileOut.done() )
                ++m_num_generated_written;
            ++m_num_generated;
        }
    }
}

void MetaInfoGenerator::writeInclude(QTextStream &s, const Include &inc)
{
    if (inc.name.isEmpty())
        return;

    s << "#include ";
    if (inc.type == Include::LocalPath)
        s << "\"" << inc.name << "\"";
    else
        s << "<" << inc.name << ">";
    s << endl;
}

void MetaInfoGenerator::writeIncludeStatements(QTextStream &s, const AbstractMetaClassList &classList,
                                               const QString &package)
{
    writeInclude(s, Include(Include::LocalPath, headerFilename()));
    writeInclude(s, Include(Include::IncludePath, "QMetaType"));
    writeInclude(s, Include(Include::IncludePath, "QString"));
    writeInclude(s, Include(Include::IncludePath, "QLatin1String"));
    writeInclude(s, Include(Include::IncludePath, "QHash"));
    writeInclude(s, Include(Include::IncludePath, "QReadWriteLock"));
    writeInclude(s, Include(Include::IncludePath, "QReadLocker"));
    writeInclude(s, Include(Include::IncludePath, "QWriteLocker"));
    writeInclude(s, Include(Include::IncludePath, "qtjambi_cache.h"));
    writeInclude(s, Include(Include::IncludePath, "qtjambi_core.h"));

#if defined(QTJAMBI_DEBUG_TOOLS)
    writeInclude(s, Include(Include::IncludePath, "qtjambidebugtools_p.h"));
#endif

    s << endl;

    foreach (AbstractMetaClass *cls, classList) {
        if (generated(cls) && !cls->isInterface() && cls->package() == package) {
            const ComplexTypeEntry *ctype = cls->typeEntry();

            Include inc = ctype->include();
            writeInclude(s, inc);
        }
    }
}

void MetaInfoGenerator::writeInitializationFunctionName(QTextStream &s, const QString &package, bool fullSignature)
{
    if (fullSignature)
        s << "void ";
    s << "__metainfo_init_" << QString(package).replace(".", "_") << "()";
}

void MetaInfoGenerator::writeInitialization(QTextStream &s, const TypeEntry *entry, const AbstractMetaClass *cls,
                                            bool registerMetaType)
{
    if (entry->codeGeneration() == TypeEntry::GenerateForSubclass)
        return;

    if (cls && cls->attributes() & AbstractMetaAttributes::Fake)
        return;


    QString constructorName = entry->customConstructor().name;
    QString destructorName = entry->customDestructor().name;
#if defined(QTJAMBI_DEBUG_TOOLS)

    if (constructorName.isEmpty())
        constructorName = "genericConstructor<" + entry->qualifiedCppName() + ">";

    if (destructorName.isEmpty())
        destructorName = "genericDestructor<" + entry->qualifiedCppName() + ", __name_" + entry->name() + ">";

#endif


    if (constructorName.isEmpty() != destructorName.isEmpty()) {
        ReportHandler::warning(QString("specify either no custom functions, or both "
                                       "constructor and destructor for type '%1'").arg(entry->name()));
     }

    QString javaPackage = entry->javaPackage();

    QString javaName =  entry->lookupName();
    if(!javaPackage.isEmpty()){
        javaName.prepend(javaPackage.replace(".", "/") + "/");
    }


    if (entry->isComplex()) {
        const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry);
        if (centry->typeFlags() & ComplexTypeEntry::DeleteInMainThread)
            s << "    registerDeletionPolicy(\"" << javaName << "\", DeletionPolicyDeleteInMainThread);" << endl;
    }

    QString qtName = entry->qualifiedCppName();
    if ((!entry->isInterface())
        && (!entry->isPrimitive() || ((PrimitiveTypeEntry *) entry)->preferredTargetLangType()))
        s << "    registerQtToJava(\"" << qtName << "\", \"" << javaName << "\");" << endl;

    if (!entry->preferredConversion())
        return ;

    s << "    registerJavaToQt(\"" << javaName << "\", \"" << qtName << "\");" << endl;
    if (entry->isComplex() && entry->isObject() && !((ComplexTypeEntry *)entry)->isQObject() && !entry->isInterface()) {
        QString patchedName = QString(javaName).replace("/", "_").replace("$", "_");

        if(lookupClassWithPublicDestructor(cls))
            s << "    registerDestructor(\"" << javaName << "\", destructor_" << patchedName << ");" << endl;
    }

    if (!registerMetaType)
        return ;

    int metaType = QMetaType::type(entry->name().toLocal8Bit().constData());
    if (metaType != QMetaType::Void)
        return ;


    if (!constructorName.isEmpty() && !destructorName.isEmpty()) {
        s << "    QMetaType::registerType(\"" << entry->qualifiedCppName() << "\"," << endl
          << "                            reinterpret_cast<QMetaType::Destructor>("
          << destructorName
          << ")," << endl
          << "                            reinterpret_cast<QMetaType::Constructor>("
          << constructorName
          << "));" << endl;
    } else {
        // Look for default constructor, required for qRegisterMetaType
        if (cls != 0) {
            AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::WasPublic | AbstractMetaClass::Constructors);

            bool hasDefaultConstructor = false;
            foreach (AbstractMetaFunction *function, functions) {
                // Default constructor has to be present
                if (function->wasPublic() && function->actualMinimumArgumentCount() == 0)
                    hasDefaultConstructor = true;
            }

            if (!hasDefaultConstructor) {
                ReportHandler::warning(QString("Value type '%1' is missing a default constructor. "
                                       "The resulting C++ code will not compile. If necessary, use <custom-constructor> and "
                                       "<custom-destructor> tags to provide the constructors.").arg(cls->fullName()));
            }

        }
        s << "    qRegisterMetaType<" << entry->qualifiedCppName() << ">(\"" << entry->qualifiedCppName() << "\");" << endl;
    }

}