setupgenerator.cpp
306 lines
| 10.9 KiB
| text/x-c
|
CppLexer
/ generator / setupgenerator.cpp
florianlink
|
r10 | /**************************************************************************** | ||
** | ||||
florianlink
|
r87 | ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). | ||
** All rights reserved. | ||||
** Contact: Nokia Corporation (qt-info@nokia.com) | ||||
florianlink
|
r10 | ** | ||
florianlink
|
r87 | ** This file is part of the Qt Script Generator project on Qt Labs. | ||
florianlink
|
r10 | ** | ||
florianlink
|
r87 | ** $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. | ||||
florianlink
|
r10 | ** | ||
florianlink
|
r87 | ** 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. | ||||
florianlink
|
r10 | ** | ||
florianlink
|
r87 | ** 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$ | ||||
florianlink
|
r10 | ** | ||
****************************************************************************/ | ||||
#include "setupgenerator.h" | ||||
florianlink
|
r24 | #include "shellgenerator.h" | ||
florianlink
|
r10 | #include "reporthandler.h" | ||
#include "fileout.h" | ||||
//#define Q_SCRIPT_LAZY_GENERATOR | ||||
florianlink
|
r93 | void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls) | ||
florianlink
|
r10 | { | ||
florianlink
|
r93 | packHash[package].append(cls); | ||
florianlink
|
r10 | } | ||
void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, | ||||
QSet<QString> ®isteredTypeNames); | ||||
bool hasDefaultConstructor(const AbstractMetaClass *meta_class); | ||||
florianlink
|
r119 | static QStringList getOperatorCodes(const AbstractMetaClass* cls) { | ||
QSet<QString> 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<QString> 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; | ||||
} | ||||
florianlink
|
r131 | static bool class_less_than(const AbstractMetaClass *a, const AbstractMetaClass *b) | ||
{ | ||||
return a->name() < b->name(); | ||||
} | ||||
florianlink
|
r10 | void SetupGenerator::generate() | ||
{ | ||||
florianlink
|
r29 | AbstractMetaClassList classes_with_polymorphic_id; | ||
{ | ||||
florianlink
|
r10 | QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash); | ||
while (pack.hasNext()) { | ||||
florianlink
|
r29 | pack.next(); | ||
QList<const AbstractMetaClass*> list = pack.value(); | ||||
foreach (const AbstractMetaClass *cls, list) { | ||||
if (cls->typeEntry()->isPolymorphicBase()) { | ||||
classes_with_polymorphic_id.append((AbstractMetaClass*)cls); | ||||
florianlink
|
r10 | } | ||
florianlink
|
r29 | } | ||
} | ||||
} | ||||
florianlink
|
r131 | qSort(classes_with_polymorphic_id.begin(), classes_with_polymorphic_id.end(), class_less_than); | ||
florianlink
|
r29 | |||
QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash); | ||||
while (pack.hasNext()) { | ||||
pack.next(); | ||||
QList<const AbstractMetaClass*> list = pack.value(); | ||||
if (list.isEmpty()) | ||||
continue; | ||||
florianlink
|
r131 | qSort(list.begin(), list.end(), class_less_than); | ||
florianlink
|
r29 | |||
QString packKey = pack.key(); | ||||
QString packName = pack.key(); | ||||
florianlink
|
r93 | QStringList components = packName.split("_"); | ||
florianlink
|
r29 | if ((components.size() > 2) && (components.at(0) == "com") | ||
&& (components.at(1) == "trolltech")) { | ||||
// kill com.trolltech in key | ||||
components.removeAt(0); | ||||
components.removeAt(0); | ||||
} | ||||
florianlink
|
r12 | |||
florianlink
|
r29 | 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"; | ||||
} | ||||
florianlink
|
r12 | |||
florianlink
|
r29 | { | ||
florianlink
|
r162 | QString fileName(packName + "/" + packKey + "_init.cpp"); | ||
FileOut initFile(m_out_dir + "/generated_cpp/" + fileName); | ||||
ReportHandler::debugSparse(QString("generating: %1").arg(fileName)); | ||||
florianlink
|
r29 | QTextStream &s = initFile.stream; | ||
florianlink
|
r10 | |||
florianlink
|
r29 | s << "#include <PythonQt.h>" << endl; | ||
florianlink
|
r92 | 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; | ||||
florianlink
|
r29 | } | ||
s << endl; | ||||
florianlink
|
r93 | QStringList polymorphicHandlers; | ||
if (!packName.endsWith("_builtin")) { | ||||
florianlink
|
r131 | polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list); | ||
florianlink
|
r93 | s << endl; | ||
} | ||||
florianlink
|
r29 | // declare individual class creation functions | ||
florianlink
|
r108 | s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl; | ||
florianlink
|
r93 | |||
if (shortPackName.endsWith("Builtin")) { | ||||
florianlink
|
r94 | shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin")); | ||
florianlink
|
r93 | } | ||
florianlink
|
r29 | QStringList cppClassNames; | ||
foreach (const AbstractMetaClass *cls, list) { | ||||
QString shellCreator; | ||||
if (cls->generateShellClass()) { | ||||
shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">"; | ||||
florianlink
|
r108 | } else { | ||
shellCreator = ", NULL"; | ||||
florianlink
|
r29 | } | ||
florianlink
|
r119 | QString operatorCodes = getOperatorCodes(cls).join("|"); | ||
if (operatorCodes.isEmpty()) { | ||||
operatorCodes = "0"; | ||||
} | ||||
florianlink
|
r29 | if (cls->isQObject()) { | ||
florianlink
|
r119 | s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; | ||
florianlink
|
r29 | } else { | ||
QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():""; | ||||
florianlink
|
r119 | s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl; | ||
florianlink
|
r29 | } | ||
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() <<","<<interface->qualifiedCppName()<<">());" << endl; | ||||
} | ||||
} | ||||
} | ||||
s << endl; | ||||
foreach (QString handler, polymorphicHandlers) { | ||||
s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl; | ||||
} | ||||
s << "}"; | ||||
s << endl; | ||||
} | ||||
} | ||||
} | ||||
florianlink
|
r10 | |||
florianlink
|
r29 | QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package, | ||
florianlink
|
r131 | const AbstractMetaClassList &polybase, QList<const AbstractMetaClass*>& allClasses) | ||
florianlink
|
r29 | { | ||
QStringList handlers; | ||||
florianlink
|
r131 | foreach (AbstractMetaClass *cls, polybase) { | ||
florianlink
|
r29 | const ComplexTypeEntry *centry = cls->typeEntry(); | ||
if (!centry->isPolymorphicBase()) | ||||
continue; | ||||
bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem"); | ||||
bool first = true; | ||||
florianlink
|
r131 | foreach (const AbstractMetaClass *clazz, allClasses) { | ||
florianlink
|
r29 | bool inherits = false; | ||
if (isGraphicsItem) { | ||||
florianlink
|
r170 | const AbstractMetaClass *currentClazz = clazz; | ||
while (!inherits && currentClazz) { | ||||
foreach(AbstractMetaClass* interfaze, currentClazz->interfaces()) { | ||||
if (interfaze->qualifiedCppName()=="QGraphicsItem") { | ||||
inherits = true; | ||||
break; | ||||
} | ||||
florianlink
|
r10 | } | ||
florianlink
|
r170 | currentClazz = currentClazz->baseClass(); | ||
florianlink
|
r29 | } | ||
} else { | ||||
inherits = clazz->inheritsFrom(cls); | ||||
} | ||||
if (clazz->package() == package && inherits) { | ||||
florianlink
|
r170 | if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) { | ||
florianlink
|
r29 | // On first find, open the function | ||
if (first) { | ||||
first = false; | ||||
QString handler = cls->name(); | ||||
handlers.append(handler); | ||||
s << "static void* polymorphichandler_" << handler | ||||
florianlink
|
r162 | << "(const void *ptr, const char **class_name)" << endl | ||
florianlink
|
r29 | << "{" << endl | ||
<< " Q_ASSERT(ptr != 0);" << endl | ||||
<< " " << cls->qualifiedCppName() << " *object = (" | ||||
<< cls->qualifiedCppName() << " *)ptr;" << endl; | ||||
florianlink
|
r10 | } | ||
florianlink
|
r12 | |||
florianlink
|
r29 | // 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); | ||||
florianlink
|
r10 | } | ||
florianlink
|
r29 | } | ||
florianlink
|
r10 | } | ||
florianlink
|
r29 | |||
// Close the function if it has been opened | ||||
if (!first) { | ||||
s << " return NULL;" << endl | ||||
<< "}" << endl; | ||||
} | ||||
} | ||||
return handlers; | ||||
florianlink
|
r10 | } | ||