Skip to content

Commit ef1c51e

Browse files
author
florianlink
committed
added support for operators and rich compare
git-svn-id: http://svn.code.sf.net/p/pythonqt/code/trunk@156 ea8d5007-eb21-0410-b261-ccb3ea6e24a9
1 parent b3d895b commit ef1c51e

11 files changed

+409
-81
lines changed

generator/abstractmetabuilder.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ QString rename_operator(const QString &oper)
7979
operator_names->insert("&", "__and__");
8080
operator_names->insert("|", "__or__");
8181
operator_names->insert("^", "__xor__");
82-
operator_names->insert("~", "__negate__");
82+
operator_names->insert("~", "__invert__");
8383
operator_names->insert("<<", "__lshift__");
8484
operator_names->insert(">>", "__rshift__");
8585

@@ -106,12 +106,12 @@ QString rename_operator(const QString &oper)
106106
operator_names->insert("--", "decrement");
107107

108108
// compare
109-
operator_names->insert("<", "less");
110-
operator_names->insert(">", "greater");
111-
operator_names->insert("<=", "less_or_equal");
112-
operator_names->insert(">=", "greater_or_equal");
113-
operator_names->insert("!=", "not_equal");
114-
operator_names->insert("==", "equal");
109+
operator_names->insert("<", "__lt__");
110+
operator_names->insert(">", "__gt__");
111+
operator_names->insert("<=", "__le__");
112+
operator_names->insert(">=", "__ge__");
113+
operator_names->insert("!=", "__ne__");
114+
operator_names->insert("==", "__eq__");
115115

116116
// other
117117
operator_names->insert("[]", "subscript");

generator/abstractmetalang.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,16 @@ AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &
849849
return returned;
850850
}
851851

852+
bool AbstractMetaClass::hasDefaultIsNull() const
853+
{
854+
foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isNull")) {
855+
if (fun->actualMinimumArgumentCount()==0) {
856+
return true;
857+
}
858+
}
859+
return false;
860+
}
861+
852862
/*******************************************************************************
853863
* Returns all reference count modifications for any function in the class
854864
*/

generator/abstractmetalang.h

+2
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,8 @@ class AbstractMetaClass : public AbstractMetaAttributes
796796
void setHasCloneOperator(bool on) { m_has_clone_operator = on; }
797797
bool hasCloneOperator() const { return m_has_clone_operator; }
798798

799+
bool hasDefaultIsNull() const;
800+
799801
void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; }
800802
QList<QPropertySpec *> propertySpecs() const { return m_property_specs; }
801803

generator/setupgenerator.cpp

+64-2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,64 @@ void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
5555
QSet<QString> &registeredTypeNames);
5656
bool hasDefaultConstructor(const AbstractMetaClass *meta_class);
5757

58+
static QStringList getOperatorCodes(const AbstractMetaClass* cls) {
59+
QSet<QString> operatorCodes;
60+
AbstractMetaFunctionList returned;
61+
AbstractMetaFunctionList functions = cls->functions();
62+
foreach (AbstractMetaFunction *function, functions) {
63+
if (function->originalName().startsWith("operator")) {
64+
QString op = function->originalName().mid(8);
65+
operatorCodes.insert(op);
66+
}
67+
}
68+
QSet<QString> r;
69+
foreach(QString op, operatorCodes.toList()) {
70+
if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") {
71+
r.insert("PythonQt::Type_RichCompare");
72+
} else if (op == "+") {
73+
r.insert("PythonQt::Type_Add");
74+
} else if (op == "-") {
75+
r.insert("PythonQt::Type_Subtract");
76+
} else if (op == "/") {
77+
r.insert("PythonQt::Type_Divide");
78+
} else if (op == "*") {
79+
r.insert("PythonQt::Type_Multiply");
80+
} else if (op == "%") {
81+
r.insert("PythonQt::Type_Mod");
82+
} else if (op == "&") {
83+
r.insert("PythonQt::Type_And");
84+
} else if (op == "|") {
85+
r.insert("PythonQt::Type_Or");
86+
} else if (op == "^") {
87+
r.insert("PythonQt::Type_Xor");
88+
} else if (op == "~") {
89+
r.insert("PythonQt::Type_Invert");
90+
91+
} else if (op == "+=") {
92+
r.insert("PythonQt::Type_InplaceAdd");
93+
} else if (op == "-=") {
94+
r.insert("PythonQt::Type_InplaceSubtract");
95+
} else if (op == "/=") {
96+
r.insert("PythonQt::Type_InplaceDivide");
97+
} else if (op == "*=") {
98+
r.insert("PythonQt::Type_InplaceMultiply");
99+
} else if (op == "%=") {
100+
r.insert("PythonQt::Type_InplaceMod");
101+
} else if (op == "&=") {
102+
r.insert("PythonQt::Type_InplaceAnd");
103+
} else if (op == "|=") {
104+
r.insert("PythonQt::Type_InplaceOr");
105+
} else if (op == "^=") {
106+
r.insert("PythonQt::Type_InplaceXor");
107+
}
108+
}
109+
if (cls->hasDefaultIsNull()) {
110+
r.insert("PythonQt::Type_NonZero");
111+
}
112+
QStringList result = r.toList();
113+
return result;
114+
}
115+
58116
void SetupGenerator::generate()
59117
{
60118
AbstractMetaClassList classes_with_polymorphic_id;
@@ -138,11 +196,15 @@ void SetupGenerator::generate()
138196
} else {
139197
shellCreator = ", NULL";
140198
}
199+
QString operatorCodes = getOperatorCodes(cls).join("|");
200+
if (operatorCodes.isEmpty()) {
201+
operatorCodes = "0";
202+
}
141203
if (cls->isQObject()) {
142-
s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module);" << endl;
204+
s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
143205
} else {
144206
QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
145-
s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module);" << endl;
207+
s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
146208
}
147209
foreach(AbstractMetaClass* interface, cls->interfaces()) {
148210
// the interface might be our own class... (e.g. QPaintDevice)

generator/shellheadergenerator.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c
282282
if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) {
283283
s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl;
284284
}
285+
if (meta_class->hasDefaultIsNull()) {
286+
s << " bool __nonzero__(" << meta_class->qualifiedCppName() << "* obj) { return !obj->isNull(); }" << endl;
287+
}
285288

