Logo Search packages:      
Sourcecode: qtjambi version File versions  Download package

typesystem.cpp

/****************************************************************************
**
** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
**
** This file is part of Qt Jambi.
**
** ** This file may be used under the terms of the GNU General Public
** License version 2.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.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.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 "typesystem.h"

#include "customtypes.h"

#include <reporthandler.h>

#include <QtXml>

QString strings_Object = QLatin1String("Object");
QString strings_String = QLatin1String("String");
QString strings_Thread = QLatin1String("Thread");
QString strings_char = QLatin1String("char");
QString strings_java_lang = QLatin1String("java.lang");
QString strings_jchar = QLatin1String("jchar");
QString strings_jobject = QLatin1String("jobject");

class StackElement
{
    public:
    enum ElementType {
        None = 0x0,

        // Type tags (0x1, ... , 0xff)
        ObjectTypeEntry      = 0x1,
        ValueTypeEntry       = 0x2,
        InterfaceTypeEntry   = 0x3,
        NamespaceTypeEntry   = 0x4,
        ComplexTypeEntryMask = 0xf,

        // Non-complex type tags (0x10, 0x20, ... , 0xf0)
        PrimitiveTypeEntry   = 0x10,
        EnumTypeEntry        = 0x20,
        TypeEntryMask        = 0xff,

        // Simple tags (0x100, 0x200, ... , 0xf00)
        ExtraIncludes               = 0x100,
        Include                     = 0x200,
        ModifyFunction              = 0x300,
        ModifyField                 = 0x400,
        Root                        = 0x500,
        CustomMetaConstructor       = 0x600,
        CustomMetaDestructor        = 0x700,
        ArgumentMap                 = 0x800,
        SuppressedWarning           = 0x900,
        Rejection                   = 0xa00,
        LoadTypesystem              = 0xb00,
        RejectEnumValue             = 0xc00,
        Template                    = 0xd00,
        TemplateInstanceEnum        = 0xe00,
        Replace                     = 0xf00,
        SimpleMask                  = 0xf00,

        // Code snip tags (0x1000, 0x2000, ... , 0xf000)
        InjectCode =           0x1000,
        InjectCodeInFunction = 0x2000,
        CodeSnipMask =         0xf000,

        // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
        Access                   = 0x010000,
        Removal                  = 0x020000,
        Rename                   = 0x040000,
        ModifyArgument           = 0x080000,
        FunctionModifiers        = 0xff0000,

        // Argument modifier tags (0x01000000 ... 0xf0000000)
        ConversionRule           = 0x01000000,
        ReplaceType              = 0x02000000,
        ReplaceDefaultExpression = 0x04000000,
        RemoveArgument           = 0x08000000,
        DefineOwnership          = 0x10000000,
        RemoveDefaultExpression  = 0x20000000,
        NoNullPointers           = 0x40000000,
        ReferenceCount           = 0x80000000,
        ArgumentModifiers        = 0xff000000
    };

    StackElement(StackElement *p) : entry(0), type(None), parent(p){ }

    TypeEntry *entry;
    ElementType type;
    StackElement *parent;

    union {
        TemplateInstance *templateInstance;
        TemplateEntry *templateEntry;
        CustomFunction *customFunction;
    } value;
};

class Handler : public QXmlDefaultHandler
{
public:
    Handler(TypeDatabase *database, bool generate)
        : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
    {
        m_current_enum = 0;
        current = 0;

        tagNames["rejection"] = StackElement::Rejection;
        tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
        tagNames["object-type"] = StackElement::ObjectTypeEntry;
        tagNames["value-type"] = StackElement::ValueTypeEntry;
        tagNames["interface-type"] = StackElement::InterfaceTypeEntry;
        tagNames["namespace-type"] = StackElement::NamespaceTypeEntry;
        tagNames["enum-type"] = StackElement::EnumTypeEntry;
        tagNames["extra-includes"] = StackElement::ExtraIncludes;
        tagNames["include"] = StackElement::Include;
        tagNames["inject-code"] = StackElement::InjectCode;
        tagNames["modify-function"] = StackElement::ModifyFunction;
        tagNames["modify-field"] = StackElement::ModifyField;
        tagNames["access"] = StackElement::Access;
        tagNames["remove"] = StackElement::Removal;
        tagNames["rename"] = StackElement::Rename;
        tagNames["typesystem"] = StackElement::Root;
        tagNames["custom-constructor"] = StackElement::CustomMetaConstructor;
        tagNames["custom-destructor"] = StackElement::CustomMetaDestructor;
        tagNames["argument-map"] = StackElement::ArgumentMap;
        tagNames["suppress-warning"] = StackElement::SuppressedWarning;
        tagNames["load-typesystem"] = StackElement::LoadTypesystem;
        tagNames["define-ownership"] = StackElement::DefineOwnership;
        tagNames["replace-default-expression"] = StackElement::ReplaceDefaultExpression;
        tagNames["reject-enum-value"] = StackElement::RejectEnumValue;
        tagNames["replace-type"] = StackElement::ReplaceType;
        tagNames["conversion-rule"] = StackElement::ConversionRule;
        tagNames["modify-argument"] = StackElement::ModifyArgument;
        tagNames["remove-argument"] = StackElement::RemoveArgument;
        tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression;
        tagNames["template"] = StackElement::Template;
        tagNames["insert-template"] = StackElement::TemplateInstanceEnum;
        tagNames["replace"] = StackElement::Replace;
        tagNames["no-null-pointer"] = StackElement::NoNullPointers;
        tagNames["reference-count"] = StackElement::ReferenceCount;
    }

    bool startElement(const QString &namespaceURI, const QString &localName,
                      const QString &qName, const QXmlAttributes &atts);
    bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);

    QString errorString() const { return m_error; }
    bool error(const QXmlParseException &exception);
    bool fatalError(const QXmlParseException &exception);
    bool warning(const QXmlParseException &exception);

    bool characters(const QString &ch);

private:
    void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
                              QHash<QString, QString> *acceptedAttributes);

    TypeDatabase *m_database;
    StackElement* current;
    QString m_defaultPackage;
    QString m_defaultSuperclass;
    QString m_error;
    TypeEntry::CodeGeneration m_generate;

    EnumTypeEntry *m_current_enum;

    CodeSnipList m_code_snips;
    FunctionModificationList m_function_mods;
    FieldModificationList m_field_mods;

    QHash<QString, StackElement::ElementType> tagNames;
};

bool Handler::error(const QXmlParseException &e)
{
    qWarning("Error: line=%d, column=%d, message=%s\n",
             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
    return false;
}

bool Handler::fatalError(const QXmlParseException &e)
{
    qWarning("Fatal error: line=%d, column=%d, message=%s\n",
             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));

    return false;
}

bool Handler::warning(const QXmlParseException &e)
{
    qWarning("Warning: line=%d, column=%d, message=%s\n",
             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));

    return false;
}

void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
                                   QHash<QString, QString> *acceptedAttributes)
{
    Q_ASSERT(acceptedAttributes != 0);

    for (int i=0; i<atts.length(); ++i) {
        QString key = atts.localName(i).toLower();
        QString val = atts.value(i);

        if (!acceptedAttributes->contains(key)) {
            ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key));
        } else {
            (*acceptedAttributes)[key] = val;
        }
    }
}

bool Handler::endElement(const QString &, const QString &, const QString &)
{
    if (!current)
        return true;

    switch (current->type) {
    case StackElement::ObjectTypeEntry:
    case StackElement::ValueTypeEntry:
    case StackElement::InterfaceTypeEntry:
        {
            ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(current->entry);
            centry->setFunctionModifications(m_function_mods);
            centry->setFieldModifications(m_field_mods);
            centry->setCodeSnips(m_code_snips);
            if (centry->designatedInterface()) {
                centry->designatedInterface()->setCodeSnips(m_code_snips);
                centry->designatedInterface()->setFunctionModifications(m_function_mods);
            }
            m_code_snips = CodeSnipList();
            m_function_mods = FunctionModificationList();
            m_field_mods = FieldModificationList();
        }
        break;
    case StackElement::CustomMetaConstructor:
        {
            current->entry->setCustomConstructor(*current->value.customFunction);
            delete current->value.customFunction;
        }
        break;
    case StackElement::CustomMetaDestructor:
        {
            current->entry->setCustomDestructor(*current->value.customFunction);
            delete current->value.customFunction;
        }
        break;
    case StackElement::EnumTypeEntry:
        m_current_enum = 0;
        break;
    case StackElement::Template:
        m_database->addTemplate(current->value.templateEntry);
        break;
    case StackElement::TemplateInstanceEnum:
        if(current->parent->type == StackElement::InjectCode){
            m_code_snips.last().addTemplateInstance(current->value.templateInstance);
        }else if(current->parent->type == StackElement::Template){
            current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance);
        }else if(current->parent->type == StackElement::CustomMetaConstructor || current->parent->type == StackElement::CustomMetaConstructor){
            current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance);
        }else if(current->parent->type == StackElement::ConversionRule){
            m_function_mods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance);
        }else if(current->parent->type == StackElement::InjectCodeInFunction){
            m_function_mods.last().snips.last().addTemplateInstance(current->value.templateInstance);
        }
        break;
    default:
        break;
    }

    StackElement *child = current;
    current=current->parent;
    delete(child);

    return true;
}

bool Handler::characters(const QString &ch)
{
    if(current->type == StackElement::Template){
        current->value.templateEntry->addCode(ch);
        return true;
    }

    if (current->type == StackElement::CustomMetaConstructor || current->type == StackElement::CustomMetaDestructor){
        current->value.customFunction->addCode(ch);
        return true;
    }

    if (current->type == StackElement::ConversionRule){
        m_function_mods.last().argument_mods.last().conversion_rules.last().addCode(ch);
        return true;
    }

    if  (current->parent){
        if (current->type & StackElement::CodeSnipMask) {
            if (current->type & StackElement::CodeSnipMask) {
                switch (current->parent->type) {
                    case StackElement::Root:
                        ((TypeSystemTypeEntry *) current->parent->entry)->snips.last().addCode(ch);
                        break;
                    case StackElement::ModifyFunction:
                        m_function_mods.last().snips.last().addCode(ch);
                        break;
                    case StackElement::ObjectTypeEntry:
                    case StackElement::ValueTypeEntry:
                        m_code_snips.last().addCode(ch);
                        break;
                    default:
                        Q_ASSERT(false);
                };
            }
            return true;
        }
    }

    return true;
}

bool Handler::startElement(const QString &, const QString &n,
                           const QString &, const QXmlAttributes &atts)
{
    QString tagName = n.toLower();

    StackElement *element = new StackElement(current);

    if (!tagNames.contains(tagName)) {
        m_error = QString("Unknown tag name: '%1'").arg(tagName);
        return false;
    }

    element->type = tagNames[tagName];
    if (element->type & StackElement::TypeEntryMask) {
        if (current->type != StackElement::Root) {
            m_error = "Nested types not supported";
            return false;
        }

        QHash<QString, QString> attributes;
        attributes["name"] = QString();

        switch (element->type) {
        case StackElement::PrimitiveTypeEntry:
            attributes["java-name"] = QString();
            attributes["jni-name"] = QString();
            attributes["preferred-conversion"] = "yes";
            break;
        case StackElement::EnumTypeEntry:
            attributes["flags"] = "no";
            attributes["upper-bound"] = QString();
            attributes["lower-bound"] = QString();
            attributes["force-integer"] = "no";
            attributes["extensible"] = "no";

            break;
        
        case StackElement::ObjectTypeEntry:
        case StackElement::ValueTypeEntry:
            attributes["force-abstract"] = QString("no");
            attributes["deprecated"] = QString("no");
            // fall throooough
        case StackElement::InterfaceTypeEntry:
            attributes["default-superclass"] = m_defaultSuperclass;
            attributes["polymorphic-base"] = QString("no");
            attributes["polymorphic-id-expression"] = QString();
            attributes["java-name"] = QString();
            // fall through
        case StackElement::NamespaceTypeEntry:
            attributes["package"] = m_defaultPackage;
            attributes["expense-cost"] = "1";
            attributes["expense-limit"] = "none";
            break;
        default:
            ; // nada
        };

        fetchAttributeValues(tagName, atts, &attributes);

        QString name = attributes["name"];

        if (name.isEmpty()) {
            m_error = "no 'name' attribute specified";
            return false;
        }

        TypeEntry *tmp = m_database->findType(name);
        if (tmp != 0) {
            ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name));
        }

        switch (element->type) {
        case StackElement::PrimitiveTypeEntry:
            {
                QString java_name = attributes["java-name"];
                QString jni_name = attributes["jni-name"];
                QString preferred_conversion = attributes["preferred-conversion"].toLower();

                if (java_name.isEmpty())
                    java_name = name;
                if (jni_name.isEmpty())
                    jni_name = name;

                PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name);
                type->setCodeGeneration(m_generate);
                type->setJavaName(java_name);
                type->setJniName(jni_name);

                if (preferred_conversion == "yes") {
                    type->setPreferredConversion(true);
                } else if (preferred_conversion == "no") {
                    type->setPreferredConversion(false);
                } else {
                    QString debug = QString("Preferred conversion value '%1' not valid for '%2'. "
                                            "Will default to 'yes'.")
                                    .arg(preferred_conversion).arg(name);
                    ReportHandler::warning(debug);
                }

                element->entry = type;
            }
            break;
        case StackElement::EnumTypeEntry: {
            QStringList names = name.split(QLatin1String("::"));
            if (names.size() != 2) {
                ReportHandler::warning(QString("enum %1 is not on the pattern Qualifier::Name")
                                       .arg(name));
                break;
            }

            m_current_enum = new EnumTypeEntry(names.at(0), names.at(1));
            element->entry = m_current_enum;
            m_current_enum->setCodeGeneration(m_generate);
            m_current_enum->setJavaPackage(m_defaultPackage);
            m_current_enum->setUpperBound(attributes["upper-bound"]);
            m_current_enum->setLowerBound(attributes["lower-bound"]);
            m_current_enum->setForceInteger(attributes["force-integer"].toLower() == "yes");
            m_current_enum->setExtensible(attributes["extensible"].toLower() == "yes");

            // put in the flags parallel...
            if (!attributes["flags"].isEmpty() && attributes["flags"] != "no") {
                FlagsTypeEntry *ftype = new FlagsTypeEntry("QFlags<" + name + ">");
                ftype->setOriginator(m_current_enum);
                ftype->setOriginalName(attributes["flags"]);
                ftype->setCodeGeneration(m_generate);
                QString n = ftype->originalName();

                QStringList lst = n.split("::");
                if (lst.size() != 2) {
                    ReportHandler::warning(QString("flag %2 is not on pattern Qualifier::Name")
                                           .arg(n));
                } else if (lst.at(0) != m_current_enum->javaQualifier()) {
                    ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
                                           .arg(m_current_enum->javaQualifier())
                                           .arg(lst.at(0)));
                }

                ftype->setFlagsName(lst.at(1));
                m_current_enum->setFlags(ftype);

                m_database->addFlagsType(ftype);
                m_database->addType(ftype);
            }
            }
            break;

        case StackElement::InterfaceTypeEntry:
            {
                ObjectTypeEntry *otype = new ObjectTypeEntry(name);
                otype->setCodeGeneration(m_generate);
                InterfaceTypeEntry *itype =
                    new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(name));
                itype->setCodeGeneration(m_generate);
                otype->setDesignatedInterface(itype);
                itype->setOrigin(otype);
                element->entry = otype;
            }
            // fall through
        case StackElement::NamespaceTypeEntry:
            if (element->entry == 0) {
                element->entry = new NamespaceTypeEntry(name);
                element->entry->setCodeGeneration(m_generate);
            }
            // fall through
        case StackElement::ObjectTypeEntry:
            if (element->entry == 0) {
                element->entry = new ObjectTypeEntry(name);
                element->entry->setCodeGeneration(m_generate);
            }
            // fall through
        case StackElement::ValueTypeEntry:
            {
                if (element->entry == 0) {
                    element->entry = new ValueTypeEntry(name);
                    element->entry->setCodeGeneration(m_generate);
                }

                ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
                ctype->setJavaPackage(attributes["package"]);
                ctype->setDefaultSuperclass(attributes["default-superclass"]);

                QString javaName = attributes["java-name"];
                if (!javaName.isEmpty())
                    ctype->setJavaName(javaName);

                // The expense policy
                QString limit = attributes["expense-limit"];
                if (!limit.isEmpty() && limit != "none") {
                    ExpensePolicy ep;
                    ep.limit = limit.toInt();
                    ep.cost = attributes["expense-cost"];
                    ctype->setExpensePolicy(ep);
                }

                bool polymorphic = attributes["polymorphic-base"].toLower() == "yes"
                                   ? true : false;

                ctype->setIsPolymorphicBase(polymorphic);
                ctype->setPolymorphicIdValue(attributes["polymorphic-id-expression"]);

                if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) {
                    if (attributes["force-abstract"] == "yes")
                        ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
                    if (attributes["deprecated"] == "yes") 
                        ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
                }

                // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
                ctype = ctype->designatedInterface();
                if (ctype != 0)
                    ctype->setJavaPackage(attributes["package"]);

            }
            break;
        default:
            Q_ASSERT(false);
        };

        if (element->entry)
            m_database->addType(element->entry);
        else
            ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name));

    } else if (element->type != StackElement::None) {
        bool topLevel = element->type == StackElement::Root
      || element->type == StackElement::SuppressedWarning
      || element->type == StackElement::Rejection
      || element->type == StackElement::LoadTypesystem
      || element->type == StackElement::InjectCode
      || element->type == StackElement::Template;

        if (!topLevel && current->type == StackElement::Root) {
            m_error = QString("Tag requires parent: '%1'").arg(tagName);
            return false;
        }

        StackElement topElement = current==0 ? StackElement(0) : *current;
        element->entry = topElement.entry;

        QHash<QString, QString> attributes;
        switch (element->type) {
        case StackElement::Root:
            attributes["package"] = QString();
            attributes["default-superclass"] = QString();
            break;
        case StackElement::LoadTypesystem:
            attributes["name"] = QString();
            attributes["generate"] = "yes";
            break;
        case StackElement::NoNullPointers:
            attributes["default-value"] = QString();
            break;
        case StackElement::SuppressedWarning:
            attributes["text"] = QString();
            break;
        case StackElement::ReplaceDefaultExpression:
            attributes["with"] = QString();
            break;
        case StackElement::DefineOwnership:
            attributes["class"] = "java";
            attributes["owner"] = "";
            break;
        case StackElement::ModifyFunction:
            attributes["signature"] = QString();
            attributes["access"] = QString();
            attributes["remove"] = QString();
            attributes["rename"] = QString();
            attributes["deprecated"] = QString("no");
            break;
        case StackElement::ModifyArgument:
            attributes["index"] = QString();
          attributes["replace-value"] = QString();
            break;
        case StackElement::ModifyField:
            attributes["name"] = QString();
            attributes["write"] = "true";
            attributes["read"] = "true";
            break;
        case StackElement::Access:
            attributes["modifier"] = QString();
            break;
        case StackElement::Include:
            attributes["file-name"] = QString();
            attributes["location"] = QString();
            break;
        case StackElement::CustomMetaConstructor:
            attributes["name"] = topElement.entry->name().toLower() + "_create";
            attributes["param-name"] = "copy";
            break;
        case StackElement::CustomMetaDestructor:
            attributes["name"] = topElement.entry->name().toLower() + "_delete";
            attributes["param-name"] = "copy";
            break;
        case StackElement::ReplaceType:
            attributes["modified-type"] = QString();
            break;
        case StackElement::InjectCode:
            attributes["class"] = "java";
            attributes["position"] = "beginning";
            break;
        case StackElement::ConversionRule:
            attributes["class"] = "";
            break;
        case StackElement::RejectEnumValue:
            attributes["name"] = "";
            break;
        case StackElement::ArgumentMap:
            attributes["index"] = "1";
            attributes["meta-name"] = QString();
            break;
        case StackElement::Rename:
            attributes["to"] = QString();
            break;
        case StackElement::Rejection:
            attributes["class"] = "*";
            attributes["function-name"] = "*";
            attributes["field-name"] = "*";
            attributes["enum-name"] = "*";
            break;
        case StackElement::Removal:
            attributes["class"] = "all";
            break;
        case StackElement::Template:
            attributes["name"] = QString();
            break;
        case StackElement::TemplateInstanceEnum:
            attributes["name"] = QString();
            break;
        case StackElement::Replace:
            attributes["from"] = QString();
            attributes["to"] = QString();
            break;
        case StackElement::ReferenceCount:
            attributes["action"] = QString();
            attributes["variable-name"] = QString();
            attributes["thread-safe"] = QString("no");
            attributes["declare-variable"] = QString();
            attributes["access"] = QString("private");
            attributes["conditional"] = QString("");
            break;
        default:
            ; // nada
        };

        if (attributes.count() > 0)
            fetchAttributeValues(tagName, atts, &attributes);

        switch (element->type) {
        case StackElement::Root:
            m_defaultPackage = attributes["package"];
            m_defaultSuperclass = attributes["default-superclass"];
            element->type = StackElement::Root;
            element->entry = new TypeSystemTypeEntry(m_defaultPackage);
            TypeDatabase::instance()->addType(element->entry);
            break;
        case StackElement::LoadTypesystem:
            {
                QString name = attributes["name"];
                if (name.isEmpty()) {
                    m_error = "No typesystem name specified";
                    return false;
                }

                QString str_generate = attributes["generate"].toLower();

                bool generate;
                if (str_generate == "no") {
                    generate = false;
                } else if (str_generate == "yes") {
                    generate = true;
                } else {
                    m_error = "Use 'yes' or 'no' to indicate whether a typesystem should generate code";
                    return false;
                }

                if (!m_database->parseFile(name, generate)) {
                    m_error = QString("Failed to parse: '%1'").arg(name);
                    return false;
                }
            }
            break;
        case StackElement::RejectEnumValue: {
            if (!m_current_enum) {
                m_error = "<reject-enum-value> node must be used inside a <enum-type> node";
                return false;
            }
            QString name = attributes["name"];
            if (!name.isEmpty()) {
                m_current_enum->addEnumValueRejection(name);
            }

            } break;
        case StackElement::ReplaceType:
            {
                if (topElement.type != StackElement::ModifyArgument) {
                    m_error = "Type replacement can only be specified for argument modifications";
                    return false;
                }

                if (attributes["modified-type"].isEmpty()) {
                    m_error = "Type replacement requires 'modified-type' attribute";
                    return false;
                }

                m_function_mods.last().argument_mods.last().modified_type = attributes["modified-type"];
            }
            break;
        case StackElement::ConversionRule:
            {
                if (topElement.type != StackElement::ModifyArgument) {
                    m_error = "Conversion rules can only be specified for argument modification";
                    return false;
                }

                static QHash<QString, TypeSystem::Language> languageNames;
                if (languageNames.isEmpty()) {
                    languageNames["native"] = TypeSystem::NativeCode;
                    languageNames["shell"] = TypeSystem::ShellCode;
                }

                CodeSnip snip;
                QString languageAttribute = attributes["class"].toLower();
                TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
                if (lang == TypeSystem::NoLanguage) {
                    m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
                    return false;
                }

                snip.language = lang;
                m_function_mods.last().argument_mods.last().conversion_rules.append(snip);
            }

            break;
        case StackElement::ModifyArgument:
            {
                if (topElement.type != StackElement::ModifyFunction) {
                    m_error = QString::fromLatin1("argument modification requires function"
                                                  " modification as parent, was %1")
                              .arg(topElement.type, 0, 16);
                    return false;
                }

                QString index = attributes["index"];
                if (index == "return")
                    index = "0";
                else if (index == "this")
                    index = "-1";

                bool ok = false;
                int idx = index.toInt(&ok);
                if (!ok) {
                    m_error = QString("Cannot convert '%1' to integer").arg(index);
                    return false;
                }

            QString replace_value = attributes["replace-value"];

            if (!replace_value.isEmpty() && idx != 0) {
                m_error = QString("replace-value is only supported for return values (index=0).");
                return false;
            }

            ArgumentModification argumentModification = ArgumentModification(idx);
            argumentModification.replace_value = replace_value;
                m_function_mods.last().argument_mods.append(argumentModification);
            }
            break;
        case StackElement::NoNullPointers:
            {
                if (topElement.type != StackElement::ModifyArgument) {
                    m_error = "no-null-pointer requires argument modification as parent";
                    return false;
                }

                m_function_mods.last().argument_mods.last().no_null_pointers = true;
                if (m_function_mods.last().argument_mods.last().index == 0) {
                    m_function_mods.last().argument_mods.last().null_pointer_default_value = attributes["default-value"];
                } else if (!attributes["default-value"].isEmpty()) {
                    ReportHandler::warning("default values for null pointer guards are only effective for return values");
                }
            }
            break;
        case StackElement::DefineOwnership:
            {
                if (topElement.type != StackElement::ModifyArgument) {
                    m_error = "define-ownership requires argument modification as parent";
                    return false;
                }

                static QHash<QString, TypeSystem::Language> languageNames;
                if (languageNames.isEmpty()) {
                    languageNames["java"] = TypeSystem::JavaCode;
                    languageNames["shell"] = TypeSystem::ShellCode;
                }

                QString classAttribute = attributes["class"].toLower();
                TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
                if (lang == TypeSystem::NoLanguage) {
                    m_error = QString("unsupported class attribute: '%1'").arg(classAttribute);
                    return false;
                }

                static QHash<QString, TypeSystem::Ownership> ownershipNames;
                if (ownershipNames.isEmpty()) {
                    ownershipNames["java"] = TypeSystem::JavaOwnership;
                    ownershipNames["c++"] = TypeSystem::CppOwnership;
                    ownershipNames["default"] = TypeSystem::DefaultOwnership;
                }

                QString ownershipAttribute = attributes["owner"].toLower();
                TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
                if (owner == TypeSystem::InvalidOwnership) {
                    m_error = QString("unsupported owner attribute: '%1'").arg(ownershipAttribute);
                    return false;
                }

                m_function_mods.last().argument_mods.last().ownerships[lang] = owner;
            }
            break;
        case StackElement::SuppressedWarning:
            if (attributes["text"].isEmpty())
                ReportHandler::warning("Suppressed warning with no text specified");
            else
                m_database->addSuppressedWarning(attributes["text"]);
            break;
        case StackElement::ArgumentMap:
            {
                if (!(topElement.type & StackElement::CodeSnipMask)) {
                    m_error = "Argument maps requires code injection as parent";
                    return false;
                }

                bool ok;
                int pos = attributes["index"].toInt(&ok);
                if (!ok) {
                    m_error = QString("Can't convert position '%1' to integer")
                              .arg(attributes["position"]);
                    return false;
                }

                if (pos <= 0) {
                    m_error = QString("Argument position %1 must be a positive number").arg(pos);
                    return false;
                }

                QString meta_name = attributes["meta-name"];
                if (meta_name.isEmpty()) {
                    ReportHandler::warning("Empty meta name in argument map");
                }

                if (topElement.type == StackElement::InjectCodeInFunction) {
                    m_function_mods.last().snips.last().argumentMap[pos] = meta_name;
                } else {
                    ReportHandler::warning("Argument maps are only useful for injection of code "
                                           "into functions.");
                }
            }
            break;
        case StackElement::Removal:
            {
                if (topElement.type != StackElement::ModifyFunction) {
                    m_error = "Function modification parent required";
                    return false;
                }

                static QHash<QString, TypeSystem::Language> languageNames;
                if (languageNames.isEmpty()) {
                    languageNames["java"] = TypeSystem::JavaAndNativeCode;
                    languageNames["all"] = TypeSystem::All;
                }

                QString languageAttribute = attributes["class"].toLower();
                TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
                if (lang == TypeSystem::NoLanguage) {
                    m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
                    return false;
                }

                m_function_mods.last().removal = lang;
            }
            break;
        case StackElement::Rename:
        case StackElement::Access:
            {
                if (topElement.type != StackElement::ModifyField
                    && topElement.type != StackElement::ModifyFunction) {
                    m_error = "Function or field modification parent required";
                    return false;
                }

                Modification *mod = 0;
                if (topElement.type == StackElement::ModifyFunction)
                    mod = &m_function_mods.last();
                else
                    mod = &m_field_mods.last();

                QString modifier;
                if (element->type == StackElement::Rename) {
                    modifier = "rename";
                    QString renamed_to = attributes["to"];
                    if (renamed_to.isEmpty()) {
                        m_error = "Rename modifier requires 'to' attribute";
                        return false;
                    }

                    if (topElement.type == StackElement::ModifyFunction)
                        mod->setRenamedTo(renamed_to);
                    else
                        mod->setRenamedTo(renamed_to);
                } else {
                    modifier = attributes["modifier"].toLower();
                }

                if (modifier.isEmpty()) {
                    m_error = "No access modification specified";
                    return false;
                }

                static QHash<QString, FunctionModification::Modifiers> modifierNames;
                if (modifierNames.isEmpty()) {
                    modifierNames["private"] = Modification::Private;
                    modifierNames["public"] = Modification::Public;
                    modifierNames["protected"] = Modification::Protected;
                    modifierNames["friendly"] = Modification::Friendly;
                    modifierNames["rename"] = Modification::Rename;
                    modifierNames["final"] = Modification::Final;
                    modifierNames["non-final"] = Modification::NonFinal;
                }

                if (!modifierNames.contains(modifier)) {
                    m_error = QString("Unknown access modifier: '%1'").arg(modifier);
                    return false;
                }

                mod->modifiers |= modifierNames[modifier];
            }
            break;
        case StackElement::RemoveArgument:
            if (topElement.type != StackElement::ModifyArgument) {
                m_error = "Removing argument requires argument modification as parent";
                return false;
            }

            m_function_mods.last().argument_mods.last().removed = true;

            break;

        case StackElement::ModifyField:
            {
                QString name = attributes["name"];
                if (name.isEmpty())
                    break;
                FieldModification fm;
                fm.name = name;
                fm.modifiers = 0;

                QString read = attributes["read"];
                QString write = attributes["write"];

                if (read == "true") fm.modifiers |= FieldModification::Readable;
                if (write == "true") fm.modifiers |= FieldModification::Writable;

                m_field_mods << fm;
            }
            break;
        case StackElement::ModifyFunction:
            {
                if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
                    m_error = QString::fromLatin1("Modify function requires complex type as parent"
                                                  ", was=%1").arg(topElement.type, 0, 16);
                    return false;
                }
                QString signature = attributes["signature"];

                signature = QMetaObject::normalizedSignature(signature.toLocal8Bit().constData());
                if (signature.isEmpty()) {
                    m_error = "No signature for modified function";
                    return false;
                }

                FunctionModification mod;
                mod.signature = signature;

                QString access = attributes["access"].toLower();
                if (!access.isEmpty()) {
                    if (access == QLatin1String("private"))
                        mod.modifiers |= Modification::Private;
                    else if (access == QLatin1String("protected"))
                        mod.modifiers |= Modification::Protected;
                    else if (access == QLatin1String("public"))
                        mod.modifiers |= Modification::Public;
                    else if (access == QLatin1String("final"))
                        mod.modifiers |= Modification::Final;
                    else if (access == QLatin1String("non-final"))
                        mod.modifiers |= Modification::NonFinal;
                    else {
                        m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
                        return false;
                    }
                }

                if (attributes["deprecated"].toLower() == "yes") {
                    mod.modifiers |= Modification::Deprecated;
                }

                QString remove = attributes["remove"].toLower();
                if (!remove.isEmpty()) {
                    if (remove == QLatin1String("all"))
                        mod.removal = TypeSystem::All;
                    else if (remove == QLatin1String("java"))
                        mod.removal = TypeSystem::JavaAndNativeCode;
                    else {
                        m_error = QString::fromLatin1("Bad removal type '%1'").arg(remove);
                        return false;
                    }
                }

                QString rename = attributes["rename"];
                if (!rename.isEmpty()) {
                    mod.renamedToName = rename;
                    mod.modifiers |= Modification::Rename;
                }

                m_function_mods << mod;
            }
            break;
        case StackElement::ReplaceDefaultExpression:
            if (!(topElement.type & StackElement::ModifyArgument)) {
                m_error = "Replace default expression only allowed as child of argument modification";
                return false;
            }

            if (attributes["with"].isEmpty()) {
               m_error = "Default expression replaced with empty string. Use remove-default-expression instead.";
               return false;
            }

            m_function_mods.last().argument_mods.last().replaced_default_expression = attributes["with"];
            break;
        case StackElement::RemoveDefaultExpression:
            m_function_mods.last().argument_mods.last().removed_default_expression = true;
            break;
        case StackElement::CustomMetaConstructor:
        case StackElement::CustomMetaDestructor:
            {
                CustomFunction *func = new CustomFunction(attributes["name"]);
                func->param_name = attributes["param-name"];
                element->value.customFunction = func;
            }
            break;
        case StackElement::ReferenceCount:
            {
                if (topElement.type != StackElement::ModifyArgument) {
                    m_error = "reference-count must be child of modify-argument";
                    return false;
                }

                ReferenceCount rc;
                rc.threadSafe = (attributes["thread-safe"].toLower() == "yes");
                if (!rc.threadSafe && attributes["thread-safe"].toLower() != "no") {
                    m_error = "thread-safe attribute must be either 'yes' or 'no'";
                    return false;
                }

                static QHash<QString, ReferenceCount::Action> actions;
                if (actions.isEmpty()) {
                    actions["add"] = ReferenceCount::Add;
                    actions["add-all"] = ReferenceCount::AddAll;
                    actions["remove"] = ReferenceCount::Remove;
                    actions["set"] = ReferenceCount::Set;
                    actions["ignore"] = ReferenceCount::Ignore;
                }
                rc.action = actions.value(attributes["action"].toLower(), ReferenceCount::Invalid);

                rc.variableName = attributes["variable-name"];
                if (rc.action != ReferenceCount::Ignore && rc.variableName.isEmpty()) {
                    m_error = "variable-name attribute must be specified";
                    return false;
                }

                rc.declareVariable = attributes["declare-variable"];
                rc.conditional = attributes["conditional"];

                static QHash<QString, int> accessRights;
                if (accessRights.isEmpty()) {
                    accessRights["private"] = ReferenceCount::Private;
                    accessRights["public"] = ReferenceCount::Public;
                    accessRights["protected"] = ReferenceCount::Protected;
                    accessRights["friendly"] = ReferenceCount::Friendly;
                }
                rc.access = accessRights.value(attributes["access"].toLower(), 0);
                if (rc.access == 0) {
                    m_error = "unrecognized access value: " + attributes["access"];
                    return false;
                }

                if (rc.action == ReferenceCount::Invalid) {
                    m_error = "unrecognized value for action attribute. supported actions:";
                    foreach (QString action, actions.keys())
                        m_error += " " + action;
                }

                m_function_mods.last().argument_mods.last().referenceCounts.append(rc);
            }
            break;
        case StackElement::InjectCode:
            {
                if (((topElement.type & StackElement::ComplexTypeEntryMask) == 0)
                    && (topElement.type != StackElement::ModifyFunction)
                    && (topElement.type != StackElement::Root)) {
                    m_error = "wrong parent type for code injection";
                    return false;
                }

                static QHash<QString, TypeSystem::Language> languageNames;
                if (languageNames.isEmpty()) {
                    languageNames["java"] = TypeSystem::JavaCode;
                    languageNames["native"] = TypeSystem::NativeCode;
                    languageNames["shell"] = TypeSystem::ShellCode;
                    languageNames["shell-declaration"] = TypeSystem::ShellDeclaration;
                    languageNames["library-initializer"] = TypeSystem::PackageInitializer;
                }

                QString className = attributes["class"].toLower();
                if (!languageNames.contains(className)) {
                    m_error = QString("Invalid class specifier: '%1'").arg(className);
                    return false;
                }

                static QHash<QString, CodeSnip::Position> positionNames;
                if (positionNames.isEmpty()) {
                    positionNames["beginning"] = CodeSnip::Beginning;
                    positionNames["end"] = CodeSnip::End;
                }

                QString position = attributes["position"].toLower();
                if (!positionNames.contains(position)) {
                    m_error = QString("Invalid position: '%1'").arg(position);
                    return false;
                }

                CodeSnip snip;
                snip.language = languageNames[className];
                snip.position = positionNames[position];

                if (topElement.type == StackElement::ModifyFunction) {
                    FunctionModification mod = m_function_mods.last();
                    if (snip.language == TypeSystem::ShellDeclaration) {
                        m_error = "no function implementation in shell declaration in which to inject code";
                        return false;
                    }

                    m_function_mods.last().snips << snip;
                    element->type = StackElement::InjectCodeInFunction;
                } else if (topElement.type == StackElement::Root) {
                    ((TypeSystemTypeEntry *) element->entry)->snips << snip;

                } else if (topElement.type != StackElement::Root) {
                    m_code_snips << snip;
                }
            }
            break;
        case StackElement::Include:
            {
                QString location = attributes["location"].toLower();

                static QHash<QString, Include::IncludeType> locationNames;
                if (locationNames.isEmpty()) {
                    locationNames["global"] = Include::IncludePath;
                    locationNames["local"] = Include::LocalPath;
                    locationNames["java"] = Include::JavaImport;
                }

                if (!locationNames.contains(location)) {
                    m_error = QString("Location not recognized: '%1'").arg(location);
                    return false;
                }

                Include::IncludeType loc = locationNames[location];
                Include inc(loc, attributes["file-name"]);

                ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
                if (topElement.type & StackElement::ComplexTypeEntryMask) {
                    ctype->setInclude(inc);
                } else if (topElement.type == StackElement::ExtraIncludes) {
                    ctype->addExtraInclude(inc);
                } else {
                    m_error = "Only supported parents are complex types and extra-includes";
                    return false;
                }

                inc = ctype->include();
                IncludeList lst = ctype->extraIncludes();
                ctype = ctype->designatedInterface();
                if (ctype != 0) {
                    ctype->setExtraIncludes(lst);
                    ctype->setInclude(inc);
                }
            }
            break;
        case StackElement::Rejection:
            {
                QString cls = attributes["class"];
                QString function = attributes["function-name"];
                QString field = attributes["field-name"];
                QString enum_ = attributes["enum-name"];
                if (cls == "*" && function == "*" && field == "*" && enum_ == "*") {
                    m_error = "bad reject entry, neither 'class', 'function-name' nor "
                              "'field' specified";
                    return false;
                }
                m_database->addRejection(cls, function, field, enum_);
            }
            break;
        case StackElement::Template:
            element->value.templateEntry = new TemplateEntry(attributes["name"]);
            break;
        case StackElement::TemplateInstanceEnum:
            if (!(topElement.type & StackElement::CodeSnipMask) &&
                  (topElement.type != StackElement::Template) &&
                  (topElement.type != StackElement::CustomMetaConstructor) &&
                  (topElement.type != StackElement::CustomMetaDestructor) &&
                  (topElement.type != StackElement::ConversionRule))
            {
                m_error = "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule.";
                return false;
            }
            element->value.templateInstance = new TemplateInstance(attributes["name"]);
            break;
        case StackElement::Replace:
            if (topElement.type != StackElement::TemplateInstanceEnum) {
                m_error = "Can only insert replace rules into insert-template.";
                return false;
            }
            element->parent->value.templateInstance->addReplaceRule(attributes["from"],attributes["to"]);
            break;
        default:
            break; // nada
        };
    }

    current = element;
    return true;
}

TypeDatabase *TypeDatabase::instance()
{
    static TypeDatabase *db = new TypeDatabase();
    return db;
}

TypeDatabase::TypeDatabase() : m_suppressWarnings(true)
{
    addType(new StringTypeEntry("QString"));

    StringTypeEntry *e = new StringTypeEntry("QLatin1String");
    e->setPreferredConversion(false);
    addType(e);

    e = new StringTypeEntry("QStringRef");
    e->setPreferredConversion(false);
    addType(e);

    addType(new CharTypeEntry("QChar"));

    CharTypeEntry *c = new CharTypeEntry("QLatin1Char");
    c->setPreferredConversion(false);
    addType(c);

    {
        VariantTypeEntry *qvariant = new VariantTypeEntry("QVariant");
        qvariant->setCodeGeneration(TypeEntry::GenerateNothing);
        addType(qvariant);
    }

    addType(new ThreadTypeEntry());
    addType(new VoidTypeEntry());

    // Predefined containers...
    addType(new ContainerTypeEntry("QList", ContainerTypeEntry::ListContainer));
    addType(new ContainerTypeEntry("QStringList", ContainerTypeEntry::StringListContainer));
    addType(new ContainerTypeEntry("QLinkedList", ContainerTypeEntry::LinkedListContainer));
    addType(new ContainerTypeEntry("QVector", ContainerTypeEntry::VectorContainer));
    addType(new ContainerTypeEntry("QStack", ContainerTypeEntry::StackContainer));
    addType(new ContainerTypeEntry("QSet", ContainerTypeEntry::SetContainer));
    addType(new ContainerTypeEntry("QMap", ContainerTypeEntry::MapContainer));
    addType(new ContainerTypeEntry("QHash", ContainerTypeEntry::HashContainer));
    addType(new ContainerTypeEntry("QPair", ContainerTypeEntry::PairContainer));
    addType(new ContainerTypeEntry("QQueue", ContainerTypeEntry::QueueContainer));

    // Custom types...
    addType(new QModelIndexTypeEntry());
}

bool TypeDatabase::parseFile(const QString &filename, bool generate)
{
    QFile file(filename);
    Q_ASSERT(file.exists());
    QXmlInputSource source(&file);

    int count = m_entries.size();

    QXmlSimpleReader reader;
    Handler handler(this, generate);

    reader.setContentHandler(&handler);
    reader.setErrorHandler(&handler);

    bool ok = reader.parse(&source, false);

    int newCount = m_entries.size();

    ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries")
                               .arg(filename)
                               .arg(newCount - count));

    return ok;
}

QString PrimitiveTypeEntry::javaObjectName() const
{
    static QHash<QString, QString> table;
    if (table.isEmpty()) {
        table["boolean"] = "Boolean";
        table["byte"] = "Byte";
        table["char"] = "Character";
        table["short"] = "Short";
        table["int"] = "Integer";
        table["long"] = "Long";
        table["float"] = "Float";
        table["double"] = "Double";
    }
    Q_ASSERT(table.contains(javaName()));
    return table[javaName()];
}

ContainerTypeEntry *TypeDatabase::findContainerType(const QString &name)
{
    QString template_name = name;

    int pos = name.indexOf('<');
    if (pos > 0)
        template_name = name.left(pos);

    TypeEntry *type_entry = findType(template_name);
    if (type_entry && type_entry->isContainer())
        return static_cast<ContainerTypeEntry *>(type_entry);
    return 0;
}

PrimitiveTypeEntry *TypeDatabase::findJavaPrimitiveType(const QString &java_name)
{
    foreach (TypeEntry *e, m_entries.values()) {
        if (e && e->isPrimitive()) {
            PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(e);
            if (pe->javaName() == java_name && pe->preferredConversion())
                return pe;
        }
    }

    return 0;
}

IncludeList TypeDatabase::extraIncludes(const QString &className)
{
    ComplexTypeEntry *typeEntry = findComplexType(className);
    if (typeEntry != 0)
        return typeEntry->extraIncludes();
    else
        return IncludeList();
}



QString Include::toString() const
{
    if (type == IncludePath)
        return "#include <" + name + '>';
    else if (type == LocalPath)
        return "#include \"" + name + "\"";
    else
        return "import " + name + ";";
}

QString Modification::accessModifierString() const
{
    if (isPrivate()) return "private";
    if (isProtected()) return "protected";
    if (isPublic()) return "public";
    if (isFriendly()) return "friendly";
    return QString();
}

FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
{
    FunctionModificationList lst;
    for (int i=0; i<m_function_mods.count(); ++i) {
        FunctionModification mod = m_function_mods.at(i);
        if (mod.signature == signature)
            lst << mod;
    }

    return lst;
}

FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
{
    for (int i=0; i<m_field_mods.size(); ++i)
        if (m_field_mods.at(i).name == name)
            return m_field_mods.at(i);
    FieldModification mod;
    mod.name = name;
    mod.modifiers = FieldModification::Readable | FieldModification::Writable;
    return mod;
}

QString ContainerTypeEntry::javaPackage() const
{
    if (m_type == PairContainer)
        return "com.trolltech.qt";
    return "java.util";
}

QString ContainerTypeEntry::javaName() const
{

    switch (m_type) {
    case StringListContainer: return "List";
    case ListContainer: return "List";
    case LinkedListContainer: return "LinkedList";
    case VectorContainer: return "List";
    case StackContainer: return "Stack";
    case QueueContainer: return "Queue";
    case SetContainer: return "Set";
    case MapContainer: return "SortedMap";
        //     case MultiMapContainer: return "MultiMap";
    case HashContainer: return "HashMap";
        //     case MultiHashCollectio: return "MultiHash";
    case PairContainer: return "QPair";
    default:
        qWarning("bad type... %d", m_type);
        break;
    }
    return QString();
}

QString ContainerTypeEntry::qualifiedCppName() const
{
    if (m_type == StringListContainer)
        return "QStringList";
    return ComplexTypeEntry::qualifiedCppName();
}

QString EnumTypeEntry::jniName() const
{
    return "jint";
}

QString FlagsTypeEntry::jniName() const
{
    return "jint";
}

void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
{
    m_enum_redirections << EnumValueRedirection(rejected, usedValue);
}

QString EnumTypeEntry::enumValueRedirection(const QString &value) const
{
    for (int i=0; i<m_enum_redirections.size(); ++i)
        if (m_enum_redirections.at(i).rejected == value)
            return m_enum_redirections.at(i).used;
    return QString();
}

QString FlagsTypeEntry::qualifiedJavaName() const
{
    return javaPackage() + "." + m_enum->javaQualifier() + "." + javaName();
}


void TypeDatabase::addRejection(const QString &class_name, const QString &function_name,
                                const QString &field_name, const QString &enum_name)
{
    TypeRejection r;
    r.class_name = class_name;
    r.function_name = function_name;
    r.field_name = field_name;
    r.enum_name = enum_name;

    m_rejections << r;
}

bool TypeDatabase::isClassRejected(const QString &class_name)
{
    if (!m_rebuild_classes.isEmpty())
        return !m_rebuild_classes.contains(class_name);

    foreach (const TypeRejection &r, m_rejections)
        if (r.class_name == class_name && r.function_name == "*" && r.field_name == "*" && r.enum_name == "*") {
            return true;
        }
    return false;
}

bool TypeDatabase::isEnumRejected(const QString &class_name, const QString &enum_name)
{
    foreach (const TypeRejection &r, m_rejections) {
        if (r.enum_name == enum_name
            && (r.class_name == class_name || r.class_name == "*")) {
            return true;
        }
    }

    return false;
}

bool TypeDatabase::isFunctionRejected(const QString &class_name, const QString &function_name)
{
    foreach (const TypeRejection &r, m_rejections)
        if (r.function_name == function_name &&
            (r.class_name == class_name || r.class_name == "*"))
            return true;
    return false;
}


bool TypeDatabase::isFieldRejected(const QString &class_name, const QString &field_name)
{
    foreach (const TypeRejection &r, m_rejections)
        if (r.field_name == field_name &&
            (r.class_name == class_name || r.class_name == "*"))
            return true;
    return false;
}

FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const
{
    FlagsTypeEntry *fte = (FlagsTypeEntry *) m_entries.value(name);
    return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name);
}


/*!
 * The Visual Studio 2002 compiler doesn't support these symbols,
 * which our typedefs unforntuatly expand to.
 */
