/**************************************************************************** ** ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt Script Generator project on Qt Labs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "setupgenerator.h" #include "shellgenerator.h" #include "reporthandler.h" #include "fileout.h" //#define Q_SCRIPT_LAZY_GENERATOR void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls) { packHash[package].append(cls); } void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, QSet ®isteredTypeNames); bool hasDefaultConstructor(const AbstractMetaClass *meta_class); static QStringList getOperatorCodes(const AbstractMetaClass* cls) { QSet operatorCodes; AbstractMetaFunctionList returned; AbstractMetaFunctionList functions = cls->functions(); foreach (AbstractMetaFunction *function, functions) { if (function->originalName().startsWith("operator")) { QString op = function->originalName().mid(8); operatorCodes.insert(op); } } QSet r; foreach(QString op, operatorCodes.toList()) { if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") { r.insert("PythonQt::Type_RichCompare"); } else if (op == "+") { r.insert("PythonQt::Type_Add"); } else if (op == "-") { r.insert("PythonQt::Type_Subtract"); } else if (op == "/") { r.insert("PythonQt::Type_Divide"); } else if (op == "*") { r.insert("PythonQt::Type_Multiply"); } else if (op == "%") { r.insert("PythonQt::Type_Mod"); } else if (op == "&") { r.insert("PythonQt::Type_And"); } else if (op == "|") { r.insert("PythonQt::Type_Or"); } else if (op == "^") { r.insert("PythonQt::Type_Xor"); } else if (op == "~") { r.insert("PythonQt::Type_Invert"); } else if (op == "+=") { r.insert("PythonQt::Type_InplaceAdd"); } else if (op == "-=") { r.insert("PythonQt::Type_InplaceSubtract"); } else if (op == "/=") { r.insert("PythonQt::Type_InplaceDivide"); } else if (op == "*=") { r.insert("PythonQt::Type_InplaceMultiply"); } else if (op == "%=") { r.insert("PythonQt::Type_InplaceMod"); } else if (op == "&=") { r.insert("PythonQt::Type_InplaceAnd"); } else if (op == "|=") { r.insert("PythonQt::Type_InplaceOr"); } else if (op == "^=") { r.insert("PythonQt::Type_InplaceXor"); } } if (cls->hasDefaultIsNull()) { r.insert("PythonQt::Type_NonZero"); } QStringList result = r.toList(); return result; } static bool class_less_than(const AbstractMetaClass *a, const AbstractMetaClass *b) { return a->name() < b->name(); } void SetupGenerator::generate() { AbstractMetaClassList classes_with_polymorphic_id; { QHashIterator > pack(packHash); while (pack.hasNext()) { pack.next(); QList list = pack.value(); foreach (const AbstractMetaClass *cls, list) { if (cls->typeEntry()->isPolymorphicBase()) { classes_with_polymorphic_id.append((AbstractMetaClass*)cls); } } } } qSort(classes_with_polymorphic_id.begin(), classes_with_polymorphic_id.end(), class_less_than); QHashIterator > pack(packHash); while (pack.hasNext()) { pack.next(); QList list = pack.value(); if (list.isEmpty()) continue; qSort(list.begin(), list.end(), class_less_than); QString packKey = pack.key(); QString packName = pack.key(); QStringList components = packName.split("_"); if ((components.size() > 2) && (components.at(0) == "com") && (components.at(1) == "trolltech")) { // kill com.trolltech in key components.removeAt(0); components.removeAt(0); } QString shortPackName; foreach (QString comp, components) { comp[0] = comp[0].toUpper(); shortPackName += comp; } // add missing camel case (workaround..) if (shortPackName == "QtWebkit") { shortPackName = "QtWebKit"; } else if (shortPackName == "QtXmlpatterns") { shortPackName = "QtXmlPatterns"; } else if (shortPackName == "QtOpengl") { shortPackName = "QtOpenGL"; } else if (shortPackName == "QtUitools") { shortPackName = "QtUiTools"; } { QString fileName(packName + "/" + packKey + "_init.cpp"); FileOut initFile(m_out_dir + "/generated_cpp/" + fileName); ReportHandler::debugSparse(QString("generating: %1").arg(fileName)); QTextStream &s = initFile.stream; s << "#include " << endl; for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) { s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl; } s << endl; QStringList polymorphicHandlers; if (!packName.endsWith("_builtin")) { polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list); s << endl; } // declare individual class creation functions s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl; if (shortPackName.endsWith("Builtin")) { shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin")); } QStringList cppClassNames; foreach (const AbstractMetaClass *cls, list) { QString shellCreator; if (cls->generateShellClass()) { shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">"; } else { shellCreator = ", NULL"; } QString operatorCodes = getOperatorCodes(cls).join("|"); if (operatorCodes.isEmpty()) { operatorCodes = "0"; } if (cls->isQObject()) { s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } else { QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObjectname() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; } foreach(AbstractMetaClass* interface, cls->interfaces()) { // the interface might be our own class... (e.g. QPaintDevice) if (interface->qualifiedCppName() != cls->qualifiedCppName()) { s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<qualifiedCppName()<<">());" << endl; } } } s << endl; foreach (QString handler, polymorphicHandlers) { s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl; } s << "}"; s << endl; } } } QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package, const AbstractMetaClassList &polybase, QList& allClasses) { QStringList handlers; foreach (AbstractMetaClass *cls, polybase) { const ComplexTypeEntry *centry = cls->typeEntry(); if (!centry->isPolymorphicBase()) continue; bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem"); bool first = true; foreach (const AbstractMetaClass *clazz, allClasses) { bool inherits = false; if (isGraphicsItem) { const AbstractMetaClass *currentClazz = clazz; while (!inherits && currentClazz) { foreach(AbstractMetaClass* interfaze, currentClazz->interfaces()) { if (interfaze->qualifiedCppName()=="QGraphicsItem") { inherits = true; break; } } currentClazz = currentClazz->baseClass(); } } else { inherits = clazz->inheritsFrom(cls); } if (clazz->package() == package && inherits) { if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) { // On first find, open the function if (first) { first = false; QString handler = cls->name(); handlers.append(handler); s << "static void* polymorphichandler_" << handler << "(const void *ptr, const char **class_name)" << endl << "{" << endl << " Q_ASSERT(ptr != 0);" << endl << " " << cls->qualifiedCppName() << " *object = (" << cls->qualifiedCppName() << " *)ptr;" << endl; } // For each, add case label QString polyId = clazz->typeEntry()->polymorphicIdValue(); s << " if (" << polyId.replace("%1", "object") << ") {" << endl << " *class_name = \"" << clazz->name() << "\";" << endl << " return (" << clazz->qualifiedCppName() << "*)object;" << 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 NULL;" << endl << "}" << endl; } } return handlers; }