286289
// Field accessors
287290
foreach (const AbstractMetaField *field, meta_class->fields()) {

src/PythonQt.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -227,14 +227,15 @@ void PythonQt::registerClass(const QMetaObject* metaobject, const char* package,
227227
_p->registerClass(metaobject, package, wrapperCreator, shell);
228228
}
229229

230-
void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module)
230+
void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
231231
{
232232
// we register all classes in the hierarchy
233233
const QMetaObject* m = metaobject;
234234
bool first = true;
235235
while (m) {
236236
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
237237
if (!info->pythonQtClassWrapper()) {
238+
info->setTypeSlots(typeSlots);
238239
info->setupQObject(m);
239240
createPythonQtClassWrapper(info, package, module);
240241
if (m->superClass()) {
@@ -1130,10 +1131,11 @@ bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTyp
11301131
}
11311132
}
11321133

1133-
void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module)
1134+
void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
11341135
{
11351136
PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
11361137
if (!info->pythonQtClassWrapper()) {
1138+
info->setTypeSlots(typeSlots);
11371139
info->setupCPPObject(typeName);
11381140
createPythonQtClassWrapper(info, package, module);
11391141
}

src/PythonQt.h

+38-2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,42 @@ class PYTHONQT_EXPORT PythonQt : public QObject {
9696
ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
9797
};
9898

99+
//! flags that tell PythonQt which operators to expect on the registered type
100+
enum TypeSlots {
101+
Type_Add = 1,
102+
Type_Subtract = 1 << 1,
103+
Type_Multiply = 1 << 2,
104+
Type_Divide = 1 << 3,
105+
Type_Mod = 1 << 4,
106+
Type_And = 1 << 5,
107+
Type_Or = 1 << 6,
108+
Type_Xor = 1 << 7,
109+
Type_LShift = 1 << 8,
110+
Type_RShift = 1 << 9,
111+
112+
Type_InplaceAdd = 1 << 10,
113+
Type_InplaceSubtract = 1 << 11,
114+
Type_InplaceMultiply = 1 << 12,
115+
Type_InplaceDivide = 1 << 13,
116+
Type_InplaceMod = 1 << 14,
117+
Type_InplaceAnd = 1 << 15,
118+
Type_InplaceOr = 1 << 16,
119+
Type_InplaceXor = 1 << 17,
120+
Type_InplaceLShift = 1 << 18,
121+
Type_InplaceRShift = 1 << 19,
122+
123+
// Not yet needed/nicely mappable/generated...
124+
//Type_Positive = 1 << 29,
125+
//Type_Negative = 1 << 29,
126+
//Type_Abs = 1 << 29,
127+
//Type_Hash = 1 << 29,
128+
129+
Type_Invert = 1 << 29,
130+
Type_RichCompare = 1 << 30,
131+
Type_NonZero = 1 << 31,
132+
133+
};
134+
99135
//! initialize the python qt binding (flags are a or combination of InitFlags), if \c pythonQtModuleName is given
100136
//! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
101137
//! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
@@ -432,7 +468,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
432468
//! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
433469
/* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
434470
you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
435-
void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL);
471+
void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
436472

437473
//! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
438474
//! (ownership of wrapper is passed to PythonQt)
@@ -442,7 +478,7 @@ class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
442478
All slots that take a pointer to typeName as the first argument will be callable from Python on
443479
a variant object that contains such a type.
444480
*/
445-
void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL);
481+
void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
446482

447483
//! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
448484
//! and it will register the classes when it first sees a pointer to such a derived class

src/PythonQtClassInfo.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ PythonQtClassInfo::PythonQtClassInfo() {
5757
_pythonQtClassWrapper = NULL;
5858
_shellSetInstanceWrapperCB = NULL;
5959
_metaTypeId = -1;
60+
_typeSlots = 0;
6061
_isQObject = false;
6162
_enumsCreated = false;
6263
}

src/PythonQtClassInfo.h

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ class PythonQtClassInfo {
104104
//! setup as a CPP (non-QObject), taking the classname
105105
void setupCPPObject(const QByteArray& classname);
106106

107+
//! set the type capabilities
108+
void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109+
//! get the type capabilities
110+
int typeSlots() const { return _typeSlots; }
111+
107112
//! get the Python method definition for a given slot name (without return type and signature)
108113
PythonQtMemberInfo member(const char* member);
109114

@@ -244,6 +249,7 @@ class PythonQtClassInfo {
244249
PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
245250

246251
int _metaTypeId;
252+
int _typeSlots;
247253

248254
bool _isQObject;
249255
bool _enumsCreated;

0 commit comments

Comments
 (0)