Skip to content

Commit e9197ec

Browse files
usiemsmrbean-bremen
authored andcommitted
Create a global namespace wrapper for each package if required
This currently just contains global enums. The content of these wrappers will be added to the current package, and to the "Qt" package. Also look in global namespace wrappers for scope-less enum types
1 parent 182df8d commit e9197ec

11 files changed

+140
-32
lines changed

generator/abstractmetabuilder.cpp

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,28 @@ void AbstractMetaBuilder::sortLists()
391391
}
392392
}
393393

394+
AbstractMetaClass* AbstractMetaBuilder::getGlobalNamespace(const TypeEntry* typeEntry)
395+
{
396+
QString package = typeEntry->javaPackage();
397+
QString globalName = TypeDatabase::globalNamespaceClassName(typeEntry);
398+
399+
AbstractMetaClass* global = m_meta_classes.findClass(package + "." + globalName);
400+
if (!global) {
401+
ComplexTypeEntry* gte = new NamespaceTypeEntry(globalName);
402+
gte->setTargetLangPackage(typeEntry->javaPackage());
403+
gte->setCodeGeneration(typeEntry->codeGeneration());
404+
global = createMetaClass();
405+
global->setIsGlobalNamespace(true);
406+
global->setTypeEntry(gte);
407+
*global += AbstractMetaAttributes::Final;
408+
*global += AbstractMetaAttributes::Public;
409+
*global += AbstractMetaAttributes::Fake;
410+
411+
m_meta_classes << global;
412+
}
413+
return global;
414+
}
415+
394416
bool AbstractMetaBuilder::build()
395417
{
396418
Q_ASSERT(!m_file_name.isEmpty());
@@ -460,36 +482,21 @@ bool AbstractMetaBuilder::build()
460482
AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet<QString>());
461483

462484
if (meta_enum) {
463-
QString package = meta_enum->typeEntry()->javaPackage();
464-
QString globalName = TypeDatabase::globalNamespaceClassName(meta_enum->typeEntry());
465-
466-
AbstractMetaClass *global = m_meta_classes.findClass(package + "." + globalName);
467-
if (!global) {
468-
ComplexTypeEntry *gte = new ObjectTypeEntry(globalName);
469-
gte->setTargetLangPackage(meta_enum->typeEntry()->javaPackage());
470-
gte->setCodeGeneration(meta_enum->typeEntry()->codeGeneration());
471-
global = createMetaClass();
472-
global->setTypeEntry(gte);
473-
*global += AbstractMetaAttributes::Final;
474-
*global += AbstractMetaAttributes::Public;
475-
*global += AbstractMetaAttributes::Fake;
476-
477-
m_meta_classes << global;
478-
}
485+
AbstractMetaClass* global = getGlobalNamespace(meta_enum->typeEntry());
479486

480487
global->addEnum(meta_enum);
481-
meta_enum->setEnclosingClass(global);
482-
meta_enum->typeEntry()->setQualifier(globalName);
483488

484489
// Global enums should be public despite not having public
485490
// identifiers so we'll fix the original attributes here.
486491
meta_enum->setOriginalAttributes(meta_enum->attributes());
487-
}
488-
489492

493+
// global enums have their own include
494+
if (meta_enum->typeEntry()->include().isValid()) {
495+
global->typeEntry()->addExtraInclude(meta_enum->typeEntry()->include());
496+
}
497+
}
490498
}
491499

492-
493500
// Go through all typedefs to see if we have defined any
494501
// specific typedefs to be used as classes.
495502
TypeAliasList typeAliases = m_dom->typeAliases();

generator/abstractmetabuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class AbstractMetaBuilder
149149
private:
150150
void sortLists();
151151

152+
AbstractMetaClass* getGlobalNamespace(const TypeEntry* typeEntry);
153+
152154
QString m_file_name;
153155

154156
AbstractMetaClassList m_meta_classes;

generator/abstractmetalang.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ class AbstractMetaClass : public AbstractMetaAttributes
676676
m_has_clone_operator(false),
677677
m_is_type_alias(false),
678678
m_has_actual_declaration(false),
679+
m_is_global_namespace(false),
679680
m_qDebug_stream_function(0)
680681
{
681682
}
@@ -801,6 +802,9 @@ class AbstractMetaClass : public AbstractMetaAttributes
801802
void setHasActualDeclaration(bool on) { m_has_actual_declaration = on; }
802803
bool hasActualDeclaration() const { return m_has_actual_declaration; }
803804

805+
void setIsGlobalNamespace(bool on) { m_is_global_namespace = on; }
806+
bool isGlobalNamespace() const { return m_is_global_namespace; }
807+
804808
QString getDefaultNonZeroFunction() const;
805809

