##// END OF EJS Templates
fixed binary operations where first argument is not a wrapper...
florianlink -
r136:90c7a1edb395
parent child
Show More
@@ -1,454 +1,462
1 1 /*
2 2 *
3 3 * Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
4 4 *
5 5 * This library is free software; you can redistribute it and/or
6 6 * modify it under the terms of the GNU Lesser General Public
7 7 * License as published by the Free Software Foundation; either
8 8 * version 2.1 of the License, or (at your option) any later version.
9 9 *
10 10 * This library is distributed in the hope that it will be useful,
11 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 13 * Lesser General Public License for more details.
14 14 *
15 15 * Further, this software is distributed without any warranty that it is
16 16 * free of the rightful claim of any third person regarding infringement
17 17 * or the like. Any license provided herein, whether implied or
18 18 * otherwise, applies only to this software file. Patent licenses, if
19 19 * any, provided herein do not apply to combinations of this program with
20 20 * other software, or any other product whatsoever.
21 21 *
22 22 * You should have received a copy of the GNU Lesser General Public
23 23 * License along with this library; if not, write to the Free Software
24 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 25 *
26 26 * Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
27 27 * 28359 Bremen, Germany or:
28 28 *
29 29 * http://www.mevis.de
30 30 *
31 31 */
32 32
33 33 //----------------------------------------------------------------------------------
34 34 /*!
35 35 // \file PythonQtClassWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtInstanceWrapper.h"
50 50
51 51 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
52 52 {
53 53 PyObject* result = NULL;
54 54 static QByteArray memberName = "__invert__";
55 55 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
56 56 if (opSlot._type == PythonQtMemberInfo::Slot) {
57 57 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
58 58 }
59 59 return result;
60 60 }
61 61
62 62 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
63 63 {
64 64 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
65 65 if (result) {
66 66 static QByteArray memberName = "__nonzero__";
67 67 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
68 68 if (opSlot._type == PythonQtMemberInfo::Slot) {
69 69 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
70 70 if (resultObj == Py_False) {
71 71 result = 0;
72 72 }
73 73 Py_XDECREF(resultObj);
74 74 }
75 75 }
76 76 return result;
77 77 }
78 78
79 79
80 static PyObject* PythonQtInstanceWrapper_binaryfunc(PythonQtInstanceWrapper* wrapper, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
80 static PyObject* PythonQtInstanceWrapper_binaryfunc(PyObject* self, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
81 81 {
82 // since we disabled type checking, we can receive any object as self, but we currently only support
83 // different objects on the right. Otherwise we would need to generate __radd__ etc. methods.
84 if (!PyObject_TypeCheck(self, &PythonQtInstanceWrapper_Type)) {
85 QString error = "Unsupported operation " + opName + "(" + self->ob_type->tp_name + ", " + other->ob_type->tp_name + ")";
86 PyErr_SetString(PyExc_ArithmeticError, error.toLatin1().data());
87 return NULL;
88 }
89 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
82 90 PyObject* result = NULL;
83 91 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
84 92 if (opSlot._type == PythonQtMemberInfo::Slot) {
85 93 // TODO get rid of tuple
86 94 PyObject* args = PyTuple_New(1);
87 95 Py_INCREF(other);
88 96 PyTuple_SET_ITEM(args, 0, other);
89 97 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
90 98 Py_DECREF(args);
91 99 if (!result && !fallbackOpName.isEmpty()) {
92 100 // try fallback if we did not get a result
93 result = PythonQtInstanceWrapper_binaryfunc(wrapper, other, fallbackOpName);
101 result = PythonQtInstanceWrapper_binaryfunc(self, other, fallbackOpName);
94 102 }
95 103 }
96 104 return result;
97 105 }
98 106
99 107 #define BINARY_OP(NAME) \
100 static PyObject* PythonQtInstanceWrapper_ ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
108 static PyObject* PythonQtInstanceWrapper_ ## NAME(PyObject* self, PyObject* other) \
101 109 { \
102 110 static const QByteArray opName("__" #NAME "__"); \
103 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName); \
111 return PythonQtInstanceWrapper_binaryfunc(self, other, opName); \
104 112 }
105 113
106 114 #define BINARY_OP_INPLACE(NAME) \
107 static PyObject* PythonQtInstanceWrapper_i ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
115 static PyObject* PythonQtInstanceWrapper_i ## NAME(PyObject* self, PyObject* other) \
108 116 { \
109 117 static const QByteArray opName("__i" #NAME "__"); \
110 118 static const QByteArray fallbackName("__" #NAME "__"); \
111 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName, fallbackName); \
119 return PythonQtInstanceWrapper_binaryfunc(self, other, opName, fallbackName); \
112 120 }
113 121
114 122 BINARY_OP(add)
115 123 BINARY_OP(sub)
116 124 BINARY_OP(mul)
117 125 BINARY_OP(div)
118 126 BINARY_OP(and)
119 127 BINARY_OP(or)
120 128 BINARY_OP(xor)
121 129 BINARY_OP(mod)
122 130 BINARY_OP(lshift)
123 131 BINARY_OP(rshift)
124 132
125 133 BINARY_OP_INPLACE(add)
126 134 BINARY_OP_INPLACE(sub)
127 135 BINARY_OP_INPLACE(mul)
128 136 BINARY_OP_INPLACE(div)
129 137 BINARY_OP_INPLACE(and)
130 138 BINARY_OP_INPLACE(or)
131 139 BINARY_OP_INPLACE(xor)
132 140 BINARY_OP_INPLACE(mod)
133 141 BINARY_OP_INPLACE(lshift)
134 142 BINARY_OP_INPLACE(rshift)
135 143
136 144 static void initializeSlots(PythonQtClassWrapper* wrap)
137 145 {
138 146 int typeSlots = wrap->classInfo()->typeSlots();
139 147 if (typeSlots) {
140 148 if (typeSlots & PythonQt::Type_Add) {
141 149 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
142 150 }
143 151 if (typeSlots & PythonQt::Type_Subtract) {
144 152 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
145 153 }
146 154 if (typeSlots & PythonQt::Type_Multiply) {
147 155 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
148 156 }
149 157 if (typeSlots & PythonQt::Type_Divide) {
150 158 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
151 159 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
152 160 }
153 161 if (typeSlots & PythonQt::Type_And) {
154 162 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
155 163 }
156 164 if (typeSlots & PythonQt::Type_Or) {
157 165 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
158 166 }
159 167 if (typeSlots & PythonQt::Type_Xor) {
160 168 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
161 169 }
162 170 if (typeSlots & PythonQt::Type_Mod) {
163 171 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
164 172 }
165 173 if (typeSlots & PythonQt::Type_LShift) {
166 174 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
167 175 }
168 176 if (typeSlots & PythonQt::Type_RShift) {
169 177 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
170 178 }
171 179
172 180 if (typeSlots & PythonQt::Type_InplaceAdd) {
173 181 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
174 182 }
175 183 if (typeSlots & PythonQt::Type_InplaceSubtract) {
176 184 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
177 185 }
178 186 if (typeSlots & PythonQt::Type_InplaceMultiply) {
179 187 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
180 188 }
181 189 if (typeSlots & PythonQt::Type_InplaceDivide) {
182 190 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
183 191 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
184 192 }
185 193 if (typeSlots & PythonQt::Type_InplaceAnd) {
186 194 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
187 195 }
188 196 if (typeSlots & PythonQt::Type_InplaceOr) {
189 197 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
190 198 }
191 199 if (typeSlots & PythonQt::Type_InplaceXor) {
192 200 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
193 201 }
194 202 if (typeSlots & PythonQt::Type_InplaceMod) {
195 203 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
196 204 }
197 205 if (typeSlots & PythonQt::Type_InplaceLShift) {
198 206 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
199 207 }
200 208 if (typeSlots & PythonQt::Type_InplaceRShift) {
201 209 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
202 210 }
203 211 if (typeSlots & PythonQt::Type_Invert) {
204 212 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
205 213 }
206 214 if (typeSlots & PythonQt::Type_NonZero) {
207 215 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
208 216 }
209 217 }
210 218 }
211 219
212 220 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
213 221 {
214 222 // call the default type alloc
215 223 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
216 224
217 225 // take current class type, if we are called via newPythonQtClassWrapper()
218 226 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
219 227 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
220 228 if (wrap->_classInfo) {
221 229 initializeSlots(wrap);
222 230 }
223 231
224 232 return obj;
225 233 }
226 234
227 235
228 236 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
229 237 {
230 238 // call the default type init
231 239 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
232 240 return -1;
233 241 }
234 242
235 243 // if we have no CPP class information, try our base class
236 244 if (!self->classInfo()) {
237 245 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
238 246
239 247 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
240 248 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
241 249 return -1;
242 250 }
243 251
244 252 // take the class info from the superType
245 253 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
246 254 }
247 255
248 256 return 0;
249 257 }
250 258
251 259 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
252 260 {
253 261 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
254 262 }
255 263
256 264 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
257 265 {
258 266 return PythonQt::self()->helpCalled(type->classInfo());
259 267 }
260 268
261 269 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args)
262 270 {
263 271 Py_ssize_t argc = PyTuple_Size(args);
264 272 if (argc>0) {
265 273 // we need to call __init__ of the instance
266 274 PyObject* self = PyTuple_GET_ITEM(args, 0);
267 275 if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) {
268 276 PyObject* newargs = PyTuple_New(argc-1);
269 277 for (int i = 0;i<argc-1; i++) {
270 278 PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1));
271 279 }
272 280 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
273 281 int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL);
274 282 Py_DECREF(newargs);
275 283 if (result==0) {
276 284 Py_INCREF(Py_None);
277 285 return Py_None;
278 286 } else {
279 287 // init failed!
280 288 }
281 289 } else {
282 290 // self not of correct type!
283 291 }
284 292 } else {
285 293 // wrong number of args
286 294 }
287 295 return NULL;
288 296 }
289 297
290 298 static PyMethodDef PythonQtClassWrapper_methods[] = {
291 299 {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS,
292 300 "Return the classname of the object"
293 301 },
294 302 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
295 303 "Return the classname of the object"
296 304 },
297 305 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
298 306 "Shows the help of available methods for this class"
299 307 },
300 308 {NULL, NULL, 0 , NULL} /* Sentinel */
301 309 };
302 310
303 311
304 312 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
305 313 {
306 314 const char *attributeName;
307 315 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
308 316
309 317 if ((attributeName = PyString_AsString(name)) == NULL) {
310 318 return NULL;
311 319 }
312 320 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
313 321 return NULL;
314 322 }
315 323
316 324 if (qstrcmp(attributeName, "__dict__")==0) {
317 325 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
318 326 if (!wrapper->classInfo()) {
319 327 Py_INCREF(dict);
320 328 return dict;
321 329 }
322 330 dict = PyDict_Copy(dict);
323 331
324 332 QStringList l = wrapper->classInfo()->memberList(false);
325 333 foreach (QString name, l) {
326 334 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
327 335 if (o) {
328 336 PyDict_SetItemString(dict, name.toLatin1().data(), o);
329 337 Py_DECREF(o);
330 338 } else {
331 339 // it must have been a property or child, which we do not know as a class object...
332 340 }
333 341 }
334 342 if (wrapper->classInfo()->constructors()) {
335 343 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj);
336 344 PyDict_SetItemString(dict, "__init__", func);
337 345 Py_DECREF(func);
338 346 }
339 347 for (int i = 1;i<3;i++) {
340 348 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
341 349 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
342 350 Py_DECREF(func);
343 351 }
344 352 return dict;
345 353 }
346 354
347 355 if (wrapper->classInfo()) {
348 356 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
349 357 if (member._type == PythonQtMemberInfo::EnumValue) {
350 358 PyObject* enumValue = member._enumValue;
351 359 Py_INCREF(enumValue);
352 360 return enumValue;
353 361 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
354 362 PyObject* enumWrapper = member._enumWrapper;
355 363 Py_INCREF(enumWrapper);
356 364 return enumWrapper;
357 365 } else if (member._type == PythonQtMemberInfo::Slot) {
358 366 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
359 367 return PythonQtSlotFunction_New(member._slot, obj, NULL);
360 368 }
361 369 }
362 370
363 371 // look for the interal methods (className(), help())
364 372 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
365 373 if (internalMethod) {
366 374 return internalMethod;
367 375 }
368 376 PyErr_Clear();
369 377
370 378 // look in super
371 379 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
372 380 if (superAttr) {
373 381 return superAttr;
374 382 }
375 383
376 384 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
377 385 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
378 386 return NULL;
379 387 }
380 388
381 389 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
382 390 {
383 391 return PyType_Type.tp_setattro(obj,name,value);
384 392 }
385 393
386 394 /*
387 395 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
388 396 {
389 397 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
390 398 if (wrapper->classInfo()->isCPPWrapper()) {
391 399 const QMetaObject* meta = wrapper->classInfo()->metaObject();
392 400 if (!meta) {
393 401 QObject* decorator = wrapper->classInfo()->decorator();
394 402 if (decorator) {
395 403 meta = decorator->metaObject();
396 404 }
397 405 }
398 406 if (meta) {
399 407 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
400 408 } else {
401 409 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
402 410 }
403 411 } else {
404 412 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
405 413 }
406 414 }
407 415
408 416 */
409 417
410 418 PyTypeObject PythonQtClassWrapper_Type = {
411 419 PyObject_HEAD_INIT(NULL)
412 420 0, /*ob_size*/
413 421 "PythonQt.PythonQtClassWrapper", /*tp_name*/
414 422 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
415 423 0, /*tp_itemsize*/
416 424 0, /*tp_dealloc*/
417 425 0, /*tp_print*/
418 426 0, /*tp_getattr*/
419 427 0, /*tp_setattr*/
420 428 0, /*tp_compare*/
421 429 0, //PythonQtClassWrapper_repr, /*tp_repr*/
422 430 0, /*tp_as_number*/
423 431 0, /*tp_as_sequence*/
424 432 0, /*tp_as_mapping*/
425 433 0, /*tp_hash */
426 434 0, /*tp_call*/
427 435 0, /*tp_str*/
428 436 PythonQtClassWrapper_getattro, /*tp_getattro*/
429 437 PythonQtClassWrapper_setattro, /*tp_setattro*/
430 438 0, /*tp_as_buffer*/
431 439 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
432 440 0, /* tp_doc */
433 441 0, /* tp_traverse */
434 442 0, /* tp_clear */
435 443 0, /* tp_richcompare */
436 444 0, /* tp_weaklistoffset */
437 445 0, /* tp_iter */
438 446 0, /* tp_iternext */
439 447 0, /* tp_methods */
440 448 0, /* tp_members */
441 449 0, /* tp_getset */
442 450 0, /* tp_base */
443 451 0, /* tp_dict */
444 452 0, /* tp_descr_get */
445 453 0, /* tp_descr_set */
446 454 0, /* tp_dictoffset */
447 455 (initproc)PythonQtClassWrapper_init, /* tp_init */
448 456 PythonQtClassWrapper_alloc, /* tp_alloc */
449 457 0, /* tp_new */
450 458 0, /* tp_free */
451 459 };
452 460
453 461 //-------------------------------------------------------
454 462
General Comments 0
You need to be logged in to leave comments. Login now