##// END OF EJS Templates
enabled signals to be emitted by simply calling them...
florianlink -
r69:5f2efada2db6
parent child
Show More
@@ -1,841 +1,843
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 bool found = false;
122 122 bool nameMapped = false;
123 123 const char* attributeName = memberName;
124 124 // look for properties
125 125 int i = _meta->indexOfProperty(attributeName);
126 126 if (i==-1) {
127 127 // try to map name to objectName
128 128 if (qstrcmp(attributeName, "name")==0) {
129 129 attributeName = "objectName";
130 130 nameMapped = true;
131 131 i = _meta->indexOfProperty(attributeName);
132 132 }
133 133 }
134 134 if (i!=-1) {
135 135 PythonQtMemberInfo newInfo(_meta->property(i));
136 136 _cachedMembers.insert(attributeName, newInfo);
137 137 if (nameMapped) {
138 138 _cachedMembers.insert(memberName, newInfo);
139 139 }
140 140 #ifdef PYTHONQT_DEBUG
141 141 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
142 142 #endif
143 143 found = true;
144 144 }
145 145 return found;
146 146 }
147 147
148 148 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
149 149 {
150 150 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
151 151 foreach(const ParentClassInfo& info, _parentClasses) {
152 152 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
153 153 }
154 154 return inputInfo;
155 155 }
156 156
157 157 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
158 158 QObject* decoratorProvider = decorator();
159 159 int memberNameLen = strlen(memberName);
160 160 if (decoratorProvider) {
161 161 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
162 162 const QMetaObject* meta = decoratorProvider->metaObject();
163 163 int numMethods = meta->methodCount();
164 164 int startFrom = QObject::staticMetaObject.methodCount();
165 165 for (int i = startFrom; i < numMethods; i++) {
166 166 QMetaMethod m = meta->method(i);
167 167 if ((m.methodType() == QMetaMethod::Method ||
168 168 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
169 169
170 170 const char* sigStart = m.signature();
171 171 bool isClassDeco = false;
172 172 if (qstrncmp(sigStart, "static_", 7)==0) {
173 173 // skip the static_classname_ part of the string
174 174 sigStart += 7 + 1 + strlen(className());
175 175 isClassDeco = true;
176 176 } else if (qstrncmp(sigStart, "new_", 4)==0) {
177 177 isClassDeco = true;
178 178 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
179 179 isClassDeco = true;
180 180 }
181 181 // find the first '('
182 182 int offset = findCharOffset(sigStart, '(');
183 183
184 184 // XXX no checking is currently done if the slots have correct first argument or not...
185 185
186 186 // check if same length and same name
187 187 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
188 188 found = true;
189 189 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
190 190 info->setUpcastingOffset(upcastingOffset);
191 191 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
192 192 if (tail) {
193 193 tail->setNextInfo(info);
194 194 } else {
195 195 PythonQtMemberInfo newInfo(info);
196 196 memberCache.insert(memberName, newInfo);
197 197 }
198 198 tail = info;
199 199 }
200 200 }
201 201 }
202 202 }
203 203
204 204 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
205 205
206 206 return tail;
207 207 }
208 208
209 209 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
210 210 {
211 211 bool found = false;
212 212 int memberNameLen = strlen(memberName);
213 213 PythonQtSlotInfo* tail = NULL;
214 214 if (_meta) {
215 215 int numMethods = _meta->methodCount();
216 216 for (int i = 0; i < numMethods; i++) {
217 217 QMetaMethod m = _meta->method(i);
218 if ((m.methodType() == QMetaMethod::Method ||
219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
218 if (((m.methodType() == QMetaMethod::Method ||
219 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
220 || m.methodType()==QMetaMethod::Signal) {
220 221
221 222 const char* sigStart = m.signature();
222 223 // find the first '('
223 224 int offset = findCharOffset(sigStart, '(');
224 225
225 226 // check if same length and same name
226 227 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
227 228 found = true;
228 229 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
229 230 if (tail) {
230 231 tail->setNextInfo(info);
231 232 } else {
232 233 PythonQtMemberInfo newInfo(info);
233 234 _cachedMembers.insert(memberName, newInfo);
234 235 }
235 236 tail = info;
236 237 }
237 238 }
238 239 }
239 240 }
240 241
241 242 // look for dynamic decorators in this class and in derived classes
242 243 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
243 244
244 245 return found;
245 246 }
246 247
247 248 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
248 249 {
249 250 bool found = false;
250 251 // look for enum values
251 252 int enumCount = meta->enumeratorCount();
252 253 for (int i=0;i<enumCount; i++) {
253 254 QMetaEnum e = meta->enumerator(i);
254 255 // we do not want flags, they will cause our values to appear two times
255 256 if (e.isFlag()) continue;
256 257
257 258 for (int j=0; j < e.keyCount(); j++) {
258 259 if (qstrcmp(e.key(j), memberName)==0) {
259 260 PyObject* enumType = findEnumWrapper(e.name());
260 261 if (enumType) {
261 262 PythonQtObjectPtr enumValuePtr;
262 263 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
263 264 PythonQtMemberInfo newInfo(enumValuePtr);
264 265 _cachedMembers.insert(memberName, newInfo);
265 266 #ifdef PYTHONQT_DEBUG
266 267 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
267 268 #endif
268 269 found = true;
269 270 break;
270 271 } else {
271 272 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
272 273 }
273 274 }
274 275 }
275 276 }
276 277 return found;
277 278 }
278 279
279 280 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
280 281 {
281 282 PythonQtMemberInfo info = _cachedMembers.value(memberName);
282 283 if (info._type != PythonQtMemberInfo::Invalid) {
283 284 return info;
284 285 } else {
285 286 bool found = false;
286 287
287 288 found = lookForPropertyAndCache(memberName);
288 289 if (!found) {
289 290 found = lookForMethodAndCache(memberName);
290 291 }
291 292 if (!found) {
292 293 if (_meta) {
293 294 // check enums in our meta object directly
294 295 found = lookForEnumAndCache(_meta, memberName);
295 296 }
296 297 if (!found) {
297 298 // check enums in the class hierachy of CPP classes
298 299 // look for dynamic decorators in this class and in derived classes
299 300 QList<QObject*> decoObjects;
300 301 recursiveCollectDecoratorObjects(decoObjects);
301 302 foreach(QObject* deco, decoObjects) {
302 303 // call on ourself for caching, but with different metaObject():
303 304 found = lookForEnumAndCache(deco->metaObject(), memberName);
304 305 if (found) {
305 306 break;
306 307 }
307 308 }
308 309 }
309 310 }
310 311 if (!found) {
311 312 // maybe it is an enum wrapper?
312 313 PyObject* p = findEnumWrapper(memberName);
313 314 if (p) {
314 315 info._type = PythonQtMemberInfo::EnumWrapper;
315 316 info._enumWrapper = p;
316 317 _cachedMembers.insert(memberName, info);
317 318 found = true;
318 319 }
319 320 }
320 321 if (!found) {
321 322 // since python keywords can not be looked up, we check if the name contains a single trailing _
322 323 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
323 324 QByteArray mbrName(memberName);
324 325 if ((mbrName.length()>2) &&
325 326 (mbrName.at(mbrName.length()-1) == '_') &&
326 327 (mbrName.at(mbrName.length()-2) != '_')) {
327 328 mbrName = mbrName.mid(0,mbrName.length()-1);
328 329 found = lookForMethodAndCache(mbrName.constData());
329 330 if (found) {
330 331 return _cachedMembers.value(mbrName);
331 332 }
332 333 }
333 334 }
334 335 if (!found) {
335 336 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
336 337 info._type = PythonQtMemberInfo::NotFound;
337 338 _cachedMembers.insert(memberName, info);
338 339 }
339 340 }
340 341
341 342 return _cachedMembers.value(memberName);
342 343 }
343 344
344 345 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
345 346 QObject* deco = decorator();
346 347 if (deco) {
347 348 decoratorObjects.append(deco);
348 349 }
349 350 foreach(const ParentClassInfo& info, _parentClasses) {
350 351 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
351 352 }
352 353 }
353 354
354 355 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
355 356 classInfoObjects.append(this);
356 357 foreach(const ParentClassInfo& info, _parentClasses) {
357 358 info._parent->recursiveCollectClassInfos(classInfoObjects);
358 359 }
359 360 }
360 361
361 362 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
362 363 {
363 364 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
364 365 while (it.hasNext()) {
365 366
366 367 PythonQtSlotInfo* infoOrig = it.next();
367 368
368 369 const char* sigStart = infoOrig->metaMethod()->signature();
369 370 if (qstrncmp("static_", sigStart, 7)==0) {
370 371 sigStart += 7;
371 372 sigStart += findCharOffset(sigStart, '_')+1;
372 373 }
373 374 int offset = findCharOffset(sigStart, '(');
374 375 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
375 376 //make a copy, otherwise we will have trouble on overloads!
376 377 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
377 378 info->setUpcastingOffset(upcastingOffset);
378 379 found = true;
379 380 if (tail) {
380 381 tail->setNextInfo(info);
381 382 } else {
382 383 PythonQtMemberInfo newInfo(info);
383 384 memberCache.insert(memberName, newInfo);
384 385 }
385 386 tail = info;
386 387 }
387 388 }
388 389 return tail;
389 390 }
390 391
391 392 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
392 393 QObject* decoratorProvider = decorator();
393 394 if (decoratorProvider) {
394 395 const QMetaObject* meta = decoratorProvider->metaObject();
395 396 int numMethods = meta->methodCount();
396 397 int startFrom = QObject::staticMetaObject.methodCount();
397 398 for (int i = startFrom; i < numMethods; i++) {
398 399 QMetaMethod m = meta->method(i);
399 400 if ((m.methodType() == QMetaMethod::Method ||
400 401 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
401 402
402 403 const char* sigStart = m.signature();
403 404 bool isClassDeco = false;
404 405 if (qstrncmp(sigStart, "static_", 7)==0) {
405 406 // skip the static_classname_ part of the string
406 407 sigStart += 7 + 1 + strlen(className());
407 408 isClassDeco = true;
408 409 } else if (qstrncmp(sigStart, "new_", 4)==0) {
409 410 continue;
410 411 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
411 412 continue;
412 413 }
413 414 // find the first '('
414 415 int offset = findCharOffset(sigStart, '(');
415 416
416 417 // XXX no checking is currently done if the slots have correct first argument or not...
417 418 if (!metaOnly || isClassDeco) {
418 419 list << QString::fromLatin1(sigStart, offset);
419 420 }
420 421 }
421 422 }
422 423 }
423 424
424 425 // look for global decorator slots
425 426 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
426 427 while (it.hasNext()) {
427 428 PythonQtSlotInfo* slot = it.next();
428 429 if (metaOnly) {
429 430 if (slot->isClassDecorator()) {
430 431 QByteArray first = slot->slotName();
431 432 if (first.startsWith("static_")) {
432 433 int idx = first.indexOf('_');
433 434 idx = first.indexOf('_', idx+1);
434 435 first = first.mid(idx+1);
435 436 }
436 437 list << first;
437 438 }
438 439 } else {
439 440 list << slot->slotName();
440 441 }
441 442 }
442 443 }
443 444
444 445 QStringList PythonQtClassInfo::propertyList()
445 446 {
446 447 QStringList l;
447 448 if (_isQObject && _meta) {
448 449 int i;
449 450 int numProperties = _meta->propertyCount();
450 451 for (i = 0; i < numProperties; i++) {
451 452 QMetaProperty p = _meta->property(i);
452 453 l << QString(p.name());
453 454 }
454 455 }
455 456 return l;
456 457 }
457 458
458 459 QStringList PythonQtClassInfo::memberList(bool metaOnly)
459 460 {
460 461 decorator();
461 462
462 463 QStringList l;
463 464 QString h;
464 465 if (_isQObject && _meta && !metaOnly) {
465 466 l = propertyList();
466 467 }
467 468
468 469 // normal slots of QObject (or wrapper QObject)
469 470 if (!metaOnly && _meta) {
470 471 int numMethods = _meta->methodCount();
471 472 bool skipQObj = !_isQObject;
472 473 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
473 474 QMetaMethod m = _meta->method(i);
474 if ((m.methodType() == QMetaMethod::Method ||
475 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
475 if (((m.methodType() == QMetaMethod::Method ||
476 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
477 || m.methodType()==QMetaMethod::Signal) {
476 478 QByteArray signa(m.signature());
477 479 signa = signa.left(signa.indexOf('('));
478 480 l << signa;
479 481 }
480 482 }
481 483 }
482 484
483 485 {
484 486 // look for dynamic decorators in this class and in derived classes
485 487 QList<PythonQtClassInfo*> infos;
486 488 recursiveCollectClassInfos(infos);
487 489 foreach(PythonQtClassInfo* info, infos) {
488 490 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
489 491 }
490 492 }
491 493
492 494 // List enumerator keys...
493 495 QList<const QMetaObject*> enumMetaObjects;
494 496 if (_meta) {
495 497 enumMetaObjects << _meta;
496 498 }
497 499 // check enums in the class hierachy of CPP classes
498 500 QList<QObject*> decoObjects;
499 501 recursiveCollectDecoratorObjects(decoObjects);
500 502 foreach(QObject* deco, decoObjects) {
501 503 enumMetaObjects << deco->metaObject();
502 504 }
503 505
504 506 foreach(const QMetaObject* meta, enumMetaObjects) {
505 507 for (int i = 0; i<meta->enumeratorCount(); i++) {
506 508 QMetaEnum e = meta->enumerator(i);
507 509 l << e.name();
508 510 // we do not want flags, they will cause our values to appear two times
509 511 if (e.isFlag()) continue;
510 512
511 513 for (int j=0; j < e.keyCount(); j++) {
512 514 l << QString(e.key(j));
513 515 }
514 516 }
515 517 }
516 518
517 519 return QSet<QString>::fromList(l).toList();
518 520 }
519 521
520 522 const char* PythonQtClassInfo::className()
521 523 {
522 524 return _wrappedClassName.constData();
523 525 }
524 526
525 527 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
526 528 {
527 529 if (ptr==NULL) {
528 530 return NULL;
529 531 }
530 532 if (_wrappedClassName == classname) {
531 533 return ptr;
532 534 }
533 535 foreach(const ParentClassInfo& info, _parentClasses) {
534 536 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
535 537 if (result) {
536 538 return result;
537 539 }
538 540 }
539 541 return NULL;
540 542 }
541 543
542 544 bool PythonQtClassInfo::inherits(const char* name)
543 545 {
544 546 if (_wrappedClassName == name) {
545 547 return true;
546 548 }
547 549 foreach(const ParentClassInfo& info, _parentClasses) {
548 550 if (info._parent->inherits(name)) {
549 551 return true;
550 552 }
551 553 }
552 554 return false;
553 555 }
554 556
555 557 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
556 558 {
557 559 if (classInfo == this) {
558 560 return true;
559 561 }
560 562 foreach(const ParentClassInfo& info, _parentClasses) {
561 563 if (info._parent->inherits(classInfo)) {
562 564 return true;
563 565 }
564 566 }
565 567 return false;
566 568 }
567 569
568 570 QString PythonQtClassInfo::help()
569 571 {
570 572 decorator();
571 573 QString h;
572 574 h += QString("--- ") + QString(className()) + QString(" ---\n");
573 575
574 576 if (_isQObject) {
575 577 h += "Properties:\n";
576 578
577 579 int i;
578 580 int numProperties = _meta->propertyCount();
579 581 for (i = 0; i < numProperties; i++) {
580 582 QMetaProperty p = _meta->property(i);
581 583 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
582 584 }
583 585 }
584 586
585 587 if (constructors()) {
586 588 h += "Constructors:\n";
587 589 PythonQtSlotInfo* constr = constructors();
588 590 while (constr) {
589 591 h += constr->fullSignature() + "\n";
590 592 constr = constr->nextInfo();
591 593 }
592 594 }
593 595
594 596 h += "Slots:\n";
595 597 h += "QString help()\n";
596 598 h += "QString className()\n";
597 599
598 600 if (_meta) {
599 601 int numMethods = _meta->methodCount();
600 602 for (int i = 0; i < numMethods; i++) {
601 603 QMetaMethod m = _meta->method(i);
602 604 if ((m.methodType() == QMetaMethod::Method ||
603 605 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
604 606 PythonQtSlotInfo slot(this, m, i);
605 607 h += slot.fullSignature()+ "\n";
606 608 }
607 609 }
608 610 }
609 611
610 612 // TODO xxx : decorators and enums from decorator() are missing...
611 613 // maybe we can reuse memberlist()?
612 614
613 615 if (_meta && _meta->enumeratorCount()) {
614 616 h += "Enums:\n";
615 617 for (int i = 0; i<_meta->enumeratorCount(); i++) {
616 618 QMetaEnum e = _meta->enumerator(i);
617 619 h += QString(e.name()) + " {";
618 620 for (int j=0; j < e.keyCount(); j++) {
619 621 if (j) { h+= ", "; }
620 622 h += e.key(j);
621 623 }
622 624 h += " }\n";
623 625 }
624 626 }
625 627
626 628 if (_isQObject && _meta) {
627 629 int numMethods = _meta->methodCount();
628 630 if (numMethods>0) {
629 631 h += "Signals:\n";
630 632 for (int i = 0; i < numMethods; i++) {
631 633 QMetaMethod m = _meta->method(i);
632 634 if (m.methodType() == QMetaMethod::Signal) {
633 635 h += QString(m.signature()) + "\n";
634 636 }
635 637 }
636 638 }
637 639 }
638 640 return h;
639 641 }
640 642
641 643 PythonQtSlotInfo* PythonQtClassInfo::constructors()
642 644 {
643 645 if (!_constructors) {
644 646 // force creation of lazy decorator, which will register the decorators
645 647 decorator();
646 648 }
647 649 return _constructors;
648 650 }
649 651
650 652 PythonQtSlotInfo* PythonQtClassInfo::destructor()
651 653 {
652 654 if (!_destructor) {
653 655 // force creation of lazy decorator, which will register the decorators
654 656 decorator();
655 657 }
656 658 return _destructor;
657 659 }
658 660
659 661 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
660 662 {
661 663 PythonQtSlotInfo* prev = constructors();
662 664 if (prev) {
663 665 info->setNextInfo(prev->nextInfo());
664 666 prev->setNextInfo(info);
665 667 } else {
666 668 _constructors = info;
667 669 }
668 670 }
669 671
670 672 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
671 673 {
672 674 _decoratorSlots.append(info);
673 675 }
674 676
675 677 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
676 678 {
677 679 if (_destructor) {
678 680 _destructor->deleteOverloadsAndThis();
679 681 }
680 682 _destructor = info;
681 683 }
682 684
683 685 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
684 686 {
685 687 _meta = meta;
686 688 clearCachedMembers();
687 689 }
688 690
689 691 QObject* PythonQtClassInfo::decorator()
690 692 {
691 693 if (!_decoratorProvider && _decoratorProviderCB) {
692 694 _decoratorProvider = (*_decoratorProviderCB)();
693 695 if (_decoratorProvider) {
694 696 _decoratorProvider->setParent(PythonQt::priv());
695 697 // setup enums early, since they might be needed by the constructor decorators:
696 698 if (!_enumsCreated) {
697 699 createEnumWrappers();
698 700 }
699 701 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
700 702 }
701 703 }
702 704 // check if enums need to be created and create them if they are not yet created
703 705 if (!_enumsCreated) {
704 706 createEnumWrappers();
705 707 }
706 708 return _decoratorProvider;
707 709 }
708 710
709 711 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
710 712 {
711 713 PythonQtMemberInfo info = member("hasOwner");
712 714 if (info._type == PythonQtMemberInfo::Slot) {
713 715 void* obj = object;
714 716 bool result = false;
715 717 void* args[2];
716 718 args[0] = &result;
717 719 args[1] = &obj;
718 720 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
719 721 return !result;
720 722 } else {
721 723 return false;
722 724 }
723 725 }
724 726
725 727 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
726 728 {
727 729 if (!_polymorphicHandlers.isEmpty()) {
728 730 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
729 731 void* resultPtr = (*cb)(ptr, resultClassName);
730 732 if (resultPtr) {
731 733 return resultPtr;
732 734 }
733 735 }
734 736 }
735 737 foreach(const ParentClassInfo& info, _parentClasses) {
736 738 if (!info._parent->isQObject()) {
737 739 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
738 740 if (resultPtr) {
739 741 return resultPtr;
740 742 }
741 743 }
742 744 }
743 745 return NULL;
744 746 }
745 747
746 748 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
747 749 {
748 750 char* className;
749 751 // this would do downcasting recursively...
750 752 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
751 753
752 754 // we only do downcasting on the base object, not on the whole inheritance tree...
753 755 void* resultPtr = NULL;
754 756 if (!_polymorphicHandlers.isEmpty()) {
755 757 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
756 758 resultPtr = (*cb)(ptr, &className);
757 759 if (resultPtr) {
758 760 break;
759 761 }
760 762 }
761 763 }
762 764 if (resultPtr) {
763 765 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
764 766 } else {
765 767 *resultClassInfo = this;
766 768 resultPtr = ptr;
767 769 }
768 770 return resultPtr;
769 771 }
770 772
771 773 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
772 774 {
773 775 if (isLocalEnum) {
774 776 *isLocalEnum = true;
775 777 }
776 778 int scopePos = name.lastIndexOf("::");
777 779 if (scopePos != -1) {
778 780 if (isLocalEnum) {
779 781 *isLocalEnum = false;
780 782 }
781 783 // split into scope and enum name
782 784 QByteArray enumScope = name.mid(0,scopePos);
783 785 QByteArray enumName = name.mid(scopePos+2);
784 786 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
785 787 if (info) {
786 788 return info->findEnumWrapper(enumName);
787 789 } else{
788 790 return NULL;
789 791 }
790 792 }
791 793 if (localScope) {
792 794 return localScope->findEnumWrapper(name);
793 795 } else {
794 796 return NULL;
795 797 }
796 798 }
797 799
798 800 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
799 801 {
800 802 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
801 803 QMetaEnum e = meta->enumerator(i);
802 804 PythonQtObjectPtr p;
803 805 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
804 806 _enumWrappers.append(p);
805 807 }
806 808 }
807 809
808 810 void PythonQtClassInfo::createEnumWrappers()
809 811 {
810 812 if (!_enumsCreated) {
811 813 _enumsCreated = true;
812 814 if (_meta) {
813 815 createEnumWrappers(_meta);
814 816 }
815 817 if (decorator()) {
816 818 createEnumWrappers(decorator()->metaObject());
817 819 }
818 820 foreach(const ParentClassInfo& info, _parentClasses) {
819 821 info._parent->createEnumWrappers();
820 822 }
821 823 }
822 824 }
823 825
824 826 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
825 827 // force enum creation
826 828 if (!_enumsCreated) {
827 829 createEnumWrappers();
828 830 }
829 831 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
830 832 const char* className = ((PyTypeObject*)p.object())->tp_name;
831 833 if (qstrcmp(className, name)==0) {
832 834 return p.object();
833 835 }
834 836 }
835 837 foreach(const ParentClassInfo& info, _parentClasses) {
836 838 PyObject* p = info._parent->findEnumWrapper(name);
837 839 if (p) return p;
838 840 }
839 841 return NULL;
840 842 }
841 843
General Comments 0
You need to be logged in to leave comments. Login now