806810
void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; }
@@ -862,7 +866,8 @@ class AbstractMetaClass : public AbstractMetaAttributes
862866
uint m_has_clone_operator :1;
863867
uint m_is_type_alias : 1;
864868
uint m_has_actual_declaration : 1;
865-
uint m_reserved : 17;
869+
uint m_is_global_namespace : 1;
870+
uint m_reserved : 16;
866871
QString m_destructor_exception;
867872

868873
const AbstractMetaClass *m_enclosing_class{};

generator/setupgenerator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ void SetupGenerator::generate()
337337
}
338338
if (cls->isQObject()) {
339339
s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << qtPackageName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
340+
} else if (cls->isGlobalNamespace()) {
341+
s << "PythonQt::priv()->registerGlobalNamespace(\"" << cls->qualifiedCppName() << "\", \"" << qtPackageName << "\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">, PythonQtWrapper_" << cls->name() << "::staticMetaObject, module); " << endl;
340342
} else {
341343
QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
342344
s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << qtPackageName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;

generator/shellgenerator.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@
5050
bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
5151
{
5252
uint cg = meta_class->typeEntry()->codeGeneration();
53-
// ignore the "Global" namespace, which contains the QtMsgType enum
54-
if (meta_class->name().startsWith("Global")) return false;
5553
return ((cg & TypeEntry::GenerateCode) != 0);
5654
}
5755

generator/shellheadergenerator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ void ShellHeaderGenerator::write(QTextStream& s, const AbstractMetaClass* meta_c
312312
bool isEnumClass = enum1->typeEntry()->isEnumClass();
313313
s << "enum " << (isEnumClass ? "class " : "") << enum1->name() << "{" << endl;
314314
bool first = true;
315-
QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName();
315+
QString scope = meta_class->isGlobalNamespace() ? QString() :
316+
(enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName());
316317
if (isEnumClass) {
317318
scope += "::" + enum1->name();
318319
}

generator/typesystem.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,8 +1835,9 @@ FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const
18351835
return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name);
18361836
}
18371837

1838-
QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) {
1839-
return QLatin1String("Global");
1838+
QString TypeDatabase::globalNamespaceClassName(const TypeEntry * entry)
1839+
{
1840+
return "Qt" + entry->javaPackage().split('.').back();
18401841
}
18411842

18421843

src/PythonQt.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,73 @@ void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentT
20602060
}
20612061
}
20622062