QString fixCppTypeName(const QString &name)
{
    if (name == "long long") return "qint64";
    else if (name == "unsigned long long") return "quint64";
    return name;
}

QString CodeSnip::formattedCode(const QString &_defaultIndent)
{
    QString returned;
    QStringList lst;
    foreach(CodeSnipFragment *codeFrag, codeList){
        lst = lst + codeFrag->code().split("\n");
    }

    QString defaultIndent(_defaultIndent);
    QString indent = defaultIndent;
    foreach (QString s, lst) {
        if (s.trimmed().isEmpty())
            continue ;

        if (s.trimmed().endsWith("}"))
            indent.chop(4);

        returned += indent + s.trimmed();

        indent = defaultIndent;
        if (!returned.endsWith(";") && !returned.endsWith("}"))
            indent += "    ";

        if (returned.endsWith("{"))
            defaultIndent += "    ";
        else if (returned.endsWith("}"))
            defaultIndent.chop(4);

        returned += "\n";
    }

    return returned;
}

QString TemplateInstance::expandCode() const{
    TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
    if(templateEntry){
        QString res = templateEntry->code();
        foreach(QString key, replaceRules.keys()){
            res.replace(key, replaceRules[key]);
        }
        return "// TEMPLATE - " + m_name + " - START" + res + "// TEMPLATE - " + m_name + " - END";
    }
    else{
        ReportHandler::warning("insert-template referring to non-existing template '" + m_name + "'");
    }
    return QString();
}


QString CodeSnipAbstract::code() const{
    QString res;
    foreach(CodeSnipFragment *codeFrag, codeList){
        res.append(codeFrag->code());
    }
    return res;
}

QString CodeSnipFragment::code() const{
    if(m_instance)
        return m_instance->expandCode();
    else
        return m_code;
}

Generated by  Doxygen 1.6.0   Back to index