Mercurial > projects > qtd
diff generator/metainfogenerator.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 1349940724eb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generator/metainfogenerator.cpp Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,808 @@ +/**************************************************************************** +** +** 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); + + QString pro_file_name = cls->package().replace(".", "_") + "/" + cls->package().replace(".", "_") + ".pri"; + priGenerator->addSource(pro_file_name, 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); + + QString pro_file_name = cls->package().replace(".", "_") + "/" + cls->package().replace(".", "_") + ".pri"; + priGenerator->addHeader(pro_file_name, 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; + + QString pro_file_name = QString(package).replace(".", "_"); + + priGenerator->addSource(pro_file_name + "/" + pro_file_name + ".pri", "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; + } + +}