2063+
namespace {
2064+
2065+
void addObjectToPackage(PyObject* obj, const char* name, const char* packageName, PyObject* package)
2066+
{
2067+
if (PyModule_AddObject(package, name, obj) < 0) {
2068+
Py_DECREF(obj);
2069+
std::cerr << "failed to add " << name << " to " << packageName << "\n";
2070+
}
2071+
}
2072+
2073+
};
2074+
2075+
void PythonQtPrivate::registerGlobalNamespace(const char* typeName, const char* packageName, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module)
2076+
{
2077+
registerCPPClass(typeName, "", packageName, wrapperCreator, nullptr, module, 0);
2078+
2079+
PyObject* package = module ? module : PythonQt::priv()->packageByName(packageName);
2080+
PythonQtClassInfo* classInfo = PythonQt::priv()->getClassInfo(typeName);
2081+
PyObject* globalNamespace = classInfo->pythonQtClassWrapper();
2082+
2083+
// Collect the names of global methods
2084+
QSet<QByteArray> methodNames;
2085+
for (int i = metaObject.methodOffset(); i < metaObject.methodCount(); i++) {
2086+
methodNames.insert(metaObject.method(i).name());
2087+
}
2088+
QByteArray staticPrefix = "static_" + QByteArray(typeName) + "_"; // every static method starts with this string
2089+
for (auto name: methodNames) {
2090+
if (name.startsWith(staticPrefix)) { // non-static methods wouldn't work (and should not exists)
2091+
name = name.mid(staticPrefix.length());
2092+
PyObject* obj = PyObject_GetAttrString(globalNamespace, name.constData());
2093+
if (obj) {
2094+
addObjectToPackage(obj, name, packageName, package);
2095+
}
2096+
else {
2097+
std::cerr << "method not found " << name.constData() << " in " << typeName << std::endl;
2098+
}
2099+
}
2100+
}
2101+
2102+
// Global enums
2103+
for (int i = metaObject.enumeratorOffset(); i < metaObject.enumeratorCount(); i++) {
2104+
QMetaEnum metaEnum = metaObject.enumerator(i);
2105+
PyObject* obj = PyObject_GetAttrString(globalNamespace, metaEnum.name());
2106+
if (obj) {
2107+
addObjectToPackage(obj, metaEnum.name(), packageName, package);
2108+
}
2109+
else {
2110+
std::cerr << "enum type not found " << metaEnum.name() << " in " << typeName << std::endl;
2111+
}
2112+
#if QT_VERSION > 0x050800
2113+
bool isScoped = metaEnum.isScoped();
2114+
#else
2115+
bool isScoped = false;
2116+
#endif
2117+
if (!isScoped) {
2118+
for (int j = 0; j < metaEnum.keyCount(); j++) {
2119+
QByteArray key = PythonQtClassInfo::escapeReservedNames(metaEnum.key(j));
2120+
int value = metaEnum.value(j);
2121+
PyObject* obj = PyInt_FromLong(value);
2122+
addObjectToPackage(obj, key, packageName, package);
2123+
}
2124+
}
2125+
}
2126+
2127+
PythonQtClassInfo::addGlobalNamespaceWrapper(classInfo);
2128+
}
2129+
20632130
PyObject* PythonQtPrivate::packageByName(const char* name)
20642131
{
20652132
if (name==nullptr || name[0]==0) {

src/PythonQt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,9 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
742742
*/
743743
void registerCPPClass(const char* typeName, const char* parentTypeName = nullptr, const char* package = nullptr, PythonQtQObjectCreatorFunctionCB* wrapperCreator = nullptr, PythonQtShellSetInstanceWrapperCB* shell = nullptr, PyObject* module = nullptr, int typeSlots = 0);
744744

745+
//! Same as above, but all enums of the created wrapper will also be added to the given package and to the "Qt" package
746+
void registerGlobalNamespace(const char* typeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, const QMetaObject& metaObject, PyObject* module = nullptr);
747+
745748
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
746749
//! and it will register the classes when it first sees a pointer to such a derived class
747750
void registerQObjectClassNames(const QStringList& names);

src/PythonQtClassInfo.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949

5050
QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
5151

52+
// List of registered global namespace wrappers that might contain a top-level enum definition
53+
QList<PythonQtClassInfo*> PythonQtClassInfo::_globalNamespaceWrappers;
54+
5255
// List of words that are reserved in Python, but not in C++, so they need escaping
5356
QSet<QByteArray> PythonQtClassInfo::_reservedNames{
5457
"None", "True", "False"
@@ -851,11 +854,20 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtCla
851854
return nullptr;
852855
}
853856
}
857+
PyObject* enumWrapper = nullptr;
854858
if (localScope) {
855-
return localScope->findEnumWrapper(name);
856-
} else {
857-
return nullptr;
859+
enumWrapper = localScope->findEnumWrapper(name);
860+
}
861+
if (!enumWrapper) {
862+
// it might be a top-level enum - search in all currently registered global namespace wrappers
863+
for (PythonQtClassInfo* globalWrapper : _globalNamespaceWrappers) {
864+
enumWrapper = globalWrapper->findEnumWrapper(name);
865+
if (enumWrapper) {
866+
break;
867+
}
868+
}
858869
}
870+
return enumWrapper;
859871
}
860872

861873
// required for the code below (for versions before Qt 6)
@@ -1033,6 +1045,11 @@ QByteArray PythonQtClassInfo::escapeReservedNames(const QByteArray& name)
10331045
}
10341046
}
10351047

1048+
void PythonQtClassInfo::addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper)
1049+
{
1050+
_globalNamespaceWrappers.insert(0, namespaceWrapper);
1051+
}
1052+
10361053
void PythonQtClassInfo::updateRefCountingCBs()
10371054
{
10381055
if (!_refCallback) {

src/PythonQtClassInfo.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,10 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
239239

240240
//! Sometimes enum values use a reserved name in Python. In this case
241241
//! replace it with something that is not reserved
242-
QByteArray escapeReservedNames(const QByteArray& name);
242+
static QByteArray escapeReservedNames(const QByteArray& name);
243+
244+
//! Add a wrapper that contains global enums
245+
static void addGlobalNamespaceWrapper(PythonQtClassInfo* namespaceWrapper);
243246

244247
private:
245248
void updateRefCountingCBs();
@@ -304,7 +307,9 @@ class PYTHONQT_EXPORT PythonQtClassInfo {
304307
bool _searchPolymorphicHandlerOnParent;
305308
bool _searchRefCountCB;
306309

307-
static QSet<QByteArray> _reservedNames;
310+
static QList<PythonQtClassInfo*> _globalNamespaceWrappers;
311+
312+
static QSet<QByteArray> _reservedNames;
308313
};
309314

310315
//---------------------------------------------------------------

0 commit comments

Comments
 (0)