##// END OF EJS Templates
adapted to new py_ naming of special methods and added support for py_toString...
florianlink -
r116:806ca936e21a
parent child
Show More
@@ -1,845 +1,848
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, 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 PythonQt.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 "PythonQtClassInfo.h"
43 43 #include "PythonQtMethodInfo.h"
44 44 #include "PythonQt.h"
45 45 #include <QMetaMethod>
46 46 #include <QMetaObject>
47 47 #include <QMetaEnum>
48 48
49 49 QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;
50 50
51 51 PythonQtClassInfo::PythonQtClassInfo() {
52 52 _meta = NULL;
53 53 _constructors = NULL;
54 54 _destructor = NULL;
55 55 _decoratorProvider = NULL;
56 56 _decoratorProviderCB = NULL;
57 57 _pythonQtClassWrapper = NULL;
58 58 _shellSetInstanceWrapperCB = NULL;
59 59 _metaTypeId = -1;
60 60 _isQObject = false;
61 61 _enumsCreated = false;
62 62 }
63 63
64 64 PythonQtClassInfo::~PythonQtClassInfo()
65 65 {
66 66 clearCachedMembers();
67 67
68 68 if (_constructors) {
69 69 _constructors->deleteOverloadsAndThis();
70 70 }
71 71 if (_destructor) {
72 72 _destructor->deleteOverloadsAndThis();
73 73 }
74 74 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 75 info->deleteOverloadsAndThis();
76 76 }
77 77 }
78 78
79 79 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 80 {
81 81 // _wrappedClassName is already set earlier in the class setup
82 82 _isQObject = true;
83 83 _meta = meta;
84 84 }
85 85
86 86 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 87 {
88 88 _isQObject = false;
89 89 _wrappedClassName = classname;
90 90 _metaTypeId = QMetaType::type(classname);
91 91 }
92 92
93 93 void PythonQtClassInfo::clearCachedMembers()
94 94 {
95 95 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 96 while (i.hasNext()) {
97 97 PythonQtMemberInfo member = i.next().value();
98 98 if (member._type== PythonQtMemberInfo::Slot) {
99 99 PythonQtSlotInfo* info = member._slot;
100 100 while (info) {
101 101 PythonQtSlotInfo* next = info->nextInfo();
102 102 delete info;
103 103 info = next;
104 104 }
105 105 }
106 106 }
107 107 }
108 108
109 109 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 110 {
111 111 const char* sigEnd = sigStart;
112 112 char c;
113 113 do {
114 114 c = *sigEnd++;
115 115 } while (c!=someChar && c!=0);
116 116 return sigEnd-sigStart-1;
117 117 }
118 118
119 119 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 120 {
121 121 if (!_meta) return false;
122 122
123 123 bool found = false;
124 124 bool nameMapped = false;
125 125 const char* attributeName = memberName;
126 126 // look for properties
127 127 int i = _meta->indexOfProperty(attributeName);
128 128 if (i==-1) {
129 129 // try to map name to objectName
130 130 if (qstrcmp(attributeName, "name")==0) {
131 131 attributeName = "objectName";
132 132 nameMapped = true;
133 133 i = _meta->indexOfProperty(attributeName);
134 134 }
135 135 }
136 136 if (i!=-1) {
137 137 PythonQtMemberInfo newInfo(_meta->property(i));
138 138 _cachedMembers.insert(attributeName, newInfo);
139 139 if (nameMapped) {
140 140 _cachedMembers.insert(memberName, newInfo);
141 141 }
142 142 #ifdef PYTHONQT_DEBUG
143 143 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
144 144 #endif
145 145 found = true;
146 146 }
147 147 return found;
148 148 }
149 149
150 150 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
151 151 {
152 152 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
153 153 foreach(const ParentClassInfo& info, _parentClasses) {
154 154 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
155 155 }
156 156 return inputInfo;
157 157 }
158 158
159 159 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
160 160 QObject* decoratorProvider = decorator();
161 161 int memberNameLen = strlen(memberName);
162 162 if (decoratorProvider) {
163 163 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
164 164 const QMetaObject* meta = decoratorProvider->metaObject();
165 165 int numMethods = meta->methodCount();
166 166 int startFrom = QObject::staticMetaObject.methodCount();
167 167 for (int i = startFrom; i < numMethods; i++) {
168 168 QMetaMethod m = meta->method(i);
169 169 if ((m.methodType() == QMetaMethod::Method ||
170 170 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
171 171
172 172 const char* sigStart = m.signature();
173 173 bool isClassDeco = false;
174 174 if (qstrncmp(sigStart, "static_", 7)==0) {
175 175 // skip the static_classname_ part of the string
176 176 sigStart += 7 + 1 + strlen(className());
177 177 isClassDeco = true;
178 178 } else if (qstrncmp(sigStart, "new_", 4)==0) {
179 179 isClassDeco = true;
180 180 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
181 181 isClassDeco = true;
182 182 }
183 183 // find the first '('
184 184 int offset = findCharOffset(sigStart, '(');
185 185
186 186 // XXX no checking is currently done if the slots have correct first argument or not...
187 187
188 188 // check if same length and same name
189 189 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
190 190 found = true;
191 191 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
192 192 info->setUpcastingOffset(upcastingOffset);
193 193 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
194 194 if (tail) {
195 195 tail->setNextInfo(info);
196 196 } else {
197 197 PythonQtMemberInfo newInfo(info);
198 198 memberCache.insert(memberName, newInfo);
199 199 }
200 200 tail = info;
201 201 }
202 202 }
203 203 }
204 204 }
205 205
206 206 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
207 207
208 208 return tail;
209 209 }
210 210
211 211 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
212 212 {
213 213 bool found = false;
214 214 int memberNameLen = strlen(memberName);
215 215 PythonQtSlotInfo* tail = NULL;
216 216 if (_meta) {
217 217 int numMethods = _meta->methodCount();
218 218 for (int i = 0; i < numMethods; i++) {
219 219 QMetaMethod m = _meta->method(i);
220 220 if (((m.methodType() == QMetaMethod::Method ||
221 221 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
222 222 || m.methodType()==QMetaMethod::Signal) {
223 223
224 224 const char* sigStart = m.signature();
225 225 // find the first '('
226 226 int offset = findCharOffset(sigStart, '(');
227 227
228 228 // check if same length and same name
229 229 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
230 230 found = true;
231 231 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
232 232 if (tail) {
233 233 tail->setNextInfo(info);
234 234 } else {
235 235 PythonQtMemberInfo newInfo(info);
236 236 _cachedMembers.insert(memberName, newInfo);
237 237 }
238 238 tail = info;
239 239 }
240 240 }
241 241 }
242 242 }
243 243
244 244 // look for dynamic decorators in this class and in derived classes
245 245 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
246 246
247 247 return found;
248 248 }
249 249
250 250 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
251 251 {
252 252 bool found = false;
253 253 // look for enum values
254 254 int enumCount = meta->enumeratorCount();
255 255 for (int i=0;i<enumCount; i++) {
256 256 QMetaEnum e = meta->enumerator(i);
257 257 // we do not want flags, they will cause our values to appear two times
258 258 if (e.isFlag()) continue;
259 259
260 260 for (int j=0; j < e.keyCount(); j++) {
261 261 if (qstrcmp(e.key(j), memberName)==0) {
262 262 PyObject* enumType = findEnumWrapper(e.name());
263 263 if (enumType) {
264 264 PythonQtObjectPtr enumValuePtr;
265 265 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
266 266 PythonQtMemberInfo newInfo(enumValuePtr);
267 267 _cachedMembers.insert(memberName, newInfo);
268 268 #ifdef PYTHONQT_DEBUG
269 269 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
270 270 #endif
271 271 found = true;
272 272 break;
273 273 } else {
274 274 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
275 275 }
276 276 }
277 277 }
278 278 }
279 279 return found;
280 280 }
281 281
282 282 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
283 283 {
284 284 PythonQtMemberInfo info = _cachedMembers.value(memberName);
285 285 if (info._type != PythonQtMemberInfo::Invalid) {
286 286 return info;
287 287 } else {
288 288 bool found = false;
289 289
290 290 found = lookForPropertyAndCache(memberName);
291 291 if (!found) {
292 292 found = lookForMethodAndCache(memberName);
293 293 }
294 294 if (!found) {
295 295 if (_meta) {
296 296 // check enums in our meta object directly
297 297 found = lookForEnumAndCache(_meta, memberName);
298 298 }
299 299 if (!found) {
300 300 // check enums in the class hierachy of CPP classes
301 301 // look for dynamic decorators in this class and in derived classes
302 302 QList<QObject*> decoObjects;
303 303 recursiveCollectDecoratorObjects(decoObjects);
304 304 foreach(QObject* deco, decoObjects) {
305 305 // call on ourself for caching, but with different metaObject():
306 306 found = lookForEnumAndCache(deco->metaObject(), memberName);
307 307 if (found) {
308 308 break;
309 309 }
310 310 }
311 311 }
312 312 }
313 313 if (!found) {
314 314 // maybe it is an enum wrapper?
315 315 PyObject* p = findEnumWrapper(memberName);
316 316 if (p) {
317 317 info._type = PythonQtMemberInfo::EnumWrapper;
318 318 info._enumWrapper = p;
319 319 _cachedMembers.insert(memberName, info);
320 320 found = true;
321 321 }
322 322 }
323 323 if (!found) {
324 324 // since python keywords can not be looked up, we check if the name contains a single trailing _
325 325 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
326 326 QByteArray mbrName(memberName);
327 327 if ((mbrName.length()>2) &&
328 328 (mbrName.at(mbrName.length()-1) == '_') &&
329 329 (mbrName.at(mbrName.length()-2) != '_')) {
330 330 mbrName = mbrName.mid(0,mbrName.length()-1);
331 331 found = lookForMethodAndCache(mbrName.constData());
332 332 if (found) {
333 333 return _cachedMembers.value(mbrName);
334 334 }
335 335 }
336 336 }
337 337 if (!found) {
338 338 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
339 339 info._type = PythonQtMemberInfo::NotFound;
340 340 _cachedMembers.insert(memberName, info);
341 341 }
342 342 }
343 343
344 344 return _cachedMembers.value(memberName);
345 345 }
346 346
347 347 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
348 348 QObject* deco = decorator();
349 349 if (deco) {
350 350 decoratorObjects.append(deco);
351 351 }
352 352 foreach(const ParentClassInfo& info, _parentClasses) {
353 353 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
354 354 }
355 355 }
356 356
357 357 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
358 358 classInfoObjects.append(this);
359 359 foreach(const ParentClassInfo& info, _parentClasses) {
360 360 info._parent->recursiveCollectClassInfos(classInfoObjects);
361 361 }
362 362 }
363 363
364 364 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
365 365 {
366 366 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
367 367 while (it.hasNext()) {
368 368
369 369 PythonQtSlotInfo* infoOrig = it.next();
370 370
371 371 const char* sigStart = infoOrig->metaMethod()->signature();
372 372 if (qstrncmp("static_", sigStart, 7)==0) {
373 373 sigStart += 7;
374 374 sigStart += findCharOffset(sigStart, '_')+1;
375 375 }
376 376 int offset = findCharOffset(sigStart, '(');
377 377 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
378 378 //make a copy, otherwise we will have trouble on overloads!
379 379 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
380 380 info->setUpcastingOffset(upcastingOffset);
381 381 found = true;
382 382 if (tail) {
383 383 tail->setNextInfo(info);
384 384 } else {
385 385 PythonQtMemberInfo newInfo(info);
386 386 memberCache.insert(memberName, newInfo);
387 387 }
388 388 tail = info;
389 389 }
390 390 }
391 391 return tail;
392 392 }
393 393
394 394 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
395 395 QObject* decoratorProvider = decorator();
396 396 if (decoratorProvider) {
397 397 const QMetaObject* meta = decoratorProvider->metaObject();
398 398 int numMethods = meta->methodCount();
399 399 int startFrom = QObject::staticMetaObject.methodCount();
400 400 for (int i = startFrom; i < numMethods; i++) {
401 401 QMetaMethod m = meta->method(i);
402 402 if ((m.methodType() == QMetaMethod::Method ||
403 403 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
404 404
405 405 const char* sigStart = m.signature();
406 406 bool isClassDeco = false;
407 407 if (qstrncmp(sigStart, "static_", 7)==0) {
408 408 // skip the static_classname_ part of the string
409 409 sigStart += 7 + 1 + strlen(className());
410 410 isClassDeco = true;
411 411 } else if (qstrncmp(sigStart, "new_", 4)==0) {
412 412 continue;
413 413 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
414 414 continue;
415 } else if (qstrncmp(sigStart, "py_", 3)==0) {
416 // hide everything that starts with py_
417 continue;
415 418 }
416 419 // find the first '('
417 420 int offset = findCharOffset(sigStart, '(');
418 421
419 422 // XXX no checking is currently done if the slots have correct first argument or not...
420 423 if (!metaOnly || isClassDeco) {
421 424 list << QString::fromLatin1(sigStart, offset);
422 425 }
423 426 }
424 427 }
425 428 }
426 429
427 430 // look for global decorator slots
428 431 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
429 432 while (it.hasNext()) {
430 433 PythonQtSlotInfo* slot = it.next();
431 434 if (metaOnly) {
432 435 if (slot->isClassDecorator()) {
433 436 QByteArray first = slot->slotName();
434 437 if (first.startsWith("static_")) {
435 438 int idx = first.indexOf('_');
436 439 idx = first.indexOf('_', idx+1);
437 440 first = first.mid(idx+1);
438 441 }
439 442 list << first;
440 443 }
441 444 } else {
442 445 list << slot->slotName();
443 446 }
444 447 }
445 448 }
446 449
447 450 QStringList PythonQtClassInfo::propertyList()
448 451 {
449 452 QStringList l;
450 453 if (_isQObject && _meta) {
451 454 int i;
452 455 int numProperties = _meta->propertyCount();
453 456 for (i = 0; i < numProperties; i++) {
454 457 QMetaProperty p = _meta->property(i);
455 458 l << QString(p.name());
456 459 }
457 460 }
458 461 return l;
459 462 }
460 463
461 464 QStringList PythonQtClassInfo::memberList(bool metaOnly)
462 465 {
463 466 decorator();
464 467
465 468 QStringList l;
466 469 QString h;
467 470 if (_isQObject && _meta && !metaOnly) {
468 471 l = propertyList();
469 472 }
470 473
471 474 // normal slots of QObject (or wrapper QObject)
472 475 if (!metaOnly && _meta) {
473 476 int numMethods = _meta->methodCount();
474 477 bool skipQObj = !_isQObject;
475 478 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
476 479 QMetaMethod m = _meta->method(i);
477 480 if (((m.methodType() == QMetaMethod::Method ||
478 481 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
479 482 || m.methodType()==QMetaMethod::Signal) {
480 483 QByteArray signa(m.signature());
481 484 signa = signa.left(signa.indexOf('('));
482 485 l << signa;
483 486 }
484 487 }
485 488 }
486 489
487 490 {
488 491 // look for dynamic decorators in this class and in derived classes
489 492 QList<PythonQtClassInfo*> infos;
490 493 recursiveCollectClassInfos(infos);
491 494 foreach(PythonQtClassInfo* info, infos) {
492 495 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
493 496 }
494 497 }
495 498
496 499 // List enumerator keys...
497 500 QList<const QMetaObject*> enumMetaObjects;
498 501 if (_meta) {
499 502 enumMetaObjects << _meta;
500 503 }
501 504 // check enums in the class hierachy of CPP classes
502 505 QList<QObject*> decoObjects;
503 506 recursiveCollectDecoratorObjects(decoObjects);
504 507 foreach(QObject* deco, decoObjects) {
505 508 enumMetaObjects << deco->metaObject();
506 509 }
507 510
508 511 foreach(const QMetaObject* meta, enumMetaObjects) {
509 512 for (int i = 0; i<meta->enumeratorCount(); i++) {
510 513 QMetaEnum e = meta->enumerator(i);
511 514 l << e.name();
512 515 // we do not want flags, they will cause our values to appear two times
513 516 if (e.isFlag()) continue;
514 517
515 518 for (int j=0; j < e.keyCount(); j++) {
516 519 l << QString(e.key(j));
517 520 }
518 521 }
519 522 }
520 523
521 524 return QSet<QString>::fromList(l).toList();
522 525 }
523 526
524 527 const char* PythonQtClassInfo::className()
525 528 {
526 529 return _wrappedClassName.constData();
527 530 }
528 531
529 532 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
530 533 {
531 534 if (ptr==NULL) {
532 535 return NULL;
533 536 }
534 537 if (_wrappedClassName == classname) {
535 538 return ptr;
536 539 }
537 540 foreach(const ParentClassInfo& info, _parentClasses) {
538 541 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
539 542 if (result) {
540 543 return result;
541 544 }
542 545 }
543 546 return NULL;
544 547 }
545 548
546 549 bool PythonQtClassInfo::inherits(const char* name)
547 550 {
548 551 if (_wrappedClassName == name) {
549 552 return true;
550 553 }
551 554 foreach(const ParentClassInfo& info, _parentClasses) {
552 555 if (info._parent->inherits(name)) {
553 556 return true;
554 557 }
555 558 }
556 559 return false;
557 560 }
558 561
559 562 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
560 563 {
561 564 if (classInfo == this) {
562 565 return true;
563 566 }
564 567 foreach(const ParentClassInfo& info, _parentClasses) {
565 568 if (info._parent->inherits(classInfo)) {
566 569 return true;
567 570 }
568 571 }
569 572 return false;
570 573 }
571 574
572 575 QString PythonQtClassInfo::help()
573 576 {
574 577 decorator();
575 578 QString h;
576 579 h += QString("--- ") + QString(className()) + QString(" ---\n");
577 580
578 581 if (_isQObject) {
579 582 h += "Properties:\n";
580 583
581 584 int i;
582 585 int numProperties = _meta->propertyCount();
583 586 for (i = 0; i < numProperties; i++) {
584 587 QMetaProperty p = _meta->property(i);
585 588 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
586 589 }
587 590 }
588 591
589 592 if (constructors()) {
590 593 h += "Constructors:\n";
591 594 PythonQtSlotInfo* constr = constructors();
592 595 while (constr) {
593 596 h += constr->fullSignature() + "\n";
594 597 constr = constr->nextInfo();
595 598 }
596 599 }
597 600
598 601 h += "Slots:\n";
599 602 h += "QString help()\n";
600 603 h += "QString className()\n";
601 604
602 605 if (_meta) {
603 606 int numMethods = _meta->methodCount();
604 607 for (int i = 0; i < numMethods; i++) {
605 608 QMetaMethod m = _meta->method(i);
606 609 if ((m.methodType() == QMetaMethod::Method ||
607 610 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
608 611 PythonQtSlotInfo slot(this, m, i);
609 612 h += slot.fullSignature()+ "\n";
610 613 }
611 614 }
612 615 }
613 616
614 617 // TODO xxx : decorators and enums from decorator() are missing...
615 618 // maybe we can reuse memberlist()?
616 619
617 620 if (_meta && _meta->enumeratorCount()) {
618 621 h += "Enums:\n";
619 622 for (int i = 0; i<_meta->enumeratorCount(); i++) {
620 623 QMetaEnum e = _meta->enumerator(i);
621 624 h += QString(e.name()) + " {";
622 625 for (int j=0; j < e.keyCount(); j++) {
623 626 if (j) { h+= ", "; }
624 627 h += e.key(j);
625 628 }
626 629 h += " }\n";
627 630 }
628 631 }
629 632
630 633 if (_isQObject && _meta) {
631 634 int numMethods = _meta->methodCount();
632 635 if (numMethods>0) {
633 636 h += "Signals:\n";
634 637 for (int i = 0; i < numMethods; i++) {
635 638 QMetaMethod m = _meta->method(i);
636 639 if (m.methodType() == QMetaMethod::Signal) {
637 640 h += QString(m.signature()) + "\n";
638 641 }
639 642 }
640 643 }
641 644 }
642 645 return h;
643 646 }
644 647
645 648 PythonQtSlotInfo* PythonQtClassInfo::constructors()
646 649 {
647 650 if (!_constructors) {
648 651 // force creation of lazy decorator, which will register the decorators
649 652 decorator();
650 653 }
651 654 return _constructors;
652 655 }
653 656
654 657 PythonQtSlotInfo* PythonQtClassInfo::destructor()
655 658 {
656 659 if (!_destructor) {
657 660 // force creation of lazy decorator, which will register the decorators
658 661 decorator();
659 662 }
660 663 return _destructor;
661 664 }
662 665
663 666 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
664 667 {
665 668 PythonQtSlotInfo* prev = constructors();
666 669 if (prev) {
667 670 info->setNextInfo(prev->nextInfo());
668 671 prev->setNextInfo(info);
669 672 } else {
670 673 _constructors = info;
671 674 }
672 675 }
673 676
674 677 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
675 678 {
676 679 _decoratorSlots.append(info);
677 680 }
678 681
679 682 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
680 683 {
681 684 if (_destructor) {
682 685 _destructor->deleteOverloadsAndThis();
683 686 }
684 687 _destructor = info;
685 688 }
686 689
687 690 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
688 691 {
689 692 _meta = meta;
690 693 clearCachedMembers();
691 694 }
692 695
693 696 QObject* PythonQtClassInfo::decorator()
694 697 {
695 698 if (!_decoratorProvider && _decoratorProviderCB) {
696 699 _decoratorProvider = (*_decoratorProviderCB)();
697 700 if (_decoratorProvider) {
698 701 _decoratorProvider->setParent(PythonQt::priv());
699 702 // setup enums early, since they might be needed by the constructor decorators:
700 703 if (!_enumsCreated) {
701 704 createEnumWrappers();
702 705 }
703 706 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
704 707 }
705 708 }
706 709 // check if enums need to be created and create them if they are not yet created
707 710 if (!_enumsCreated) {
708 711 createEnumWrappers();
709 712 }
710 713 return _decoratorProvider;
711 714 }
712 715
713 716 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
714 717 {
715 PythonQtMemberInfo info = member("hasOwner");
718 PythonQtMemberInfo info = member("py_hasOwner");
716 719 if (info._type == PythonQtMemberInfo::Slot) {
717 720 void* obj = object;
718 721 bool result = false;
719 722 void* args[2];
720 723 args[0] = &result;
721 724 args[1] = &obj;
722 725 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
723 726 return !result;
724 727 } else {
725 728 return false;
726 729 }
727 730 }
728 731
729 732 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
730 733 {
731 734 if (!_polymorphicHandlers.isEmpty()) {
732 735 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
733 736 void* resultPtr = (*cb)(ptr, resultClassName);
734 737 if (resultPtr) {
735 738 return resultPtr;
736 739 }
737 740 }
738 741 }
739 742 foreach(const ParentClassInfo& info, _parentClasses) {
740 743 if (!info._parent->isQObject()) {
741 744 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
742 745 if (resultPtr) {
743 746 return resultPtr;
744 747 }
745 748 }
746 749 }
747 750 return NULL;
748 751 }
749 752
750 753 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
751 754 {
752 755 char* className;
753 756 // this would do downcasting recursively...
754 757 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
755 758
756 759 // we only do downcasting on the base object, not on the whole inheritance tree...
757 760 void* resultPtr = NULL;
758 761 if (!_polymorphicHandlers.isEmpty()) {
759 762 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
760 763 resultPtr = (*cb)(ptr, &className);
761 764 if (resultPtr) {
762 765 break;
763 766 }
764 767 }
765 768 }
766 769 if (resultPtr) {
767 770 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
768 771 } else {
769 772 *resultClassInfo = this;
770 773 resultPtr = ptr;
771 774 }
772 775 return resultPtr;
773 776 }
774 777
775 778 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
776 779 {
777 780 if (isLocalEnum) {
778 781 *isLocalEnum = true;
779 782 }
780 783 int scopePos = name.lastIndexOf("::");
781 784 if (scopePos != -1) {
782 785 if (isLocalEnum) {
783 786 *isLocalEnum = false;
784 787 }
785 788 // split into scope and enum name
786 789 QByteArray enumScope = name.mid(0,scopePos);
787 790 QByteArray enumName = name.mid(scopePos+2);
788 791 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
789 792 if (info) {
790 793 return info->findEnumWrapper(enumName);
791 794 } else{
792 795 return NULL;
793 796 }
794 797 }
795 798 if (localScope) {
796 799 return localScope->findEnumWrapper(name);
797 800 } else {
798 801 return NULL;
799 802 }
800 803 }
801 804
802 805 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
803 806 {
804 807 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
805 808 QMetaEnum e = meta->enumerator(i);
806 809 PythonQtObjectPtr p;
807 810 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
808 811 _enumWrappers.append(p);
809 812 }
810 813 }
811 814
812 815 void PythonQtClassInfo::createEnumWrappers()
813 816 {
814 817 if (!_enumsCreated) {
815 818 _enumsCreated = true;
816 819 if (_meta) {
817 820 createEnumWrappers(_meta);
818 821 }
819 822 if (decorator()) {
820 823 createEnumWrappers(decorator()->metaObject());
821 824 }
822 825 foreach(const ParentClassInfo& info, _parentClasses) {
823 826 info._parent->createEnumWrappers();
824 827 }
825 828 }
826 829 }
827 830
828 831 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
829 832 // force enum creation
830 833 if (!_enumsCreated) {
831 834 createEnumWrappers();
832 835 }
833 836 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
834 837 const char* className = ((PyTypeObject*)p.object())->tp_name;
835 838 if (qstrcmp(className, name)==0) {
836 839 return p.object();
837 840 }
838 841 }
839 842 foreach(const ParentClassInfo& info, _parentClasses) {
840 843 PyObject* p = info._parent->findEnumWrapper(name);
841 844 if (p) return p;
842 845 }
843 846 return NULL;
844 847 }
845 848
@@ -1,256 +1,256
1 1 #ifndef _PYTHONQTCLASSINFO_H
2 2 #define _PYTHONQTCLASSINFO_H
3 3
4 4 /*
5 5 *
6 6 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
7 7 *
8 8 * This library is free software; you can redistribute it and/or
9 9 * modify it under the terms of the GNU Lesser General Public
10 10 * License as published by the Free Software Foundation; either
11 11 * version 2.1 of the License, or (at your option) any later version.
12 12 *
13 13 * This library is distributed in the hope that it will be useful,
14 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 16 * Lesser General Public License for more details.
17 17 *
18 18 * Further, this software is distributed without any warranty that it is
19 19 * free of the rightful claim of any third person regarding infringement
20 20 * or the like. Any license provided herein, whether implied or
21 21 * otherwise, applies only to this software file. Patent licenses, if
22 22 * any, provided herein do not apply to combinations of this program with
23 23 * other software, or any other product whatsoever.
24 24 *
25 25 * You should have received a copy of the GNU Lesser General Public
26 26 * License along with this library; if not, write to the Free Software
27 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 28 *
29 29 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
30 30 * 28359 Bremen, Germany or:
31 31 *
32 32 * http://www.mevis.de
33 33 *
34 34 */
35 35
36 36 #include <QMetaObject>
37 37 #include <QMetaMethod>
38 38 #include <QHash>
39 39 #include <QByteArray>
40 40 #include <QList>
41 41 #include "PythonQt.h"
42 42
43 43 class PythonQtSlotInfo;
44 44
45 45 struct PythonQtMemberInfo {
46 46 enum Type {
47 47 Invalid, Slot, EnumValue, EnumWrapper, Property, NotFound
48 48 };
49 49
50 50 PythonQtMemberInfo():_type(Invalid),_slot(NULL),_enumWrapper(NULL),_enumValue(0) { }
51 51
52 52 PythonQtMemberInfo(PythonQtSlotInfo* info) {
53 53 _type = Slot;
54 54 _slot = info;
55 55 _enumValue = NULL;
56 56 }
57 57
58 58 PythonQtMemberInfo(const PythonQtObjectPtr& enumValue) {
59 59 _type = EnumValue;
60 60 _slot = NULL;
61 61 _enumValue = enumValue;
62 62 _enumWrapper = NULL;
63 63 }
64 64
65 65 PythonQtMemberInfo(const QMetaProperty& prop) {
66 66 _type = Property;
67 67 _slot = NULL;
68 68 _enumValue = NULL;
69 69 _property = prop;
70 70 _enumWrapper = NULL;
71 71 }
72 72
73 73 Type _type;
74 74
75 75 // TODO: this could be a union...
76 76 PythonQtSlotInfo* _slot;
77 77 PyObject* _enumWrapper;
78 78 PythonQtObjectPtr _enumValue;
79 79 QMetaProperty _property;
80 80 };
81 81
82 82 //! a class that stores all required information about a Qt object (and an optional associated C++ class name)
83 83 /*! for fast lookup of slots when calling the object from Python
84 84 */
85 85 class PythonQtClassInfo {
86 86
87 87 public:
88 88 PythonQtClassInfo();
89 89 ~PythonQtClassInfo();
90 90
91 91 //! store information about parent classes
92 92 struct ParentClassInfo {
93 93 ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
94 94 {};
95 95
96 96 PythonQtClassInfo* _parent;
97 97 int _upcastingOffset;
98 98 };
99 99
100 100
101 101 //! setup as a QObject, taking the meta object as meta information about the QObject
102 102 void setupQObject(const QMetaObject* meta);
103 103
104 104 //! setup as a CPP (non-QObject), taking the classname
105 105 void setupCPPObject(const QByteArray& classname);
106 106
107 107 //! get the Python method definition for a given slot name (without return type and signature)
108 108 PythonQtMemberInfo member(const char* member);
109 109
110 110 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
111 111 PythonQtSlotInfo* constructors();
112 112
113 113 //! get access to the destructor slot
114 114 PythonQtSlotInfo* destructor();
115 115
116 116 //! add a constructor, ownership is passed to classinfo
117 117 void addConstructor(PythonQtSlotInfo* info);
118 118
119 119 //! set a destructor, ownership is passed to classinfo
120 120 void setDestructor(PythonQtSlotInfo* info);
121 121
122 122 //! add a decorator slot, ownership is passed to classinfo
123 123 void addDecoratorSlot(PythonQtSlotInfo* info);
124 124
125 125 //! get the classname (either of the QObject or of the wrapped CPP object)
126 126 const char* className();
127 127
128 128 //! returns if the QObject
129 129 bool isQObject() { return _isQObject; }
130 130
131 131 //! returns if the class is a CPP wrapper
132 132 bool isCPPWrapper() { return !_isQObject; }
133 133
134 134 //! get the meta object
135 135 const QMetaObject* metaObject() { return _meta; }
136 136
137 137 //! set the meta object, this will reset the caching
138 138 void setMetaObject(const QMetaObject* meta);
139 139
140 140 //! returns if this class inherits from the given classname
141 141 bool inherits(const char* classname);
142 142
143 143 //! returns if this class inherits from the given classinfo
144 144 bool inherits(PythonQtClassInfo* info);
145 145
146 146 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
147 147 //! which might be different to \c ptr due to C++ multiple inheritance
148 148 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
149 149 void* castTo(void* ptr, const char* classname);
150 150
151 151 //! get help string for the metaobject
152 152 QString help();
153 153
154 154 //! get list of all properties (on QObjects only, otherwise the list is empty)
155 155 QStringList propertyList();
156 156
157 157 //! get list of all members
158 158 QStringList memberList(bool metaOnly = false);
159 159
160 160 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
161 161 int metaTypeId() { return _metaTypeId; }
162 162
163 163 //! set an additional decorator provider that offers additional decorator slots for this class
164 164 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
165 165
166 166 //! get the decorator qobject instance
167 167 QObject* decorator();
168 168
169 169 //! add the parent class info of a CPP object
170 170 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
171 171
172 //! check if the special method "hasOwner" is implemented and if it returns false, which means that the object may be destroyed
172 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
173 173 bool hasOwnerMethodButNoOwner(void* object);
174 174
175 175 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
176 176 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
177 177
178 178 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
179 179 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
180 180
181 181 //! set the shell set instance wrapper cb
182 182 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
183 183 _shellSetInstanceWrapperCB = cb;
184 184 }
185 185
186 186 //! get the shell set instance wrapper cb
187 187 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
188 188 return _shellSetInstanceWrapperCB;
189 189 }
190 190
191 191 //! add a handler for polymorphic downcasting
192 192 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
193 193
194 194 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
195 195 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
196 196
197 197 //! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
198 198 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
199 199
200 200 private:
201 201 void createEnumWrappers();
202 202 void createEnumWrappers(const QMetaObject* meta);
203 203 PyObject* findEnumWrapper(const char* name);
204 204
205 205 //! clear all cached members
206 206 void clearCachedMembers();
207 207
208 208 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
209 209
210 210 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
211 211 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
212 212 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
213 213
214 214 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
215 215 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
216 216
217 217 bool lookForPropertyAndCache(const char* memberName);
218 218 bool lookForMethodAndCache(const char* memberName);
219 219 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
220 220
221 221 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
222 222 int findCharOffset(const char* sigStart, char someChar);
223 223
224 224 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
225 225
226 226 PythonQtSlotInfo* _constructors;
227 227 PythonQtSlotInfo* _destructor;
228 228 QList<PythonQtSlotInfo*> _decoratorSlots;
229 229
230 230 QList<PythonQtObjectPtr> _enumWrappers;
231 231
232 232 const QMetaObject* _meta;
233 233
234 234 QByteArray _wrappedClassName;
235 235 QList<ParentClassInfo> _parentClasses;
236 236
237 237 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
238 238
239 239 QObject* _decoratorProvider;
240 240 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
241 241
242 242 PyObject* _pythonQtClassWrapper;
243 243
244 244 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
245 245
246 246 int _metaTypeId;
247 247
248 248 bool _isQObject;
249 249 bool _enumsCreated;
250 250
251 251 };
252 252
253 253 //---------------------------------------------------------------
254 254
255 255
256 256 #endif
@@ -1,641 +1,671
1 1 /*
2 2 *
3 3 * Copyright (C) 2006 MeVis Research GmbH 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 Research GmbH, 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 PythonQtInstanceWrapper.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 "PythonQtInstanceWrapper.h"
43 43 #include <QObject>
44 44 #include "PythonQt.h"
45 45 #include "PythonQtSlot.h"
46 46 #include "PythonQtClassInfo.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtClassWrapper.h"
49 49
50 50 PythonQtClassInfo* PythonQtInstanceWrapperStruct::classInfo()
51 51 {
52 52 // take the class info from our type object
53 53 return ((PythonQtClassWrapper*)ob_type)->_classInfo;
54 54 }
55 55
56 56 static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, bool force = false) {
57 57
58 58 // is this a C++ wrapper?
59 59 if (self->_wrappedPtr) {
60 60 //mlabDebugConst("Python","c++ wrapper removed " << self->_wrappedPtr << " " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
61 61
62 62 PythonQt::priv()->removeWrapperPointer(self->_wrappedPtr);
63 63 // we own our qobject, so we delete it now:
64 64 delete self->_obj;
65 65 self->_obj = NULL;
66 66 if (force || self->classInfo()->hasOwnerMethodButNoOwner(self->_wrappedPtr) || self->_ownedByPythonQt) {
67 67 int type = self->classInfo()->metaTypeId();
68 68 if (self->_useQMetaTypeDestroy && type>=0) {
69 69 // use QMetaType to destroy the object
70 70 QMetaType::destroy(type, self->_wrappedPtr);
71 71 } else {
72 72 PythonQtSlotInfo* slot = self->classInfo()->destructor();
73 73 if (slot) {
74 74 void* args[2];
75 75 args[0] = NULL;
76 76 args[1] = &self->_wrappedPtr;
77 77 slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, slot->slotIndex(), args);
78 78 self->_wrappedPtr = NULL;
79 79 } else {
80 80 if (type>=0) {
81 81 // use QMetaType to destroy the object
82 82 QMetaType::destroy(type, self->_wrappedPtr);
83 83 } else {
84 84 // TODO: warn about not being able to destroy the object?
85 85 }
86 86 }
87 87 }
88 88 }
89 89 } else {
90 90 //mlabDebugConst("Python","qobject wrapper removed " << self->_obj->className() << " " << self->classInfo()->wrappedClassName().latin1());
91 91 if (self->_objPointerCopy) {
92 92 PythonQt::priv()->removeWrapperPointer(self->_objPointerCopy);
93 93 }
94 94 if (self->_obj) {
95 95 if (force || self->_ownedByPythonQt) {
96 96 if (force || !self->_obj->parent()) {
97 97 delete self->_obj;
98 98 }
99 99 } else {
100 100 if (self->_obj->parent()==NULL) {
101 101 // tell someone who is interested that the qobject is no longer wrapped, if it has no parent
102 102 PythonQt::qObjectNoLongerWrappedCB(self->_obj);
103 103 }
104 104 }
105 105 }
106 106 }
107 107 self->_obj = NULL;
108 108 }
109 109
110 110 static void PythonQtInstanceWrapper_dealloc(PythonQtInstanceWrapper* self)
111 111 {
112 112 PythonQtInstanceWrapper_deleteObject(self);
113 113 self->_obj.~QPointer<QObject>();
114 114 self->ob_type->tp_free((PyObject*)self);
115 115 }
116 116
117 117 static PyObject* PythonQtInstanceWrapper_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
118 118 {
119 119 //PythonQtClassWrapper *classType = (PythonQtClassWrapper*)type;
120 120 PythonQtInstanceWrapper *self;
121 121 static PyObject* emptyTuple = NULL;
122 122 if (emptyTuple==NULL) {
123 123 emptyTuple = PyTuple_New(0);
124 124 }
125 125
126 126 self = (PythonQtInstanceWrapper*)PyBaseObject_Type.tp_new(type, emptyTuple, NULL);
127 127
128 128 if (self != NULL) {
129 129 new (&self->_obj) QPointer<QObject>();
130 130 self->_wrappedPtr = NULL;
131 131 self->_ownedByPythonQt = false;
132 132 self->_useQMetaTypeDestroy = false;
133 133 self->_isShellInstance = false;
134 134 }
135 135 return (PyObject *)self;
136 136 }
137 137
138 138 int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds)
139 139 {
140 140 if (args == PythonQtPrivate::dummyTuple()) {
141 141 // we are called from the internal PythonQt API, so our data will be filled later on...
142 142 return 0;
143 143 }
144 144
145 145 // we are called from python, try to construct our object
146 146 if (self->classInfo()->constructors()) {
147 147 void* directCPPPointer = NULL;
148 148 PythonQtSlotFunction_CallImpl(self->classInfo(), NULL, self->classInfo()->constructors(), args, kwds, NULL, &directCPPPointer);
149 149 if (PyErr_Occurred()) {
150 150 return -1;
151 151 }
152 152 if (directCPPPointer) {
153 153 // change ownershipflag to be owned by PythonQt
154 154 self->_ownedByPythonQt = true;
155 155 self->_useQMetaTypeDestroy = false;
156 156 if (self->classInfo()->isCPPWrapper()) {
157 157 self->_wrappedPtr = directCPPPointer;
158 158 // TODO xxx: if there is a wrapper factory, we might want to generate a wrapper for our class?!
159 159 } else {
160 160 self->setQObject((QObject*)directCPPPointer);
161 161 }
162 162 // register with PythonQt
163 163 PythonQt::priv()->addWrapperPointer(directCPPPointer, self);
164 164
165 165 PythonQtShellSetInstanceWrapperCB* cb = self->classInfo()->shellSetInstanceWrapperCB();
166 166 if (cb) {
167 167 // if we are a derived python class, we set the wrapper
168 168 // to activate the shell class, otherwise we just ignore that it is a shell...
169 169 // we detect it be checking if the type does not have PythonQtInstanceWrapper_Type as direct base class,
170 170 // which is the case for all non-python derived types
171 171 if (((PyObject*)self)->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
172 172 // set the wrapper and remember that we have a shell instance!
173 173 (*cb)(directCPPPointer, self);
174 174 self->_isShellInstance = true;
175 175 }
176 176 }
177 177 }
178 178 } else {
179 179 QString error = QString("No constructors available for ") + self->classInfo()->className();
180 180 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
181 181 return -1;
182 182 }
183 183 return 0;
184 184 }
185 185
186 186 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
187 187 {
188 188 return PyString_FromString(obj->ob_type->tp_name);
189 189 }
190 190
191 191 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
192 192 {
193 193 return PythonQt::self()->helpCalled(obj->classInfo());
194 194 }
195 195
196 196 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
197 197 {
198 198 PythonQtInstanceWrapper_deleteObject(self, true);
199 199 Py_INCREF(Py_None);
200 200 return Py_None;
201 201 }
202 202
203 203
204 204 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
205 205 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
206 206 "Return the classname of the object"
207 207 },
208 208 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
209 209 "Shows the help of available methods for this class"
210 210 },
211 211 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
212 212 "Deletes the C++ object (at your own risk, my friend!)"
213 213 },
214 214 {NULL, NULL, 0, NULL} /* Sentinel */
215 215 };
216 216
217 217
218 218 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
219 219 {
220 220 const char *attributeName;
221 221 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
222 222
223 223 if ((attributeName = PyString_AsString(name)) == NULL) {
224 224 return NULL;
225 225 }
226 226
227 227 if (qstrcmp(attributeName, "__dict__")==0) {
228 228 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
229 229 dict = PyDict_Copy(dict);
230 230
231 231 if (wrapper->_obj) {
232 232 // only the properties are missing, the rest is already available from
233 233 // PythonQtClassWrapper...
234 234 QStringList l = wrapper->classInfo()->propertyList();
235 235 foreach (QString name, l) {
236 236 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
237 237 if (o) {
238 238 PyDict_SetItemString(dict, name.toLatin1().data(), o);
239 239 Py_DECREF(o);
240 240 } else {
241 241 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
242 242 }
243 243 }
244 244
245 245 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
246 246 foreach (QByteArray name, dynamicProps) {
247 247 PyObject* o = PyObject_GetAttrString(obj, name.data());
248 248 if (o) {
249 249 PyDict_SetItemString(dict, name.data(), o);
250 250 Py_DECREF(o);
251 251 } else {
252 252 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
253 253 }
254 254 }
255 255 }
256 256 // Note: we do not put children into the dict, is would look confusing?!
257 257 return dict;
258 258 }
259 259
260 260 // first look in super, to return derived methods from base object first
261 261 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
262 262 if (superAttr) {
263 263 return superAttr;
264 264 }
265 265 PyErr_Clear();
266 266
267 267 // mlabDebugConst("Python","get " << attributeName);
268 268
269 269 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
270 270 switch (member._type) {
271 271 case PythonQtMemberInfo::Property:
272 272 if (wrapper->_obj) {
273 273 if (member._property.userType() != QVariant::Invalid) {
274 274 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
275 275 } else {
276 276 Py_INCREF(Py_None);
277 277 return Py_None;
278 278 }
279 279 } else {
280 280 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
281 281 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
282 282 return NULL;
283 283 }
284 284 break;
285 285 case PythonQtMemberInfo::Slot:
286 286 return PythonQtSlotFunction_New(member._slot, obj, NULL);
287 287 break;
288 288 case PythonQtMemberInfo::EnumValue:
289 289 {
290 290 PyObject* enumValue = member._enumValue;
291 291 Py_INCREF(enumValue);
292 292 return enumValue;
293 293 }
294 294 break;
295 295 case PythonQtMemberInfo::EnumWrapper:
296 296 {
297 297 PyObject* enumWrapper = member._enumWrapper;
298 298 Py_INCREF(enumWrapper);
299 299 return enumWrapper;
300 300 }
301 301 break;
302 302 case PythonQtMemberInfo::NotFound:
303 303 {
304 // check for a getter_
305 PythonQtMemberInfo member = wrapper->classInfo()->member(QByteArray("getter_") + attributeName);
304 static const QByteArray getterString("py_get_");
305 // check for a getter slot
306 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
306 307 if (member._type == PythonQtMemberInfo::Slot) {
307 308 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
308 309 }
309 310
310 311 // handle dynamic properties
311 312 if (wrapper->_obj) {
312 313 QVariant v = wrapper->_obj->property(attributeName);
313 314 if (v.isValid()) {
314 315 return PythonQtConv::QVariantToPyObject(v);
315 316 }
316 317 }
317 318 }
318 319 break;
319 320 default:
320 321 // is an invalid type, go on
321 322 break;
322 323 }
323 324
324 325 // look for the internal methods (className(), help())
325 326 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
326 327 if (internalMethod) {
327 328 return internalMethod;
328 329 }
329 330 PyErr_Clear();
330 331
331 332 if (wrapper->_obj) {
332 333 // look for a child
333 334 QObjectList children = wrapper->_obj->children();
334 335 for (int i = 0; i < children.count(); i++) {
335 336 QObject *child = children.at(i);
336 337 if (child->objectName() == attributeName) {
337 338 return PythonQt::priv()->wrapQObject(child);
338 339 }
339 340 }
340 341 }
341 342
342 343 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
343 344 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
344 345 return NULL;
345 346 }
346 347
347 348 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
348 349 {
349 350 QString error;
350 351 const char *attributeName;
351 352 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
352 353
353 354 if ((attributeName = PyString_AsString(name)) == NULL)
354 355 return -1;
355 356
356 357 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
357 358 if (member._type == PythonQtMemberInfo::Property) {
358 359
359 360 if (!wrapper->_obj) {
360 361 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
361 362 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
362 363 return -1;
363 364 }
364 365
365 366 QMetaProperty prop = member._property;
366 367 if (prop.isWritable()) {
367 368 QVariant v;
368 369 if (prop.isEnumType()) {
369 370 // this will give us either a string or an int, everything else will probably be an error
370 371 v = PythonQtConv::PyObjToQVariant(value);
371 372 } else {
372 373 int t = prop.userType();
373 374 v = PythonQtConv::PyObjToQVariant(value, t);
374 375 }
375 376 bool success = false;
376 377 if (v.isValid()) {
377 378 success = prop.write(wrapper->_obj, v);
378 379 }
379 380 if (success) {
380 381 return 0;
381 382 } else {
382 383 error = QString("Property '") + attributeName + "' of type '" +
383 384 prop.typeName() + "' does not accept an object of type "
384 385 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
385 386 }
386 387 } else {
387 388 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
388 389 }
389 390 } else if (member._type == PythonQtMemberInfo::Slot) {
390 391 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
391 392 } else if (member._type == PythonQtMemberInfo::EnumValue) {
392 393 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
393 394 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
394 395 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
395 396 } else if (member._type == PythonQtMemberInfo::NotFound) {
396 // check for a setter_
397 PythonQtMemberInfo setter = wrapper->classInfo()->member(QByteArray("setter_") + attributeName);
397 // check for a setter slot
398 static const QByteArray setterString("py_set_");
399 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
398 400 if (setter._type == PythonQtMemberInfo::Slot) {
399 401 // call the setter and ignore the result value
400 402 void* result;
401 403 PyObject* args = PyTuple_New(1);
402 404 Py_INCREF(value);
403 405 PyTuple_SET_ITEM(args, 0, value);
404 406 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
405 407 Py_DECREF(args);
406 408 return 0;
407 409 }
408 410
409 411 // handle dynamic properties
410 412 if (wrapper->_obj) {
411 413 QVariant prop = wrapper->_obj->property(attributeName);
412 414 if (prop.isValid()) {
413 415 QVariant v = PythonQtConv::PyObjToQVariant(value);
414 416 if (v.isValid()) {
415 417 wrapper->_obj->setProperty(attributeName, v);
416 418 return 0;
417 419 } else {
418 420 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
419 421 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
420 422 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
421 423 return -1;
422 424 }
423 425 }
424 426 }
425 427
426 428 // if we are a derived python class, we allow setting attributes.
427 429 // if we are a direct CPP wrapper, we do NOT allow it, since
428 430 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
429 431 // and when it is recreated from a CPP pointer the attributes are gone...
430 432 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
431 433 return PyBaseObject_Type.tp_setattro(obj,name,value);
432 434 } else {
433 435 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
434 436 }
435 437 }
436 438
437 439 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
438 440 return -1;
439 441 }
440 442
443 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
444 QString result;
445 if (wrapper->_wrappedPtr) {
446 // first try some manually string conversions for some variants
447 int metaid = wrapper->classInfo()->metaTypeId();
448 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
449 if (!result.isEmpty()) {
450 return result;
451 }
452 }
453 // next, try to call py_toString
454 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
455 if (info._type == PythonQtMemberInfo::Slot) {
456 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
457 if (resultObj) {
458 // TODO this is one conversion too much, would be nicer to call the slot directly...
459 result = PythonQtConv::PyObjGetString(resultObj);
460 Py_DECREF(resultObj);
461 }
462 }
463 return result;
464 }
465
441 466 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
442 467 {
443 468 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
444 469 const char* typeName = obj->ob_type->tp_name;
445 470 QObject *qobj = wrapper->_obj;
446 if (wrapper->_wrappedPtr) {
447 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
471 QString str = getStringFromObject(wrapper);
448 472 if (!str.isEmpty()) {
449 473 return PyString_FromFormat("%s", str.toLatin1().constData());
450 } else
474 }
475 if (wrapper->_wrappedPtr) {
451 476 if (wrapper->_obj) {
452 477 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
453 478 } else {
454 479 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
455 480 }
456 481 } else {
457 482 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
458 483 }
459 484 }
460 485
461 486 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
462 487 {
463 488 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
464 489 const char* typeName = obj->ob_type->tp_name;
465 490
466 491 QObject *qobj = wrapper->_obj;
467 if (wrapper->_wrappedPtr) {
468 QString str = PythonQtConv::CPPObjectToString(wrapper->classInfo()->metaTypeId(), wrapper->_wrappedPtr);
492 QString str = getStringFromObject(wrapper);
469 493 if (!str.isEmpty()) {
494 if (str.startsWith(typeName)) {
495 return PyString_FromFormat("%s", str.toLatin1().constData());
496 } else {
470 497 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
471 } else
498 }
499 }
500 if (wrapper->_wrappedPtr) {
472 501 if (wrapper->_obj) {
473 502 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
474 503 } else {
475 504 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
476 505 }
477 506 } else {
478 507 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
479 508 }
480 509 }
481 510
482 511 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2)
483 512 {
484 513 if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) &&
485 514 PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) {
486 515
487 516 PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1;
488 517 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2;
489 518 // check pointers directly first:
490 519 if (w1->_wrappedPtr != NULL) {
491 520 if (w1->_wrappedPtr == w2->_wrappedPtr) {
492 521 return 0;
493 522 }
494 523 } else if (w1->_obj == w2->_obj) {
495 524 return 0;
496 525 }
497 526 const char* class1 = w1->classInfo()->className();
498 527 const char* class2 = w2->classInfo()->className();
499 528 if (strcmp(class1, class2) == 0) {
500 529 // same class names, so we can try the operator_equal
501 530 PythonQtMemberInfo info = w1->classInfo()->member("operator_equal");
502 531 if (info._type == PythonQtMemberInfo::Slot) {
503 532 bool result = false;
504 533 void* obj1 = w1->_wrappedPtr;
505 534 if (!obj1) {
506 535 obj1 = w1->_obj;
507 536 }
508 537 if (!obj1) { return -1; }
509 538 void* obj2 = w2->_wrappedPtr;
510 539 if (!obj2) {
511 540 obj2 = w2->_obj;
512 541 }
513 542 if (!obj2) { return -1; }
514 543 if (info._slot->isInstanceDecorator()) {
515 544 // call on decorator QObject
516 545 void* args[3];
517 546 args[0] = &result;
518 547 args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer
519 548 args[2] = obj2; // this is a reference, so it needs the direct pointer
520 549 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
521 550 return result?0:-1;
522 551 } else {
523 552 // call directly on QObject
524 553 if (w1->_obj && w2->_obj) {
525 554 void* args[2];
526 555 args[0] = &result;
527 556 args[1] = obj2; // this is a reference, so it needs the direct pointer
528 557 w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
558 return result?0:-1;
529 559 }
530 560 }
531 561 }
532 562 }
533 563 }
534 564 return -1;
535 565 }
536 566
537 567 static int PythonQtInstanceWrapper_nonzero(PyObject *obj)
538 568 {
539 569 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
540 570 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
541 571 }
542 572
543 573
544 574 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
545 575 {
546 576 if (obj->_wrappedPtr != NULL) {
547 577 return reinterpret_cast<long>(obj->_wrappedPtr);
548 578 } else {
549 579 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
550 580 return reinterpret_cast<long>(qobj);
551 581 }
552 582 }
553 583
554 584
555 585
556 586 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
557 587 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
558 588 0, /* nb_add */
559 589 0, /* nb_subtract */
560 590 0, /* nb_multiply */
561 591 0, /* nb_divide */
562 592 0, /* nb_remainder */
563 593 0, /* nb_divmod */
564 594 0, /* nb_power */
565 595 0, /* nb_negative */
566 596 0, /* nb_positive */
567 597 0, /* nb_absolute */
568 598 PythonQtInstanceWrapper_nonzero, /* nb_nonzero */
569 599 0, /* nb_invert */
570 600 0, /* nb_lshift */
571 601 0, /* nb_rshift */
572 602 0, /* nb_and */
573 603 0, /* nb_xor */
574 604 0, /* nb_or */
575 605 0, /* nb_coerce */
576 606 0, /* nb_int */
577 607 0, /* nb_long */
578 608 0, /* nb_float */
579 609 0, /* nb_oct */
580 610 0, /* nb_hex */
581 611 0, /* nb_inplace_add */
582 612 0, /* nb_inplace_subtract */
583 613 0, /* nb_inplace_multiply */
584 614 0, /* nb_inplace_divide */
585 615 0, /* nb_inplace_remainder */
586 616 0, /* nb_inplace_power */
587 617 0, /* nb_inplace_lshift */
588 618 0, /* nb_inplace_rshift */
589 619 0, /* nb_inplace_and */
590 620 0, /* nb_inplace_xor */
591 621 0, /* nb_inplace_or */
592 622 0, /* nb_floor_divide */
593 623 0, /* nb_true_divide */
594 624 0, /* nb_inplace_floor_divide */
595 625 0, /* nb_inplace_true_divide */
596 626 };
597 627
598 628 PyTypeObject PythonQtInstanceWrapper_Type = {
599 629 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
600 630 0, /*ob_size*/
601 631 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
602 632 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
603 633 0, /*tp_itemsize*/
604 634 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
605 635 0, /*tp_print*/
606 636 0, /*tp_getattr*/
607 637 0, /*tp_setattr*/
608 638 PythonQtInstanceWrapper_compare, /*tp_compare*/
609 639 PythonQtInstanceWrapper_repr, /*tp_repr*/
610 640 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
611 641 0, /*tp_as_sequence*/
612 642 0, /*tp_as_mapping*/
613 643 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
614 644 0, /*tp_call*/
615 645 PythonQtInstanceWrapper_str, /*tp_str*/
616 646 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
617 647 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
618 648 0, /*tp_as_buffer*/
619 649 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
620 650 "PythonQtInstanceWrapper object", /* tp_doc */
621 651 0, /* tp_traverse */
622 652 0, /* tp_clear */
623 653 0, /* tp_richcompare */
624 654 0, /* tp_weaklistoffset */
625 655 0, /* tp_iter */
626 656 0, /* tp_iternext */
627 657 0, /* tp_methods */
628 658 0, /* tp_members */
629 659 0, /* tp_getset */
630 660 0, /* tp_base */
631 661 0, /* tp_dict */
632 662 0, /* tp_descr_get */
633 663 0, /* tp_descr_set */
634 664 0, /* tp_dictoffset */
635 665 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
636 666 0, /* tp_alloc */
637 667 PythonQtInstanceWrapper_new, /* tp_new */
638 668 };
639 669
640 670 //-------------------------------------------------------
641 671
General Comments 0
You need to be logged in to leave comments. Login now