##// END OF EJS Templates
added support for operators and rich compare...
florianlink -
r119:609e1e5898f0
parent child
Show More
@@ -1,2634 +1,2634
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #include "abstractmetabuilder.h"
43 43 #include "reporthandler.h"
44 44
45 45 #include "ast.h"
46 46 #include "binder.h"
47 47 #include "control.h"
48 48 #include "default_visitor.h"
49 49 #include "dumptree.h"
50 50 #include "lexer.h"
51 51 #include "parser.h"
52 52 #include "tokens.h"
53 53
54 54 #include <QtCore/QDebug>
55 55 #include <QtCore/QFile>
56 56 #include <QtCore/QFileInfo>
57 57 #include <QtCore/QTextCodec>
58 58 #include <QtCore/QTextStream>
59 59 #include <QtCore/QVariant>
60 60
61 61 static QString strip_template_args(const QString &name)
62 62 {
63 63 int pos = name.indexOf('<');
64 64 return pos < 0 ? name : name.left(pos);
65 65 }
66 66
67 67 static QHash<QString, QString> *operator_names;
68 68 QString rename_operator(const QString &oper)
69 69 {
70 70 QString op = oper.trimmed();
71 71 if (!operator_names) {
72 72 operator_names = new QHash<QString, QString>;
73 73
74 74 operator_names->insert("+", "__add__");
75 75 operator_names->insert("-", "__sub__");
76 76 operator_names->insert("*", "__mul__");
77 77 operator_names->insert("/", "__div__");
78 78 operator_names->insert("%", "__mod__");
79 79 operator_names->insert("&", "__and__");
80 80 operator_names->insert("|", "__or__");
81 81 operator_names->insert("^", "__xor__");
82 operator_names->insert("~", "__negate__");
82 operator_names->insert("~", "__invert__");
83 83 operator_names->insert("<<", "__lshift__");
84 84 operator_names->insert(">>", "__rshift__");
85 85
86 86 // assigments
87 87 operator_names->insert("=", "assign");
88 88 operator_names->insert("+=", "__iadd__");
89 89 operator_names->insert("-=", "__isub__");
90 90 operator_names->insert("*=", "__imul__");
91 91 operator_names->insert("/=", "__idiv__");
92 92 operator_names->insert("%=", "__imod__");
93 93 operator_names->insert("&=", "__iand__");
94 94 operator_names->insert("|=", "__ior__");
95 95 operator_names->insert("^=", "__ixor__");
96 96 operator_names->insert("<<=", "__ilshift__");
97 97 operator_names->insert(">>=", "__irshift__");
98 98
99 99 // Logical
100 100 operator_names->insert("&&", "logical_and");
101 101 operator_names->insert("||", "logical_or");
102 102 operator_names->insert("!", "not");
103 103
104 104 // incr/decr
105 105 operator_names->insert("++", "increment");
106 106 operator_names->insert("--", "decrement");
107 107
108 108 // compare
109 operator_names->insert("<", "less");
110 operator_names->insert(">", "greater");
111 operator_names->insert("<=", "less_or_equal");
112 operator_names->insert(">=", "greater_or_equal");
113 operator_names->insert("!=", "not_equal");
114 operator_names->insert("==", "equal");
109 operator_names->insert("<", "__lt__");
110 operator_names->insert(">", "__gt__");
111 operator_names->insert("<=", "__le__");
112 operator_names->insert(">=", "__ge__");
113 operator_names->insert("!=", "__ne__");
114 operator_names->insert("==", "__eq__");
115 115
116 116 // other
117 117 operator_names->insert("[]", "subscript");
118 118 operator_names->insert("->", "pointer");
119 119 }
120 120
121 121 if (!operator_names->contains(op)) {
122 122 TypeDatabase *tb = TypeDatabase::instance();
123 123
124 124 TypeParser::Info typeInfo = TypeParser::parse(op);
125 125 QString cast_to_name = typeInfo.qualified_name.join("::");
126 126 TypeEntry *te = tb->findType(cast_to_name);
127 127 if ((te && te->codeGeneration() == TypeEntry::GenerateNothing)
128 128 || tb->isClassRejected(cast_to_name)) {
129 129 return QString();
130 130 } else if (te) {
131 131 return "operator_cast_" + typeInfo.qualified_name.join("_");
132 132 } else {
133 133 ReportHandler::warning(QString("unknown operator '%1'").arg(op));
134 134 return "operator " + op;
135 135 }
136 136 }
137 137
138 138 QString r = operator_names->value(op);
139 139 if (r.startsWith("__")) {
140 140 return r;
141 141 } else {
142 142 return "operator_" + r;
143 143 }
144 144 }
145 145
146 146 AbstractMetaBuilder::AbstractMetaBuilder()
147 147 : m_current_class(0)
148 148 {
149 149 }
150 150
151 151 void AbstractMetaBuilder::checkFunctionModifications()
152 152 {
153 153 TypeDatabase *types = TypeDatabase::instance();
154 154 SingleTypeEntryHash entryHash = types->entries();
155 155 QList<TypeEntry *> entries = entryHash.values();
156 156 foreach (TypeEntry *entry, entries) {
157 157 if (entry == 0)
158 158 continue;
159 159 if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing)
160 160 continue;
161 161
162 162 ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(entry);
163 163 FunctionModificationList modifications = centry->functionModifications();
164 164
165 165 foreach (FunctionModification modification, modifications) {
166 166 QString signature = modification.signature;
167 167
168 168 QString name = signature.trimmed();
169 169 name = name.mid(0, signature.indexOf("("));
170 170
171 171 AbstractMetaClass *clazz = m_meta_classes.findClass(centry->qualifiedCppName());
172 172 if (clazz == 0)
173 173 continue;
174 174
175 175 AbstractMetaFunctionList functions = clazz->functions();
176 176 bool found = false;
177 177 QStringList possibleSignatures;
178 178 foreach (AbstractMetaFunction *function, functions) {
179 179 if (function->minimalSignature() == signature && function->implementingClass() == clazz) {
180 180 found = true;
181 181 break;
182 182 }
183 183
184 184 if (function->originalName() == name)
185 185 possibleSignatures.append(function->minimalSignature() + " in " + function->implementingClass()->name());
186 186 }
187 187
188 188 if (!found) {
189 189 QString warning
190 190 = QString("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
191 191 .arg(signature)
192 192 .arg(clazz->qualifiedCppName())
193 193 .arg(possibleSignatures.join(", "));
194 194
195 195 ReportHandler::warning(warning);
196 196 }
197 197 }
198 198 }
199 199 }
200 200
201 201 AbstractMetaClass *AbstractMetaBuilder::argumentToClass(ArgumentModelItem argument)
202 202 {
203 203 AbstractMetaClass *returned = 0;
204 204 bool ok = false;
205 205 AbstractMetaType *type = translateType(argument->type(), &ok);
206 206 if (ok && type != 0 && type->typeEntry() != 0 && type->typeEntry()->isComplex()) {
207 207 const TypeEntry *entry = type->typeEntry();
208 208 returned = m_meta_classes.findClass(entry->name());
209 209 }
210 210 delete type;
211 211 return returned;
212 212 }
213 213
214 214 /**
215 215 * Checks the argument of a hash function and flags the type if it is a complex type
216 216 */
217 217 void AbstractMetaBuilder::registerHashFunction(FunctionModelItem function_item)
218 218 {
219 219 ArgumentList arguments = function_item->arguments();
220 220 if (arguments.size() == 1) {
221 221 if (AbstractMetaClass *cls = argumentToClass(arguments.at(0)))
222 222 cls->setHasHashFunction(true);
223 223 }
224 224 }
225 225
226 226 /**
227 227 * Check if a class has a debug stream operator that can be used as toString
228 228 */
229 229
230 230 void AbstractMetaBuilder::registerToStringCapability(FunctionModelItem function_item)
231 231 {
232 232 ArgumentList arguments = function_item->arguments();
233 233 if (arguments.size() == 2) {
234 234 if (arguments.at(0)->type().toString() == "QDebug"){
235 235 ArgumentModelItem arg = arguments.at(1);
236 236 if (AbstractMetaClass *cls = argumentToClass(arg)) {
237 237 if (arg->type().indirections() < 2 && cls->name()!="QObject") {
238 238 cls->setToStringCapability(function_item);
239 239 }
240 240 }
241 241 }
242 242 }
243 243 }
244 244
245 245 void AbstractMetaBuilder::traverseCompareOperator(FunctionModelItem item) {
246 246 ArgumentList arguments = item->arguments();
247 247 if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
248 248 AbstractMetaClass *comparer_class = argumentToClass(arguments.at(0));
249 249 AbstractMetaClass *compared_class = argumentToClass(arguments.at(1));
250 250 if (comparer_class != 0 && compared_class != 0) {
251 251 AbstractMetaClass *old_current_class = m_current_class;
252 252 m_current_class = comparer_class;
253 253
254 254 AbstractMetaFunction *meta_function = traverseFunction(item);
255 255 if (meta_function != 0 && !meta_function->isInvalid()) {
256 256 // Strip away first argument, since that is the containing object
257 257 AbstractMetaArgumentList arguments = meta_function->arguments();
258 258 arguments.pop_front();
259 259 meta_function->setArguments(arguments);
260 260
261 261 meta_function->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
262 262
263 263 meta_function->setOriginalAttributes(meta_function->attributes());
264 264 setupFunctionDefaults(meta_function, comparer_class);
265 265
266 266 comparer_class->addFunction(meta_function);
267 267 } else if (meta_function != 0) {
268 268 delete meta_function;
269 269 }
270 270
271 271 m_current_class = old_current_class;
272 272 }
273 273 }
274 274 }
275 275
276 276 void AbstractMetaBuilder::traverseStreamOperator(FunctionModelItem item)
277 277 {
278 278 ArgumentList arguments = item->arguments();
279 279 if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
280 280 AbstractMetaClass *streamClass = argumentToClass(arguments.at(0));
281 281 AbstractMetaClass *streamedClass = argumentToClass(arguments.at(1));
282 282
283 283 if (streamClass != 0 && streamedClass != 0
284 284 && (streamClass->name() == "QDataStream" || streamClass->name() == "QTextStream")) {
285 285 AbstractMetaClass *old_current_class = m_current_class;
286 286 m_current_class = streamedClass;
287 287 AbstractMetaFunction *streamFunction = traverseFunction(item);
288 288
289 289 if (streamFunction != 0 && !streamFunction->isInvalid()) {
290 290 QString name = item->name();
291 291 streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
292 292
293 293 if (name.endsWith("<<"))
294 294 streamFunction->setName("writeTo");
295 295 else
296 296 streamFunction->setName("readFrom");
297 297
298 298 // Strip away last argument, since that is the containing object
299 299 AbstractMetaArgumentList arguments = streamFunction->arguments();
300 300 arguments.pop_back();
301 301 streamFunction->setArguments(arguments);
302 302
303 303 *streamFunction += AbstractMetaAttributes::Final;
304 304 *streamFunction += AbstractMetaAttributes::Public;
305 305 streamFunction->setOriginalAttributes(streamFunction->attributes());
306 306
307 307 streamFunction->setType(0);
308 308
309 309 setupFunctionDefaults(streamFunction, streamedClass);
310 310
311 311 streamedClass->addFunction(streamFunction);
312 312 streamedClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
313 313
314 314 m_current_class = old_current_class;
315 315 }
316 316 }
317 317 }
318 318 }
319 319
320 320 void AbstractMetaBuilder::traverseBinaryArithmeticOperator(FunctionModelItem item)
321 321 {
322 322 ArgumentList arguments = item->arguments();
323 323 if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
324 324 AbstractMetaClass *aClass = argumentToClass(arguments.at(0));
325 325 AbstractMetaClass *bClass = argumentToClass(arguments.at(1));
326 326
327 327 if (!aClass) return;
328 328
329 329 AbstractMetaClass *old_current_class = m_current_class;
330 330 m_current_class = aClass;
331 331 AbstractMetaFunction *streamFunction = traverseFunction(item);
332 332 if (streamFunction != 0 && !streamFunction->isInvalid()) {
333 333 QString name = rename_operator(item->name().mid(8));
334 334 if (name.isEmpty()) return;
335 335
336 336 streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
337 337 streamFunction->setName(name);
338 338
339 339 // Strip away the first argument, since that is the operator object
340 340 AbstractMetaArgumentList arguments = streamFunction->arguments();
341 341 arguments.removeFirst();
342 342 streamFunction->setArguments(arguments);
343 343
344 344 *streamFunction += AbstractMetaAttributes::Final;
345 345 *streamFunction += AbstractMetaAttributes::Public;
346 346 streamFunction->setOriginalAttributes(streamFunction->attributes());
347 347
348 348 setupFunctionDefaults(streamFunction, aClass);
349 349
350 350 aClass->addFunction(streamFunction);
351 351 if (bClass) {
352 352 aClass->typeEntry()->addExtraInclude(bClass->typeEntry()->include());
353 353 }
354 354
355 355 m_current_class = old_current_class;
356 356 }
357 357 }
358 358 }
359 359
360 360 void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase *types,
361 361 NamespaceModelItem scope)
362 362 {
363 363 foreach (ClassModelItem item, scope->classes()) {
364 364 QString qualified_name = item->qualifiedName().join("::");
365 365 TypeEntry *entry = types->findType(qualified_name);
366 366 if (entry) {
367 367 if (isQObject(qualified_name) && entry->isComplex()) {
368 368 ((ComplexTypeEntry *) entry)->setQObject(true);
369 369 }
370 370 }
371 371 }
372 372
373 373 foreach (NamespaceModelItem item, scope->namespaceMap().values()) {
374 374 if (scope != item)
375 375 fixQObjectForScope(types, item);
376 376 }
377 377 }
378 378
379 379 static bool class_less_than(AbstractMetaClass *a, AbstractMetaClass *b)
380 380 {
381 381 return a->name() < b->name();
382 382 }
383 383
384 384
385 385 void AbstractMetaBuilder::sortLists()
386 386 {
387 387 qSort(m_meta_classes.begin(), m_meta_classes.end(), class_less_than);
388 388 foreach (AbstractMetaClass *cls, m_meta_classes) {
389 389 cls->sortFunctions();
390 390 }
391 391 }
392 392
393 393 bool AbstractMetaBuilder::build()
394 394 {
395 395 Q_ASSERT(!m_file_name.isEmpty());
396 396
397 397 QFile file(m_file_name);
398 398
399 399 if (!file.open(QFile::ReadOnly))
400 400 return false;
401 401
402 402 QTextStream stream(&file);
403 403 stream.setCodec(QTextCodec::codecForName("UTF-8"));
404 404 QByteArray contents = stream.readAll().toUtf8();
405 405 file.close();
406 406
407 407 Control control;
408 408 Parser p(&control);
409 409 pool __pool;
410 410
411 411 TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
412 412
413 413 CodeModel model;
414 414 Binder binder(&model, p.location());
415 415 m_dom = binder.run(ast);
416 416
417 417 pushScope(model_dynamic_cast<ScopeModelItem>(m_dom));
418 418
419 419 QHash<QString, ClassModelItem> typeMap = m_dom->classMap();
420 420
421 421
422 422 // fix up QObject's in the type system..
423 423 TypeDatabase *types = TypeDatabase::instance();
424 424 fixQObjectForScope(types, model_dynamic_cast<NamespaceModelItem>(m_dom));
425 425
426 426
427 427 // Start the generation...
428 428 foreach (ClassModelItem item, typeMap.values()) {
429 429 AbstractMetaClass *cls = traverseClass(item);
430 430 addAbstractMetaClass(cls);
431 431 }
432 432
433 433
434 434 QHash<QString, NamespaceModelItem> namespaceMap = m_dom->namespaceMap();
435 435 foreach (NamespaceModelItem item, namespaceMap.values()) {
436 436 AbstractMetaClass *meta_class = traverseNamespace(item);
437 437 if (meta_class)
438 438 m_meta_classes << meta_class;
439 439 }
440 440
441 441
442 442 // Some trickery to support global-namespace enums...
443 443 QHash<QString, EnumModelItem> enumMap = m_dom->enumMap();
444 444 m_current_class = 0;
445 445 foreach (EnumModelItem item, enumMap) {
446 446 AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet<QString>());
447 447
448 448 if (meta_enum) {
449 449 QString package = meta_enum->typeEntry()->javaPackage();
450 450 QString globalName = TypeDatabase::globalNamespaceClassName(meta_enum->typeEntry());
451 451
452 452 AbstractMetaClass *global = m_meta_classes.findClass(package + "." + globalName);
453 453 if (!global) {
454 454 ComplexTypeEntry *gte = new ObjectTypeEntry(globalName);
455 455 gte->setTargetLangPackage(meta_enum->typeEntry()->javaPackage());
456 456 gte->setCodeGeneration(meta_enum->typeEntry()->codeGeneration());
457 457 global = createMetaClass();
458 458 global->setTypeEntry(gte);
459 459 *global += AbstractMetaAttributes::Final;
460 460 *global += AbstractMetaAttributes::Public;
461 461 *global += AbstractMetaAttributes::Fake;
462 462
463 463 m_meta_classes << global;
464 464 }
465 465
466 466 global->addEnum(meta_enum);
467 467 meta_enum->setEnclosingClass(global);
468 468 meta_enum->typeEntry()->setQualifier(globalName);
469 469
470 470 // Global enums should be public despite not having public
471 471 // identifiers so we'll fix the original attributes here.
472 472 meta_enum->setOriginalAttributes(meta_enum->attributes());
473 473 }
474 474
475 475
476 476 }
477 477
478 478
479 479 // Go through all typedefs to see if we have defined any
480 480 // specific typedefs to be used as classes.
481 481 TypeAliasList typeAliases = m_dom->typeAliases();
482 482 foreach (TypeAliasModelItem typeAlias, typeAliases) {
483 483 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
484 484 addAbstractMetaClass(cls);
485 485 }
486 486
487 487
488 488
489 489
490 490 foreach (AbstractMetaClass *cls, m_meta_classes) {
491 491 if (!cls->isInterface() && !cls->isNamespace()) {
492 492 setupInheritance(cls);
493 493 }
494 494 }
495 495
496 496
497 497 foreach (AbstractMetaClass *cls, m_meta_classes) {
498 498 cls->fixFunctions();
499 499
500 500 if (cls->typeEntry() == 0) {
501 501 ReportHandler::warning(QString("class '%1' does not have an entry in the type system")
502 502 .arg(cls->name()));
503 503 } else {
504 504 if (!cls->hasConstructors() && !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace())
505 505 cls->addDefaultConstructor();
506 506 }
507 507
508 508 if (cls->isAbstract() && !cls->isInterface()) {
509 509 cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + "$ConcreteWrapper");
510 510 }
511 511 }
512 512
513 513 QList<TypeEntry *> entries = TypeDatabase::instance()->entries().values();
514 514 foreach (const TypeEntry *entry, entries) {
515 515 if (entry->isPrimitive())
516 516 continue;
517 517
518 518 if ((entry->isValue() || entry->isObject())
519 519 && !entry->isString()
520 520 && !entry->isChar()
521 521 && !entry->isContainer()
522 522 && !entry->isCustom()
523 523 && !entry->isVariant()
524 524 && !m_meta_classes.findClass(entry->qualifiedCppName())) {
525 525 ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
526 526 .arg(entry->qualifiedCppName()));
527 527 }
528 528
529 529 if (entry->isEnum()) {
530 530 QString pkg = entry->javaPackage();
531 531 QString name = (pkg.isEmpty() ? QString() : pkg + ".")
532 532 + ((EnumTypeEntry *) entry)->javaQualifier();
533 533 AbstractMetaClass *cls = m_meta_classes.findClass(name);
534 534
535 535 if (!cls) {
536 536 ReportHandler::warning(QString("namespace '%1' for enum '%2' is not declared")
537 537 .arg(name).arg(entry->targetLangName()));
538 538 } else {
539 539 AbstractMetaEnum *e = cls->findEnum(entry->targetLangName());
540 540 if (!e)
541 541 ReportHandler::warning(QString("enum '%1' is specified in typesystem, "
542 542 "but not declared")
543 543 .arg(entry->qualifiedCppName()));
544 544 }
545 545 }
546 546 }
547 547
548 548 {
549 549 FunctionList hash_functions = m_dom->findFunctions("qHash");
550 550 foreach (FunctionModelItem item, hash_functions) {
551 551 registerHashFunction(item);
552 552 }
553 553 }
554 554
555 555 {
556 556 FunctionList hash_functions = m_dom->findFunctions("operator<<");
557 557 foreach (FunctionModelItem item, hash_functions) {
558 558 registerToStringCapability(item);
559 559 }
560 560 }
561 561
562 562 {
563 563 FunctionList compare_operators = m_dom->findFunctions("operator==")
564 564 + m_dom->findFunctions("operator<=")
565 565 + m_dom->findFunctions("operator>=")
566 566 + m_dom->findFunctions("operator<")
567 567 + m_dom->findFunctions("operator>");
568 568 foreach (FunctionModelItem item, compare_operators) {
569 569 traverseCompareOperator(item);
570 570 }
571 571 }
572 572
573 573 {
574 574 FunctionList stream_operators =
575 575 m_dom->findFunctions("operator+") + m_dom->findFunctions("operator-")
576 576 + m_dom->findFunctions("operator/") + m_dom->findFunctions("operator*")
577 577 + m_dom->findFunctions("operator&") + m_dom->findFunctions("operator|")
578 578 + m_dom->findFunctions("operator%") + m_dom->findFunctions("operator^");
579 579 foreach (FunctionModelItem item, stream_operators) {
580 580 traverseBinaryArithmeticOperator(item);
581 581 }
582 582 }
583 583 {
584 584 FunctionList stream_operators = m_dom->findFunctions("operator<<") + m_dom->findFunctions("operator>>");
585 585 foreach (FunctionModelItem item, stream_operators) {
586 586 traverseStreamOperator(item);
587 587 }
588 588 }
589 589
590 590 figureOutEnumValues();
591 591 figureOutDefaultEnumArguments();
592 592 checkFunctionModifications();
593 593
594 594 foreach (AbstractMetaClass *cls, m_meta_classes) {
595 595 setupEquals(cls);
596 596 setupComparable(cls);
597 597 setupClonable(cls);
598 598 }
599 599
600 600 dumpLog();
601 601
602 602 sortLists();
603 603
604 604 return true;
605 605 }
606 606
607 607
608 608 void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls)
609 609 {
610 610 if (!cls)
611 611 return;
612 612
613 613 cls->setOriginalAttributes(cls->attributes());
614 614 if (cls->typeEntry()->isContainer()) {
615 615 m_templates << cls;
616 616 } else {
617 617 m_meta_classes << cls;
618 618 if (cls->typeEntry()->designatedInterface()) {
619 619 AbstractMetaClass *interface = cls->extractInterface();
620 620 m_meta_classes << interface;
621 621 ReportHandler::debugSparse(QString(" -> interface '%1'").arg(interface->name()));
622 622 }
623 623 }
624 624 }
625 625
626 626
627 627 AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem namespace_item)
628 628 {
629 629 QString namespace_name = (!m_namespace_prefix.isEmpty() ? m_namespace_prefix + "::" : QString()) + namespace_item->name();
630 630 NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespace_name);
631 631
632 632 if (TypeDatabase::instance()->isClassRejected(namespace_name)) {
633 633 m_rejected_classes.insert(namespace_name, GenerationDisabled);
634 634 return 0;
635 635 }
636 636
637 637 if (!type) {
638 638 ReportHandler::warning(QString("namespace '%1' does not have a type entry")
639 639 .arg(namespace_name));
640 640 return 0;
641 641 }
642 642
643 643 AbstractMetaClass *meta_class = createMetaClass();
644 644 meta_class->setTypeEntry(type);
645 645
646 646 *meta_class += AbstractMetaAttributes::Public;
647 647
648 648 m_current_class = meta_class;
649 649
650 650 ReportHandler::debugSparse(QString("namespace '%1.%2'")
651 651 .arg(meta_class->package())
652 652 .arg(namespace_item->name()));
653 653
654 654 traverseEnums(model_dynamic_cast<ScopeModelItem>(namespace_item), meta_class, namespace_item->enumsDeclarations());
655 655 traverseFunctions(model_dynamic_cast<ScopeModelItem>(namespace_item), meta_class);
656 656 // traverseClasses(model_dynamic_cast<ScopeModelItem>(namespace_item));
657 657
658 658 pushScope(model_dynamic_cast<ScopeModelItem>(namespace_item));
659 659 m_namespace_prefix = currentScope()->qualifiedName().join("::");
660 660
661 661
662 662 ClassList classes = namespace_item->classes();
663 663 foreach (ClassModelItem cls, classes) {
664 664 AbstractMetaClass *mjc = traverseClass(cls);
665 665 addAbstractMetaClass(mjc);
666 666 }
667 667
668 668 // Go through all typedefs to see if we have defined any
669 669 // specific typedefs to be used as classes.
670 670 TypeAliasList typeAliases = namespace_item->typeAliases();
671 671 foreach (TypeAliasModelItem typeAlias, typeAliases) {
672 672 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
673 673 addAbstractMetaClass(cls);
674 674 }
675 675
676 676
677 677
678 678 // Traverse namespaces recursively
679 679 QList<NamespaceModelItem> inner_namespaces = namespace_item->namespaceMap().values();
680 680 foreach (const NamespaceModelItem &ni, inner_namespaces) {
681 681 AbstractMetaClass *mjc = traverseNamespace(ni);
682 682 addAbstractMetaClass(mjc);
683 683 }
684 684
685 685 m_current_class = 0;
686 686
687 687
688 688 popScope();
689 689 m_namespace_prefix = currentScope()->qualifiedName().join("::");
690 690
691 691 if (!type->include().isValid()) {
692 692 QFileInfo info(namespace_item->fileName());
693 693 type->setInclude(Include(Include::IncludePath, info.fileName()));
694 694 }
695 695
696 696 return meta_class;
697 697 }
698 698
699 699 struct Operator
700 700 {
701 701 enum Type { Plus, ShiftLeft, None };
702 702
703 703 Operator() : type(None) { }
704 704
705 705 int calculate(int x) {
706 706 switch (type) {
707 707 case Plus: return x + value;
708 708 case ShiftLeft: return x << value;
709 709 case None: return x;
710 710 }
711 711 return x;
712 712 }
713 713
714 714 Type type;
715 715 int value;
716 716 };
717 717
718 718
719 719
720 720 Operator findOperator(QString *s) {
721 721 const char *names[] = {
722 722 "+",
723 723 "<<"
724 724 };
725 725
726 726 for (int i=0; i<Operator::None; ++i) {
727 727 QString name = QLatin1String(names[i]);
728 728 QString str = *s;
729 729 int splitPoint = str.indexOf(name);
730 730 if (splitPoint > 0) {
731 731 bool ok;
732 732 QString right = str.mid(splitPoint + name.length());
733 733 Operator op;
734 734 op.value = right.toInt(&ok);
735 735 if (ok) {
736 736 op.type = Operator::Type(i);
737 737 *s = str.left(splitPoint).trimmed();
738 738 return op;
739 739 }
740 740 }
741 741 }
742 742 return Operator();
743 743 }
744 744
745 745 int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue,
746 746 int oldValuevalue,
747 747 AbstractMetaEnum *meta_enum,
748 748 AbstractMetaFunction *meta_function)
749 749 {
750 750 if (stringValue.isEmpty())
751 751 return oldValuevalue;
752 752
753 753 QStringList stringValues = stringValue.split("|");
754 754
755 755 int returnValue = 0;
756 756
757 757 bool matched = false;
758 758
759 759 for (int i=0; i<stringValues.size(); ++i) {
760 760 QString s = stringValues.at(i).trimmed();
761 761
762 762 bool ok;
763 763 int v;
764 764
765 765 Operator op = findOperator(&s);
766 766
767 767 if (s.length() > 0 && s.at(0) == QLatin1Char('0'))
768 768 v = s.toUInt(&ok, 0);
769 769 else
770 770 v = s.toInt(&ok);
771 771
772 772 if (ok) {
773 773 matched = true;
774 774
775 775 } else if (m_enum_values.contains(s)) {
776 776 v = m_enum_values[s]->value();
777 777 matched = true;
778 778
779 779 } else {
780 780 AbstractMetaEnumValue *ev = 0;
781 781
782 782 if (meta_enum && (ev = meta_enum->values().find(s))) {
783 783 v = ev->value();
784 784 matched = true;
785 785
786 786 } else if (meta_enum && (ev = meta_enum->enclosingClass()->findEnumValue(s, meta_enum))) {
787 787 v = ev->value();
788 788 matched = true;
789 789
790 790 } else {
791 791 if (meta_enum)
792 792 ReportHandler::warning("unhandled enum value: " + s + " in "
793 793 + meta_enum->enclosingClass()->name() + "::"
794 794 + meta_enum->name());
795 795 else
796 796 ReportHandler::warning("unhandled enum value: Unknown enum");
797 797 }
798 798 }
799 799
800 800 if (matched)
801 801 returnValue |= op.calculate(v);
802 802 }
803 803
804 804 if (!matched) {
805 805 QString warn = QString("unmatched enum %1").arg(stringValue);
806 806
807 807 if (meta_function != 0) {
808 808 warn += QString(" when parsing default value of '%1' in class '%2'")
809 809 .arg(meta_function->name())
810 810 .arg(meta_function->implementingClass()->name());
811 811 }
812 812
813 813 ReportHandler::warning(warn);
814 814 returnValue = oldValuevalue;
815 815 }
816 816
817 817 return returnValue;
818 818 }
819 819
820 820 void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass *meta_class,
821 821 QSet<AbstractMetaClass *> *classes)
822 822 {
823 823 AbstractMetaClass *base = meta_class->baseClass();
824 824
825 825 if (base != 0 && !classes->contains(base))
826 826 figureOutEnumValuesForClass(base, classes);
827 827
828 828 if (classes->contains(meta_class))
829 829 return;
830 830
831 831 AbstractMetaEnumList enums = meta_class->enums();
832 832 foreach (AbstractMetaEnum *e, enums) {
833 833 if (!e) {
834 834 ReportHandler::warning("bad enum in class " + meta_class->name());
835 835 continue;
836 836 }
837 837 AbstractMetaEnumValueList lst = e->values();
838 838 int value = 0;
839 839 for (int i=0; i<lst.size(); ++i) {
840 840 value = figureOutEnumValue(lst.at(i)->stringValue(), value, e);
841 841 lst.at(i)->setValue(value);
842 842 value++;
843 843 }
844 844
845 845 // Check for duplicate values...
846 846 EnumTypeEntry *ete = e->typeEntry();
847 847 if (!ete->forceInteger()) {
848 848 QHash<int, AbstractMetaEnumValue *> entries;
849 849 foreach (AbstractMetaEnumValue *v, lst) {
850 850
851 851 bool vRejected = ete->isEnumValueRejected(v->name());
852 852
853 853 AbstractMetaEnumValue *current = entries.value(v->value());
854 854 if (current) {
855 855 bool currentRejected = ete->isEnumValueRejected(current->name());
856 856 if (!currentRejected && !vRejected) {
857 857 ReportHandler::warning(
858 858 QString("duplicate enum values: %1::%2, %3 and %4 are %5, already rejected: (%6)")
859 859 .arg(meta_class->name())
860 860 .arg(e->name())
861 861 .arg(v->name())
862 862 .arg(entries[v->value()]->name())
863 863 .arg(v->value())
864 864 .arg(ete->enumValueRejections().join(", ")));
865 865 continue;
866 866 }
867 867 }
868 868
869 869 if (!vRejected)
870 870 entries[v->value()] = v;
871 871 }
872 872
873 873 // Entries now contain all the original entries, no
874 874 // rejected ones... Use this to generate the enumValueRedirection table.
875 875 foreach (AbstractMetaEnumValue *reject, lst) {
876 876 if (!ete->isEnumValueRejected(reject->name()))
877 877 continue;
878 878
879 879 AbstractMetaEnumValue *used = entries.value(reject->value());
880 880 if (!used) {
881 881 ReportHandler::warning(
882 882 QString::fromLatin1("Rejected enum has no alternative...: %1::%2")
883 883 .arg(meta_class->name())
884 884 .arg(reject->name()));
885 885 continue;
886 886 }
887 887 ete->addEnumValueRedirection(reject->name(), used->name());
888 888 }
889 889
890 890 }
891 891 }
892 892
893 893
894 894
895 895 *classes += meta_class;
896 896 }
897 897
898 898
899 899 void AbstractMetaBuilder::figureOutEnumValues()
900 900 {
901 901 // Keep a set of classes that we already traversed. We use this to
902 902 // enforce that we traverse base classes prior to subclasses.
903 903 QSet<AbstractMetaClass *> classes;
904 904 foreach (AbstractMetaClass *c, m_meta_classes) {
905 905 figureOutEnumValuesForClass(c, &classes);
906 906 }
907 907 }
908 908
909 909 void AbstractMetaBuilder::figureOutDefaultEnumArguments()
910 910 {
911 911 foreach (AbstractMetaClass *meta_class, m_meta_classes) {
912 912 foreach (AbstractMetaFunction *meta_function, meta_class->functions()) {
913 913 foreach (AbstractMetaArgument *arg, meta_function->arguments()) {
914 914
915 915 QString expr = arg->defaultValueExpression();
916 916 if (expr.isEmpty())
917 917 continue;
918 918
919 919 if (!meta_function->replacedDefaultExpression(meta_function->implementingClass(),
920 920 arg->argumentIndex()+1).isEmpty()) {
921 921 continue;
922 922 }
923 923
924 924 QString new_expr = expr;
925 925 if (arg->type()->isEnum()) {
926 926 QStringList lst = expr.split(QLatin1String("::"));
927 927 if (lst.size() == 1) {
928 928 QVector<AbstractMetaClass *> classes(1, meta_class);
929 929 AbstractMetaEnum *e = 0;
930 930 while (!classes.isEmpty() && e == 0) {
931 931 if (classes.front() != 0) {
932 932 classes << classes.front()->baseClass();
933 933
934 934 AbstractMetaClassList interfaces = classes.front()->interfaces();
935 935 foreach (AbstractMetaClass *interface, interfaces)
936 936 classes << interface->primaryInterfaceImplementor();
937 937
938 938 e = classes.front()->findEnumForValue(expr);
939 939 }
940 940
941 941 classes.pop_front();
942 942 }
943 943
944 944 if (e != 0) {
945 945 new_expr = QString("%1.%2")
946 946 .arg(e->typeEntry()->qualifiedTargetLangName())
947 947 .arg(expr);
948 948 } else {
949 949 ReportHandler::warning("Cannot find enum constant for value '" + expr + "' in '" + meta_class->name() + "' or any of its super classes");
950 950 }
951 951 } else if (lst.size() == 2) {
952 952 AbstractMetaClass *cl = m_meta_classes.findClass(lst.at(0));
953 953 if (!cl) {
954 954 ReportHandler::warning("missing required class for enums: " + lst.at(0));
955 955 continue;
956 956 }
957 957 new_expr = QString("%1.%2.%3")
958 958 .arg(cl->typeEntry()->qualifiedTargetLangName())
959 959 .arg(arg->type()->name())
960 960 .arg(lst.at(1));
961 961 } else {
962 962 ReportHandler::warning("bad default value passed to enum " + expr);
963 963 }
964 964
965 965 } else if(arg->type()->isFlags()) {
966 966 const FlagsTypeEntry *flagsEntry =
967 967 static_cast<const FlagsTypeEntry *>(arg->type()->typeEntry());
968 968 EnumTypeEntry *enumEntry = flagsEntry->originator();
969 969 AbstractMetaEnum *meta_enum = m_meta_classes.findEnum(enumEntry);
970 970 if (!meta_enum) {
971 971 ReportHandler::warning("unknown required enum " + enumEntry->qualifiedCppName());
972 972 continue;
973 973 }
974 974
975 975 int value = figureOutEnumValue(expr, 0, meta_enum, meta_function);
976 976 new_expr = QString::number(value);
977 977
978 978 } else if (arg->type()->isPrimitive()) {
979 979 AbstractMetaEnumValue *value = 0;
980 980 if (expr.contains("::"))
981 981 value = m_meta_classes.findEnumValue(expr);
982 982 if (!value)
983 983 value = meta_class->findEnumValue(expr, 0);
984 984
985 985 if (value) {
986 986 new_expr = QString::number(value->value());
987 987 } else if (expr.contains(QLatin1Char('+'))) {
988 988 new_expr = QString::number(figureOutEnumValue(expr, 0, 0));
989 989
990 990 }
991 991
992 992
993 993
994 994 }
995 995
996 996 arg->setDefaultValueExpression(new_expr);
997 997 }
998 998 }
999 999 }
1000 1000 }
1001 1001
1002 1002
1003 1003 AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item, AbstractMetaClass *enclosing, const QSet<QString> &enumsDeclarations)
1004 1004 {
1005 1005 // Skipping private enums.
1006 1006 if (enum_item->accessPolicy() == CodeModel::Private) {
1007 1007 return 0;
1008 1008 }
1009 1009
1010 1010 QString qualified_name = enum_item->qualifiedName().join("::");
1011 1011
1012 1012 TypeEntry *type_entry = TypeDatabase::instance()->findType(qualified_name);
1013 1013 QString enum_name = enum_item->name();
1014 1014
1015 1015 QString class_name;
1016 1016 if (m_current_class)
1017 1017 class_name = m_current_class->typeEntry()->qualifiedCppName();
1018 1018
1019 1019 if (TypeDatabase::instance()->isEnumRejected(class_name, enum_name)) {
1020 1020 m_rejected_enums.insert(qualified_name, GenerationDisabled);
1021 1021 return 0;
1022 1022 }
1023 1023
1024 1024 if (!type_entry || !type_entry->isEnum()) {
1025 1025 QString context = m_current_class ? m_current_class->name() : QLatin1String("");
1026 1026 ReportHandler::warning(QString("enum '%1' does not have a type entry or is not an enum")
1027 1027 .arg(qualified_name));
1028 1028 m_rejected_enums.insert(qualified_name, NotInTypeSystem);
1029 1029 return 0;
1030 1030 }
1031 1031
1032 1032 AbstractMetaEnum *meta_enum = createMetaEnum();
1033 1033 if ( enumsDeclarations.contains(qualified_name)
1034 1034 || enumsDeclarations.contains(enum_name)) {
1035 1035 meta_enum->setHasQEnumsDeclaration(true);
1036 1036 }
1037 1037
1038 1038 meta_enum->setTypeEntry((EnumTypeEntry *) type_entry);
1039 1039 switch (enum_item->accessPolicy()) {
1040 1040 case CodeModel::Public: *meta_enum += AbstractMetaAttributes::Public; break;
1041 1041 case CodeModel::Protected: *meta_enum += AbstractMetaAttributes::Protected; break;
1042 1042 // case CodeModel::Private: *meta_enum += AbstractMetaAttributes::Private; break;
1043 1043 default: break;
1044 1044 }
1045 1045
1046 1046 ReportHandler::debugMedium(QString(" - traversing enum %1").arg(meta_enum->fullName()));
1047 1047
1048 1048 foreach (EnumeratorModelItem value, enum_item->enumerators()) {
1049 1049
1050 1050 AbstractMetaEnumValue *meta_enum_value = createMetaEnumValue();
1051 1051 meta_enum_value->setName(value->name());
1052 1052 // Deciding the enum value...
1053 1053
1054 1054 meta_enum_value->setStringValue(value->value());
1055 1055 meta_enum->addEnumValue(meta_enum_value);
1056 1056
1057 1057 ReportHandler::debugFull(" - " + meta_enum_value->name() + " = "
1058 1058 + meta_enum_value->value());
1059 1059
1060 1060 // Add into global register...
1061 1061 if (enclosing)
1062 1062 m_enum_values[enclosing->name() + "::" + meta_enum_value->name()] = meta_enum_value;
1063 1063 else
1064 1064 m_enum_values[meta_enum_value->name()] = meta_enum_value;
1065 1065 }
1066 1066
1067 1067 QFileInfo info(enum_item->fileName());
1068 1068 meta_enum->typeEntry()->setInclude(Include(Include::IncludePath, info.fileName()));
1069 1069
1070 1070 m_enums << meta_enum;
1071 1071
1072 1072 return meta_enum;
1073 1073 }
1074 1074
1075 1075 AbstractMetaClass *AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typeAlias)
1076 1076 {
1077 1077 QString class_name = strip_template_args(typeAlias->name());
1078 1078
1079 1079 QString full_class_name = class_name;
1080 1080 // we have an inner class
1081 1081 if (m_current_class) {
1082 1082 full_class_name = strip_template_args(m_current_class->typeEntry()->qualifiedCppName())
1083 1083 + "::" + full_class_name;
1084 1084 }
1085 1085
1086 1086 // If we haven't specified anything for the typedef, then we don't care
1087 1087 ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(full_class_name);
1088 1088 if (type == 0)
1089 1089 return 0;
1090 1090
1091 1091 if (type->isObject())
1092 1092 static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(strip_template_args(typeAlias->type().qualifiedName().join("::"))));
1093 1093
1094 1094 AbstractMetaClass *meta_class = createMetaClass();
1095 1095 meta_class->setTypeAlias(true);
1096 1096 meta_class->setTypeEntry(type);
1097 1097 meta_class->setBaseClassNames(QStringList() << typeAlias->type().qualifiedName().join("::"));
1098 1098 *meta_class += AbstractMetaAttributes::Public;
1099 1099
1100 1100 // Set the default include file name
1101 1101 if (!type->include().isValid()) {
1102 1102 QFileInfo info(typeAlias->fileName());
1103 1103 type->setInclude(Include(Include::IncludePath, info.fileName()));
1104 1104 }
1105 1105
1106 1106 return meta_class;
1107 1107 }
1108 1108
1109 1109 AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem class_item)
1110 1110 {
1111 1111 QString class_name = strip_template_args(class_item->name());
1112 1112 QString full_class_name = class_name;
1113 1113
1114 1114 // we have inner an class
1115 1115 if (m_current_class) {
1116 1116 full_class_name = strip_template_args(m_current_class->typeEntry()->qualifiedCppName())
1117 1117 + "::" + full_class_name;
1118 1118 }
1119 1119
1120 1120 ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(full_class_name);
1121 1121 RejectReason reason = NoReason;
1122 1122
1123 1123 if (full_class_name == "QMetaTypeId") {
1124 1124 // QtScript: record which types have been declared
1125 1125 int lpos = class_item->name().indexOf('<');
1126 1126 int rpos = class_item->name().lastIndexOf('>');
1127 1127 if ((lpos != -1) && (rpos != -1)) {
1128 1128 QString declared_typename = class_item->name().mid(lpos+1, rpos - lpos-1);
1129 1129 m_qmetatype_declared_typenames.insert(declared_typename);
1130 1130 }
1131 1131 }
1132 1132
1133 1133 if (TypeDatabase::instance()->isClassRejected(full_class_name)) {
1134 1134 reason = GenerationDisabled;
1135 1135 } else if (!type) {
1136 1136 TypeEntry *te = TypeDatabase::instance()->findType(full_class_name);
1137 1137 if (te && !te->isComplex())
1138 1138 reason = RedefinedToNotClass;
1139 1139 else
1140 1140 reason = NotInTypeSystem;
1141 1141 } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
1142 1142 reason = GenerationDisabled;
1143 1143 }
1144 1144
1145 1145 if (reason != NoReason) {
1146 1146 m_rejected_classes.insert(full_class_name, reason);
1147 1147 return 0;
1148 1148 }
1149 1149
1150 1150 if (type->isObject()) {
1151 1151 ((ObjectTypeEntry *)type)->setQObject(isQObject(full_class_name));
1152 1152 }
1153 1153
1154 1154 AbstractMetaClass *meta_class = createMetaClass();
1155 1155 meta_class->setTypeEntry(type);
1156 1156 meta_class->setBaseClassNames(class_item->baseClasses());
1157 1157 *meta_class += AbstractMetaAttributes::Public;
1158 1158
1159 1159 AbstractMetaClass *old_current_class = m_current_class;
1160 1160 m_current_class = meta_class;
1161 1161
1162 1162 if (type->isContainer()) {
1163 1163 ReportHandler::debugSparse(QString("container: '%1'").arg(full_class_name));
1164 1164 } else {
1165 1165 ReportHandler::debugSparse(QString("class: '%1'").arg(meta_class->fullName()));
1166 1166 }
1167 1167
1168 1168 TemplateParameterList template_parameters = class_item->templateParameters();
1169 1169 QList<TypeEntry *> template_args;
1170 1170 template_args.clear();
1171 1171 for (int i=0; i<template_parameters.size(); ++i) {
1172 1172 const TemplateParameterModelItem &param = template_parameters.at(i);
1173 1173 TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name());
1174 1174 param_type->setOrdinal(i);
1175 1175 template_args.append(param_type);
1176 1176 }
1177 1177 meta_class->setTemplateArguments(template_args);
1178 1178
1179 1179 parseQ_Property(meta_class, class_item->propertyDeclarations());
1180 1180
1181 1181 traverseFunctions(model_dynamic_cast<ScopeModelItem>(class_item), meta_class);
1182 1182 traverseEnums(model_dynamic_cast<ScopeModelItem>(class_item), meta_class, class_item->enumsDeclarations());
1183 1183 traverseFields(model_dynamic_cast<ScopeModelItem>(class_item), meta_class);
1184 1184
1185 1185 // Inner classes
1186 1186 {
1187 1187 QList<ClassModelItem> inner_classes = class_item->classMap().values();
1188 1188 foreach (const ClassModelItem &ci, inner_classes) {
1189 1189 AbstractMetaClass *cl = traverseClass(ci);
1190 1190 if (cl) {
1191 1191 cl->setEnclosingClass(meta_class);
1192 1192 m_meta_classes << cl;
1193 1193 }
1194 1194 }
1195 1195
1196 1196 }
1197 1197
1198 1198 // Go through all typedefs to see if we have defined any
1199 1199 // specific typedefs to be used as classes.
1200 1200 TypeAliasList typeAliases = class_item->typeAliases();
1201 1201 foreach (TypeAliasModelItem typeAlias, typeAliases) {
1202 1202 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
1203 1203 if (cls != 0) {
1204 1204 cls->setEnclosingClass(meta_class);
1205 1205 addAbstractMetaClass(cls);
1206 1206 }
1207 1207 }
1208 1208
1209 1209
1210 1210 m_current_class = old_current_class;
1211 1211
1212 1212 // Set the default include file name
1213 1213 if (!type->include().isValid()) {
1214 1214 QFileInfo info(class_item->fileName());
1215 1215 type->setInclude(Include(Include::IncludePath, info.fileName()));
1216 1216 }
1217 1217
1218 1218 return meta_class;
1219 1219 }
1220 1220
1221 1221 AbstractMetaField *AbstractMetaBuilder::traverseField(VariableModelItem field, const AbstractMetaClass *cls)
1222 1222 {
1223 1223 QString field_name = field->name();
1224 1224 QString class_name = m_current_class->typeEntry()->qualifiedCppName();
1225 1225
1226 1226 // Ignore friend decl.
1227 1227 if (field->isFriend())
1228 1228 return 0;
1229 1229
1230 1230 if (field->accessPolicy() == CodeModel::Private)
1231 1231 return 0;
1232 1232
1233 1233 if (TypeDatabase::instance()->isFieldRejected(class_name, field_name)) {
1234 1234 m_rejected_fields.insert(class_name + "::" + field_name, GenerationDisabled);
1235 1235 return 0;
1236 1236 }
1237 1237
1238 1238
1239 1239 AbstractMetaField *meta_field = createMetaField();
1240 1240 meta_field->setName(field_name);
1241 1241 meta_field->setEnclosingClass(cls);
1242 1242
1243 1243 bool ok;
1244 1244 TypeInfo field_type = field->type();
1245 1245 AbstractMetaType *meta_type = translateType(field_type, &ok);
1246 1246
1247 1247 if (!meta_type || !ok) {
1248 1248 ReportHandler::warning(QString("skipping field '%1::%2' with unmatched type '%3'")
1249 1249 .arg(m_current_class->name())
1250 1250 .arg(field_name)
1251 1251 .arg(TypeInfo::resolveType(field_type, currentScope()->toItem()).qualifiedName().join("::")));
1252 1252 delete meta_field;
1253 1253 return 0;
1254 1254 }
1255 1255
1256 1256 meta_field->setType(meta_type);
1257 1257
1258 1258 uint attr = 0;
1259 1259 if (field->isStatic())
1260 1260 attr |= AbstractMetaAttributes::Static;
1261 1261
1262 1262 CodeModel::AccessPolicy policy = field->accessPolicy();
1263 1263 if (policy == CodeModel::Public)
1264 1264 attr |= AbstractMetaAttributes::Public;
1265 1265 else if (policy == CodeModel::Protected)
1266 1266 attr |= AbstractMetaAttributes::Protected;
1267 1267 else
1268 1268 attr |= AbstractMetaAttributes::Private;
1269 1269 meta_field->setAttributes(attr);
1270 1270
1271 1271 return meta_field;
1272 1272 }
1273 1273
1274 1274 void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMetaClass *meta_class)
1275 1275 {
1276 1276 foreach (VariableModelItem field, scope_item->variables()) {
1277 1277 AbstractMetaField *meta_field = traverseField(field, meta_class);
1278 1278
1279 1279 if (meta_field) {
1280 1280 meta_field->setOriginalAttributes(meta_field->attributes());
1281 1281 meta_class->addField(meta_field);
1282 1282 }
1283 1283 }
1284 1284 }
1285 1285
1286 1286 void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction *meta_function, AbstractMetaClass *meta_class)
1287 1287 {
1288 1288 // Set the default value of the declaring class. This may be changed
1289 1289 // in fixFunctions later on
1290 1290 meta_function->setDeclaringClass(meta_class);
1291 1291
1292 1292 // Some of the queries below depend on the implementing class being set
1293 1293 // to function properly. Such as function modifications
1294 1294 meta_function->setImplementingClass(meta_class);
1295 1295
1296 1296 if (meta_function->name() == "operator_equal")
1297 1297 meta_class->setHasEqualsOperator(true);
1298 1298
1299 1299 if (!meta_function->isFinalInTargetLang()
1300 1300 && meta_function->isRemovedFrom(meta_class, TypeSystem::TargetLangCode)) {
1301 1301 *meta_function += AbstractMetaAttributes::FinalInCpp;
1302 1302 }
1303 1303 }
1304 1304
1305 1305 void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractMetaClass *meta_class)
1306 1306 {
1307 1307 foreach (FunctionModelItem function, scope_item->functions()) {
1308 1308 AbstractMetaFunction *meta_function = traverseFunction(function);
1309 1309
1310 1310 if (meta_function) {
1311 1311 meta_function->setOriginalAttributes(meta_function->attributes());
1312 1312 if (meta_class->isNamespace())
1313 1313 *meta_function += AbstractMetaAttributes::Static;
1314 1314
1315 1315 if (QPropertySpec *read = meta_class->propertySpecForRead(meta_function->name())) {
1316 1316 if (read->type() == meta_function->type()->typeEntry()) {
1317 1317 *meta_function += AbstractMetaAttributes::PropertyReader;
1318 1318 meta_function->setPropertySpec(read);
1319 1319 // printf("%s is reader for %s\n",
1320 1320 // qPrintable(meta_function->name()),
1321 1321 // qPrintable(read->name()));
1322 1322 }
1323 1323 } else if (QPropertySpec *write =
1324 1324 meta_class->propertySpecForWrite(meta_function->name())) {
1325 1325 if (write->type() == meta_function->arguments().at(0)->type()->typeEntry()) {
1326 1326 *meta_function += AbstractMetaAttributes::PropertyWriter;
1327 1327 meta_function->setPropertySpec(write);
1328 1328 // printf("%s is writer for %s\n",
1329 1329 // qPrintable(meta_function->name()),
1330 1330 // qPrintable(write->name()));
1331 1331 }
1332 1332 } else if (QPropertySpec *reset =
1333 1333 meta_class->propertySpecForReset(meta_function->name())) {
1334 1334 *meta_function += AbstractMetaAttributes::PropertyResetter;
1335 1335 meta_function->setPropertySpec(reset);
1336 1336 // printf("%s is resetter for %s\n",
1337 1337 // qPrintable(meta_function->name()),
1338 1338 // qPrintable(reset->name()));
1339 1339 }
1340 1340
1341 1341
1342 1342 bool isInvalidDestructor = meta_function->isDestructor() && meta_function->isPrivate();
1343 1343 bool isInvalidConstructor = meta_function->isConstructor()
1344 1344 && (meta_function->isPrivate() || meta_function->isInvalid());
1345 1345 if ((isInvalidDestructor || isInvalidConstructor)
1346 1346 && !meta_class->hasNonPrivateConstructor()) {
1347 1347 *meta_class += AbstractMetaAttributes::Final;
1348 1348 } else if (meta_function->isConstructor() && !meta_function->isPrivate()) {
1349 1349 *meta_class -= AbstractMetaAttributes::Final;
1350 1350 meta_class->setHasNonPrivateConstructor(true);
1351 1351 }
1352 1352
1353 1353 // Classes with virtual destructors should always have a shell class
1354 1354 // (since we aren't registering the destructors, we need this extra check)
1355 1355 if (meta_function->isDestructor() && !meta_function->isFinal())
1356 1356 meta_class->setForceShellClass(true);
1357 1357
1358 1358 if (!meta_function->isDestructor()
1359 1359 && !meta_function->isInvalid()
1360 1360 && (!meta_function->isConstructor() || !meta_function->isPrivate())) {
1361 1361
1362 1362 if (meta_class->typeEntry()->designatedInterface() && !meta_function->isPublic()
1363 1363 && !meta_function->isPrivate()) {
1364 1364 QString warn = QString("non-public function '%1' in interface '%2'")
1365 1365 .arg(meta_function->name()).arg(meta_class->name());
1366 1366 ReportHandler::warning(warn);
1367 1367
1368 1368 meta_function->setVisibility(AbstractMetaClass::Public);
1369 1369 }
1370 1370
1371 1371 setupFunctionDefaults(meta_function, meta_class);
1372 1372
1373 1373 if (meta_function->isSignal() && meta_class->hasSignal(meta_function)) {
1374 1374 QString warn = QString("signal '%1' in class '%2' is overloaded.")
1375 1375 .arg(meta_function->name()).arg(meta_class->name());
1376 1376 ReportHandler::warning(warn);
1377 1377 }
1378 1378
1379 1379 if (meta_function->isSignal() && !meta_class->isQObject()) {
1380 1380 QString warn = QString("signal '%1' in non-QObject class '%2'")
1381 1381 .arg(meta_function->name()).arg(meta_class->name());
1382 1382 ReportHandler::warning(warn);
1383 1383 }
1384 1384
1385 1385 meta_class->addFunction(meta_function);
1386 1386 } else if (meta_function->isDestructor() && !meta_function->isPublic()) {
1387 1387 meta_class->setHasPublicDestructor(false);
1388 1388 }
1389 1389 }
1390 1390 }
1391 1391 }
1392 1392
1393 1393 bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class)
1394 1394 {
1395 1395 Q_ASSERT(!meta_class->isInterface());
1396 1396
1397 1397 if (m_setup_inheritance_done.contains(meta_class))
1398 1398 return true;
1399 1399 m_setup_inheritance_done.insert(meta_class);
1400 1400
1401 1401 QStringList base_classes = meta_class->baseClassNames();
1402 1402
1403 1403 TypeDatabase *types = TypeDatabase::instance();
1404 1404
1405 1405 // we only support our own containers and ONLY if there is only one baseclass
1406 1406 if (base_classes.size() == 1 && base_classes.first().count('<') == 1) {
1407 1407 QStringList scope = meta_class->typeEntry()->qualifiedCppName().split("::");
1408 1408 scope.removeLast();
1409 1409 for (int i=scope.size(); i>=0; --i) {
1410 1410 QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join("::") + "::" : QString();
1411 1411 QString complete_name = prefix + base_classes.first();
1412 1412 TypeParser::Info info = TypeParser::parse(complete_name);
1413 1413 QString base_name = info.qualified_name.join("::");
1414 1414
1415 1415 AbstractMetaClass *templ = 0;
1416 1416 foreach (AbstractMetaClass *c, m_templates) {
1417 1417 if (c->typeEntry()->name() == base_name) {
1418 1418 templ = c;
1419 1419 break;
1420 1420 }
1421 1421 }
1422 1422
1423 1423 if (templ == 0)
1424 1424 templ = m_meta_classes.findClass(base_name);
1425 1425
1426 1426 if (templ) {
1427 1427 setupInheritance(templ);
1428 1428 inheritTemplate(meta_class, templ, info);
1429 1429 return true;
1430 1430 }
1431 1431 }
1432 1432
1433 1433 ReportHandler::warning(QString("template baseclass '%1' of '%2' is not known")
1434 1434 .arg(base_classes.first())
1435 1435 .arg(meta_class->name()));
1436 1436 return false;
1437 1437 }
1438 1438
1439 1439 int primary = -1;
1440 1440 int primaries = 0;
1441 1441 for (int i=0; i<base_classes.size(); ++i) {
1442 1442
1443 1443 if (types->isClassRejected(base_classes.at(i)))
1444 1444 continue;
1445 1445
1446 1446 TypeEntry *base_class_entry = types->findType(base_classes.at(i));
1447 1447 if (!base_class_entry) {
1448 1448 ReportHandler::warning(QString("class '%1' inherits from unknown base class '%2'")
1449 1449 .arg(meta_class->name()).arg(base_classes.at(i)));
1450 1450 }
1451 1451
1452 1452 // true for primary base class
1453 1453 else if (!base_class_entry->designatedInterface()) {
1454 1454 if (primaries > 0) {
1455 1455 ReportHandler::warning(QString("class '%1' has multiple primary base classes"
1456 1456 " '%2' and '%3'")
1457 1457 .arg(meta_class->name())
1458 1458 .arg(base_classes.at(primary))
1459 1459 .arg(base_class_entry->name()));
1460 1460 return false;
1461 1461 }
1462 1462 primaries++;
1463 1463 primary = i;
1464 1464 }
1465 1465 }
1466 1466
1467 1467 if (primary >= 0) {
1468 1468 AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(primary));
1469 1469 if (!base_class) {
1470 1470 ReportHandler::warning(QString("unknown baseclass for '%1': '%2'")
1471 1471 .arg(meta_class->name())
1472 1472 .arg(base_classes.at(primary)));
1473 1473 return false;
1474 1474 }
1475 1475 meta_class->setBaseClass(base_class);
1476 1476
1477 1477 if (meta_class->typeEntry()->designatedInterface() != 0 && meta_class->isQObject()) {
1478 1478 ReportHandler::warning(QString("QObject extended by interface type '%1'. This is not supported and the generated Java code will not compile.")
1479 1479 .arg(meta_class->name()));
1480 1480 } else if (meta_class->typeEntry()->designatedInterface() != 0 && base_class != 0 && !base_class->isInterface()) {
1481 1481 ReportHandler::warning(QString("object type '%1' extended by interface type '%2'. The resulting API will be less expressive than the original.")
1482 1482 .arg(base_class->name())
1483 1483 .arg(meta_class->name()));
1484 1484 }
1485 1485
1486 1486 }
1487 1487
1488 1488 for (int i=0; i<base_classes.size(); ++i) {
1489 1489 if (types->isClassRejected(base_classes.at(i)))
1490 1490 continue;
1491 1491
1492 1492 if (i != primary) {
1493 1493 AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(i));
1494 1494 if (base_class == 0) {
1495 1495 ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(base_classes.at(i)));
1496 1496 return false;
1497 1497 }
1498 1498
1499 1499 setupInheritance(base_class);
1500 1500
1501 1501 QString interface_name = InterfaceTypeEntry::interfaceName(base_class->name());
1502 1502 AbstractMetaClass *iface = m_meta_classes.findClass(interface_name);
1503 1503 if (!iface) {
1504 1504 ReportHandler::warning(QString("unknown interface for '%1': '%2'")
1505 1505 .arg(meta_class->name())
1506 1506 .arg(interface_name));
1507 1507 return false;
1508 1508 }
1509 1509 meta_class->addInterface(iface);
1510 1510
1511 1511 AbstractMetaClassList interfaces = iface->interfaces();
1512 1512 foreach (AbstractMetaClass *iface, interfaces)
1513 1513 meta_class->addInterface(iface);
1514 1514 }
1515 1515 }
1516 1516
1517 1517 return true;
1518 1518 }
1519 1519
1520 1520 void AbstractMetaBuilder::traverseEnums(ScopeModelItem scope_item, AbstractMetaClass *meta_class, const QStringList &enumsDeclarations)
1521 1521 {
1522 1522 EnumList enums = scope_item->enums();
1523 1523 foreach (EnumModelItem enum_item, enums) {
1524 1524 AbstractMetaEnum *meta_enum = traverseEnum(enum_item, meta_class, QSet<QString>::fromList(enumsDeclarations));
1525 1525 if (meta_enum) {
1526 1526 meta_enum->setOriginalAttributes(meta_enum->attributes());
1527 1527 meta_class->addEnum(meta_enum);
1528 1528 meta_enum->setEnclosingClass(meta_class);
1529 1529 }
1530 1530 }
1531 1531 }
1532 1532
1533 1533 AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem function_item)
1534 1534 {
1535 1535 QString function_name = function_item->name();
1536 1536 QString class_name = m_current_class->typeEntry()->qualifiedCppName();
1537 1537
1538 1538 if (TypeDatabase::instance()->isFunctionRejected(class_name, function_name)) {
1539 1539 m_rejected_functions.insert(class_name + "::" + function_name, GenerationDisabled);
1540 1540 return 0;
1541 1541 }
1542 1542
1543 1543
1544 1544 Q_ASSERT(function_item->functionType() == CodeModel::Normal
1545 1545 || function_item->functionType() == CodeModel::Signal
1546 1546 || function_item->functionType() == CodeModel::Slot);
1547 1547
1548 1548 if (function_item->isFriend())
1549 1549 return 0;
1550 1550
1551 1551
1552 1552 QString cast_type;
1553 1553
1554 1554 if (function_name.startsWith("operator")) {
1555 1555 function_name = rename_operator(function_name.mid(8));
1556 1556 if (function_name.isEmpty()) {
1557 1557 m_rejected_functions.insert(class_name + "::" + function_name,
1558 1558 GenerationDisabled);
1559 1559 return 0;
1560 1560 }
1561 1561 if (function_name.contains("_cast_"))
1562 1562 cast_type = function_name.mid(14).trimmed();
1563 1563 }
1564 1564
1565 1565 AbstractMetaFunction *meta_function = createMetaFunction();
1566 1566 meta_function->setConstant(function_item->isConstant());
1567 1567
1568 1568 ReportHandler::debugMedium(QString(" - %2()").arg(function_name));
1569 1569
1570 1570 meta_function->setName(function_name);
1571 1571 meta_function->setOriginalName(function_item->name());
1572 1572
1573 1573 if (function_item->isAbstract())
1574 1574 *meta_function += AbstractMetaAttributes::Abstract;
1575 1575
1576 1576 if (!meta_function->isAbstract())
1577 1577 *meta_function += AbstractMetaAttributes::Native;
1578 1578
1579 1579 if (!function_item->isVirtual())
1580 1580 *meta_function += AbstractMetaAttributes::Final;
1581 1581
1582 1582 if (function_item->isInvokable())
1583 1583 *meta_function += AbstractMetaAttributes::Invokable;
1584 1584
1585 1585 if (function_item->isStatic()) {
1586 1586 *meta_function += AbstractMetaAttributes::Static;
1587 1587 *meta_function += AbstractMetaAttributes::Final;
1588 1588 }
1589 1589
1590 1590 // Access rights
1591 1591 if (function_item->accessPolicy() == CodeModel::Public)
1592 1592 *meta_function += AbstractMetaAttributes::Public;
1593 1593 else if (function_item->accessPolicy() == CodeModel::Private)
1594 1594 *meta_function += AbstractMetaAttributes::Private;
1595 1595 else
1596 1596 *meta_function += AbstractMetaAttributes::Protected;
1597 1597
1598 1598
1599 1599 QString stripped_class_name = class_name;
1600 1600 int cc_pos = stripped_class_name.lastIndexOf("::");
1601 1601 if (cc_pos > 0)
1602 1602 stripped_class_name = stripped_class_name.mid(cc_pos + 2);
1603 1603
1604 1604 TypeInfo function_type = function_item->type();
1605 1605 if (function_name.startsWith('~')) {
1606 1606 meta_function->setFunctionType(AbstractMetaFunction::DestructorFunction);
1607 1607 meta_function->setInvalid(true);
1608 1608 } else if (strip_template_args(function_name) == stripped_class_name) {
1609 1609 meta_function->setFunctionType(AbstractMetaFunction::ConstructorFunction);
1610 1610 meta_function->setName(m_current_class->name());
1611 1611 } else {
1612 1612 bool ok;
1613 1613 AbstractMetaType *type = 0;
1614 1614
1615 1615 if (!cast_type.isEmpty()) {
1616 1616 TypeInfo info;
1617 1617 info.setQualifiedName(QStringList(cast_type));
1618 1618 type = translateType(info, &ok);
1619 1619 } else {
1620 1620 type = translateType(function_type, &ok);
1621 1621 }
1622 1622
1623 1623 if (!ok) {
1624 1624 ReportHandler::warning(QString("skipping function '%1::%2', unmatched return type '%3'")
1625 1625 .arg(class_name)
1626 1626 .arg(function_item->name())
1627 1627 .arg(function_item->type().toString()));
1628 1628 m_rejected_functions[class_name + "::" + function_name] =
1629 1629 UnmatchedReturnType;
1630 1630 meta_function->setInvalid(true);
1631 1631 return meta_function;
1632 1632 }
1633 1633 meta_function->setType(type);
1634 1634
1635 1635 if (function_item->functionType() == CodeModel::Signal)
1636 1636 meta_function->setFunctionType(AbstractMetaFunction::SignalFunction);
1637 1637 else if (function_item->functionType() == CodeModel::Slot)
1638 1638 meta_function->setFunctionType(AbstractMetaFunction::SlotFunction);
1639 1639 }
1640 1640
1641 1641 ArgumentList arguments = function_item->arguments();
1642 1642 AbstractMetaArgumentList meta_arguments;
1643 1643
1644 1644 int first_default_argument = 0;
1645 1645 for (int i=0; i<arguments.size(); ++i) {
1646 1646 ArgumentModelItem arg = arguments.at(i);
1647 1647
1648 1648 bool ok;
1649 1649 AbstractMetaType *meta_type = translateType(arg->type(), &ok);
1650 1650 if (!meta_type || !ok) {
1651 1651 ReportHandler::warning(QString("skipping function '%1::%2', "
1652 1652 "unmatched parameter type '%3'")
1653 1653 .arg(class_name)
1654 1654 .arg(function_item->name())
1655 1655 .arg(arg->type().toString()));
1656 1656 m_rejected_functions[class_name + "::" + function_name] =
1657 1657 UnmatchedArgumentType;
1658 1658 meta_function->setInvalid(true);
1659 1659 return meta_function;
1660 1660 }
1661 1661 AbstractMetaArgument *meta_argument = createMetaArgument();
1662 1662 meta_argument->setType(meta_type);
1663 1663 meta_argument->setName(arg->name());
1664 1664 meta_argument->setArgumentIndex(i);
1665 1665 meta_arguments << meta_argument;
1666 1666 }
1667 1667
1668 1668 meta_function->setArguments(meta_arguments);
1669 1669
1670 1670 // Find the correct default values
1671 1671 for (int i=0; i<arguments.size(); ++i) {
1672 1672 ArgumentModelItem arg = arguments.at(i);
1673 1673 AbstractMetaArgument *meta_arg = meta_arguments.at(i);
1674 1674 if (arg->defaultValue()) {
1675 1675 QString expr = arg->defaultValueExpression();
1676 1676 if (!expr.isEmpty())
1677 1677 meta_arg->setOriginalDefaultValueExpression(expr);
1678 1678
1679 1679 expr = translateDefaultValue(arg, meta_arg->type(), meta_function, m_current_class, i);
1680 1680 if (expr.isEmpty()) {
1681 1681 first_default_argument = i;
1682 1682 } else {
1683 1683 meta_arg->setDefaultValueExpression(expr);
1684 1684 }
1685 1685
1686 1686 if (meta_arg->type()->isEnum() || meta_arg->type()->isFlags()) {
1687 1687 m_enum_default_arguments
1688 1688 << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(meta_arg, meta_function);
1689 1689 }
1690 1690
1691 1691 }
1692 1692 }
1693 1693
1694 1694 // If we where not able to translate the default argument make it
1695 1695 // reset all default arguments before this one too.
1696 1696 for (int i=0; i<first_default_argument; ++i)
1697 1697 meta_arguments[i]->setDefaultValueExpression(QString());
1698 1698
1699 1699 if (ReportHandler::debugLevel() == ReportHandler::FullDebug)
1700 1700 foreach(AbstractMetaArgument *arg, meta_arguments)
1701 1701 ReportHandler::debugFull(" - " + arg->toString());
1702 1702
1703 1703 return meta_function;
1704 1704 }
1705 1705
1706 1706
1707 1707 AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, bool *ok, bool resolveType, bool resolveScope)
1708 1708 {
1709 1709 Q_ASSERT(ok);
1710 1710 *ok = true;
1711 1711
1712 1712 // 1. Test the type info without resolving typedefs in case this is present in the
1713 1713 // type system
1714 1714 TypeInfo typei;
1715 1715 if (resolveType) {
1716 1716 bool isok;
1717 1717 AbstractMetaType *t = translateType(_typei, &isok, false, resolveScope);
1718 1718 if (t != 0 && isok)
1719 1719 return t;
1720 1720 }
1721 1721
1722 1722 if (!resolveType)
1723 1723 typei = _typei;
1724 1724 else {
1725 1725 // Go through all parts of the current scope (including global namespace)
1726 1726 // to resolve typedefs. The parser does not properly resolve typedefs in
1727 1727 // the global scope when they are referenced from inside a namespace.
1728 1728 // This is a work around to fix this bug since fixing it in resolveType
1729 1729 // seemed non-trivial
1730 1730 int i = m_scopes.size() - 1;
1731 1731 while (i >= 0) {
1732 1732 typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)->toItem());
1733 1733 if (typei.qualifiedName().join("::") != _typei.qualifiedName().join("::"))
1734 1734 break;
1735 1735 }
1736 1736
1737 1737 }
1738 1738
1739 1739 if (typei.isFunctionPointer()) {
1740 1740 *ok = false;
1741 1741 return 0;
1742 1742 }
1743 1743
1744 1744 TypeParser::Info typeInfo = TypeParser::parse(typei.toString());
1745 1745 if (typeInfo.is_busted) {
1746 1746 *ok = false;
1747 1747 return 0;
1748 1748 }
1749 1749
1750 1750 // 2. Handle pointers specified as arrays with unspecified size
1751 1751 bool array_of_unspecified_size = false;
1752 1752 if (typeInfo.arrays.size() > 0) {
1753 1753 array_of_unspecified_size = true;
1754 1754 for (int i=0; i<typeInfo.arrays.size(); ++i)
1755 1755 array_of_unspecified_size = array_of_unspecified_size && typeInfo.arrays.at(i).isEmpty();
1756 1756
1757 1757 if (!array_of_unspecified_size) {
1758 1758 TypeInfo newInfo;
1759 1759 //newInfo.setArguments(typei.arguments());
1760 1760 newInfo.setIndirections(typei.indirections());
1761 1761 newInfo.setConstant(typei.isConstant());
1762 1762 newInfo.setFunctionPointer(typei.isFunctionPointer());
1763 1763 newInfo.setQualifiedName(typei.qualifiedName());
1764 1764 newInfo.setReference(typei.isReference());
1765 1765 newInfo.setVolatile(typei.isVolatile());
1766 1766
1767 1767 AbstractMetaType *elementType = translateType(newInfo, ok);
1768 1768 if (!(*ok))
1769 1769 return 0;
1770 1770
1771 1771 for (int i=typeInfo.arrays.size()-1; i>=0; --i) {
1772 1772 QString s = typeInfo.arrays.at(i);
1773 1773 bool isok;
1774 1774
1775 1775 int elems = s.toInt(&isok);
1776 1776 if (!isok)
1777 1777 return 0;
1778 1778
1779 1779 AbstractMetaType *arrayType = createMetaType();
1780 1780 arrayType->setArrayElementCount(elems);
1781 1781 arrayType->setArrayElementType(elementType);
1782 1782 arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry()));
1783 1783 decideUsagePattern(arrayType);
1784 1784
1785 1785 elementType = arrayType;
1786 1786 }
1787 1787
1788 1788 return elementType;
1789 1789 } else {
1790 1790 typeInfo.indirections += typeInfo.arrays.size();
1791 1791 }
1792 1792 }
1793 1793
1794 1794 QStringList qualifier_list = typeInfo.qualified_name;
1795 1795 if (qualifier_list.isEmpty()) {
1796 1796 ReportHandler::warning(QString("horribly broken type '%1'").arg(_typei.toString()));
1797 1797 *ok = false;
1798 1798 return 0;
1799 1799 }
1800 1800
1801 1801 QString qualified_name = qualifier_list.join("::");
1802 1802 QString name = qualifier_list.takeLast();
1803 1803
1804 1804 // 3. Special case 'void' type
1805 1805 if (name == "void" && typeInfo.indirections == 0) {
1806 1806 return 0;
1807 1807 }
1808 1808
1809 1809 // 4. Special case QFlags (include instantiation in name)
1810 1810 if (qualified_name == "QFlags")
1811 1811 qualified_name = typeInfo.toString();
1812 1812
1813 1813 // 5. Try to find the type
1814 1814 const TypeEntry *type = TypeDatabase::instance()->findType(qualified_name);
1815 1815
1816 1816 // 6. No? Try looking it up as a flags type
1817 1817 if (!type)
1818 1818 type = TypeDatabase::instance()->findFlagsType(qualified_name);
1819 1819
1820 1820 // 7. No? Try looking it up as a container type
1821 1821 if (!type)
1822 1822 type = TypeDatabase::instance()->findContainerType(name);
1823 1823
1824 1824 // 8. No? Check if the current class is a template and this type is one
1825 1825 // of the parameters.
1826 1826 if (type == 0 && m_current_class != 0) {
1827 1827 QList<TypeEntry *> template_args = m_current_class->templateArguments();
1828 1828 foreach (TypeEntry *te, template_args) {
1829 1829 if (te->name() == qualified_name)
1830 1830 type = te;
1831 1831 }
1832 1832 }
1833 1833
1834 1834 // 9. Try finding the type by prefixing it with the current
1835 1835 // context and all baseclasses of the current context
1836 1836 if (!type && !TypeDatabase::instance()->isClassRejected(qualified_name) && m_current_class != 0 && resolveScope) {
1837 1837 QStringList contexts;
1838 1838 contexts.append(m_current_class->qualifiedCppName());
1839 1839 contexts.append(currentScope()->qualifiedName().join("::"));
1840 1840
1841 1841
1842 1842 TypeInfo info = typei;
1843 1843 bool subclasses_done = false;
1844 1844 while (!contexts.isEmpty() && type == 0) {
1845 1845 //type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualified_name);
1846 1846
1847 1847 bool isok;
1848 1848 info.setQualifiedName(QStringList() << contexts.at(0) << qualified_name);
1849 1849 AbstractMetaType *t = translateType(info, &isok, true, false);
1850 1850 if (t != 0 && isok)
1851 1851 return t;
1852 1852
1853 1853 ClassModelItem item = m_dom->findClass(contexts.at(0));
1854 1854 if (item != 0)
1855 1855 contexts += item->baseClasses();
1856 1856 contexts.pop_front();
1857 1857
1858 1858 // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
1859 1859 // enum types from there may be addressed without any scope resolution in properties.
1860 1860 if (contexts.size() == 0 && !subclasses_done) {
1861 1861 contexts << "Qt";
1862 1862 subclasses_done = true;
1863 1863 }
1864 1864 }
1865 1865
1866 1866 }
1867 1867
1868 1868 if (!type) {
1869 1869 *ok = false;
1870 1870 return 0;
1871 1871 }
1872 1872
1873 1873 // Used to for diagnostics later...
1874 1874 m_used_types << type;
1875 1875
1876 1876 // These are only implicit and should not appear in code...
1877 1877 Q_ASSERT(!type->isInterface());
1878 1878
1879 1879 AbstractMetaType *meta_type = createMetaType();
1880 1880 meta_type->setTypeEntry(type);
1881 1881 meta_type->setIndirections(typeInfo.indirections);
1882 1882 meta_type->setReference(typeInfo.is_reference);
1883 1883 meta_type->setConstant(typeInfo.is_constant);
1884 1884 meta_type->setOriginalTypeDescription(_typei.toString());
1885 1885 decideUsagePattern(meta_type);
1886 1886
1887 1887 if (meta_type->typeEntry()->isContainer()) {
1888 1888 ContainerTypeEntry::Type container_type = static_cast<const ContainerTypeEntry *>(type)->type();
1889 1889
1890 1890 if (container_type == ContainerTypeEntry::StringListContainer) {
1891 1891 TypeInfo info;
1892 1892 info.setQualifiedName(QStringList() << "QString");
1893 1893 AbstractMetaType *targ_type = translateType(info, ok);
1894 1894
1895 1895 Q_ASSERT(*ok);
1896 1896 Q_ASSERT(targ_type);
1897 1897
1898 1898 meta_type->addInstantiation(targ_type);
1899 1899 meta_type->setInstantiationInCpp(false);
1900 1900
1901 1901 } else {
1902 1902 foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) {
1903 1903 TypeInfo info;
1904 1904 info.setConstant(ta.is_constant);
1905 1905 info.setReference(ta.is_reference);
1906 1906 info.setIndirections(ta.indirections);
1907 1907
1908 1908 info.setFunctionPointer(false);
1909 1909 info.setQualifiedName(ta.instantiationName().split("::"));
1910 1910
1911 1911 AbstractMetaType *targ_type = translateType(info, ok);
1912 1912 if (!(*ok)) {
1913 1913 delete meta_type;
1914 1914 return 0;
1915 1915 }
1916 1916
1917 1917 meta_type->addInstantiation(targ_type);
1918 1918 }
1919 1919 }
1920 1920
1921 1921 if (container_type == ContainerTypeEntry::ListContainer
1922 1922 || container_type == ContainerTypeEntry::VectorContainer
1923 1923 || container_type == ContainerTypeEntry::StringListContainer) {
1924 1924 Q_ASSERT(meta_type->instantiations().size() == 1);
1925 1925 }
1926 1926 }
1927 1927
1928 1928 return meta_type;
1929 1929 }
1930 1930
1931 1931 void AbstractMetaBuilder::decideUsagePattern(AbstractMetaType *meta_type)
1932 1932 {
1933 1933 const TypeEntry *type = meta_type->typeEntry();
1934 1934
1935 1935 if (type->isPrimitive() && (meta_type->actualIndirections() == 0
1936 1936 || (meta_type->isConstant() && meta_type->isReference() && meta_type->indirections() == 0))) {
1937 1937 meta_type->setTypeUsagePattern(AbstractMetaType::PrimitivePattern);
1938 1938
1939 1939 } else if (type->isVoid()) {
1940 1940 meta_type->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
1941 1941
1942 1942 } else if (type->isString()
1943 1943 && meta_type->indirections() == 0
1944 1944 && (meta_type->isConstant() == meta_type->isReference()
1945 1945 || meta_type->isConstant())) {
1946 1946 meta_type->setTypeUsagePattern(AbstractMetaType::StringPattern);
1947 1947
1948 1948 } else if (type->isChar()
1949 1949 && meta_type->indirections() == 0
1950 1950 && meta_type->isConstant() == meta_type->isReference()) {
1951 1951 meta_type->setTypeUsagePattern(AbstractMetaType::CharPattern);
1952 1952
1953 1953 } else if (type->isJObjectWrapper()
1954 1954 && meta_type->indirections() == 0
1955 1955 && meta_type->isConstant() == meta_type->isReference()) {
1956 1956 meta_type->setTypeUsagePattern(AbstractMetaType::JObjectWrapperPattern);
1957 1957
1958 1958 } else if (type->isVariant()
1959 1959 && meta_type->indirections() == 0
1960 1960 && meta_type->isConstant() == meta_type->isReference()) {
1961 1961 meta_type->setTypeUsagePattern(AbstractMetaType::VariantPattern);
1962 1962
1963 1963 } else if (type->isEnum() && meta_type->actualIndirections() == 0) {
1964 1964 meta_type->setTypeUsagePattern(AbstractMetaType::EnumPattern);
1965 1965
1966 1966 } else if (type->isObject()
1967 1967 && meta_type->indirections() == 0
1968 1968 && meta_type->isReference()) {
1969 1969 if (((ComplexTypeEntry *) type)->isQObject())
1970 1970 meta_type->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
1971 1971 else
1972 1972 meta_type->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
1973 1973
1974 1974 } else if (type->isObject()
1975 1975 && meta_type->indirections() == 1) {
1976 1976 if (((ComplexTypeEntry *) type)->isQObject())
1977 1977 meta_type->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
1978 1978 else
1979 1979 meta_type->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
1980 1980
1981 1981 // const-references to pointers can be passed as pointers
1982 1982 if (meta_type->isReference() && meta_type->isConstant()) {
1983 1983 meta_type->setReference(false);
1984 1984 meta_type->setConstant(false);
1985 1985 }
1986 1986
1987 1987 } else if (type->isContainer() && meta_type->indirections() == 0) {
1988 1988 meta_type->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
1989 1989
1990 1990 } else if (type->isTemplateArgument()) {
1991 1991
1992 1992 } else if (type->isFlags()
1993 1993 && meta_type->indirections() == 0
1994 1994 && (meta_type->isConstant() == meta_type->isReference())) {
1995 1995 meta_type->setTypeUsagePattern(AbstractMetaType::FlagsPattern);
1996 1996
1997 1997 } else if (type->isArray()) {
1998 1998 meta_type->setTypeUsagePattern(AbstractMetaType::ArrayPattern);
1999 1999
2000 2000 } else if (type->isThread()) {
2001 2001 Q_ASSERT(meta_type->indirections() == 1);
2002 2002 meta_type->setTypeUsagePattern(AbstractMetaType::ThreadPattern);
2003 2003
2004 2004 } else if (type->isValue()
2005 2005 && meta_type->indirections() == 0
2006 2006 && (meta_type->isConstant() == meta_type->isReference()
2007 2007 || !meta_type->isReference())) {
2008 2008 meta_type->setTypeUsagePattern(AbstractMetaType::ValuePattern);
2009 2009
2010 2010 } else {
2011 2011 meta_type->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
2012 2012 ReportHandler::debugFull(QString("native pointer pattern for '%1'")
2013 2013 .arg(meta_type->cppSignature()));
2014 2014 }
2015 2015 }
2016 2016
2017 2017 QString AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
2018 2018 AbstractMetaFunction *fnc, AbstractMetaClass *implementing_class,
2019 2019 int argument_index)
2020 2020 {
2021 2021 QString function_name = fnc->name();
2022 2022 QString class_name = implementing_class->name();
2023 2023
2024 2024 QString replaced_expression = fnc->replacedDefaultExpression(implementing_class, argument_index + 1);
2025 2025 if (fnc->removedDefaultExpression(implementing_class, argument_index +1))
2026 2026 return "";
2027 2027 if (!replaced_expression.isEmpty())
2028 2028 return replaced_expression;
2029 2029
2030 2030 QString expr = item->defaultValueExpression();
2031 2031 if (type != 0 && type->isPrimitive()) {
2032 2032 if (type->name() == "boolean") {
2033 2033 if (expr == "false" || expr=="true") {
2034 2034 return expr;
2035 2035 } else {
2036 2036 bool ok = false;
2037 2037 int number = expr.toInt(&ok);
2038 2038 if (ok && number)
2039 2039 return "true";
2040 2040 else
2041 2041 return "false";
2042 2042 }
2043 2043 } else if (expr == "ULONG_MAX") {
2044 2044 return "Long.MAX_VALUE";
2045 2045 } else if (expr == "QVariant::Invalid") {
2046 2046 return QString::number(QVariant::Invalid);
2047 2047 } else {
2048 2048 // This can be an enum or flag so I need to delay the
2049 2049 // translation untill all namespaces are completly
2050 2050 // processed. This is done in figureOutEnumValues()
2051 2051 return expr;
2052 2052 }
2053 2053 } else if (type != 0 && (type->isFlags() || type->isEnum())) {
2054 2054 // Same as with enum explanation above...
2055 2055 return expr;
2056 2056
2057 2057 } else {
2058 2058
2059 2059 // constructor or functioncall can be a bit tricky...
2060 2060 if (expr == "QVariant()" || expr == "QModelIndex()") {
2061 2061 return "null";
2062 2062 } else if (expr == "QString()") {
2063 2063 return "null";
2064 2064 } else if (expr.endsWith(")") && expr.contains("::")) {
2065 2065 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(expr.indexOf("::")));
2066 2066 if (typeEntry)
2067 2067 return typeEntry->qualifiedTargetLangName() + "." + expr.right(expr.length() - expr.indexOf("::") - 2);
2068 2068 } else if (expr.endsWith(")") && type != 0 && type->isValue()) {
2069 2069 int pos = expr.indexOf("(");
2070 2070
2071 2071 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(pos));
2072 2072 if (typeEntry)
2073 2073 return "new " + typeEntry->qualifiedTargetLangName() + expr.right(expr.length() - pos);
2074 2074 else
2075 2075 return expr;
2076 2076 } else if (expr == "0") {
2077 2077 return "null";
2078 2078 } else if (type != 0 && (type->isObject() || type->isValue() || expr.contains("::"))) { // like Qt::black passed to a QColor
2079 2079 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(expr.indexOf("::")));
2080 2080
2081 2081 expr = expr.right(expr.length() - expr.indexOf("::") - 2);
2082 2082 if (typeEntry) {
2083 2083 return "new " + type->typeEntry()->qualifiedTargetLangName() +
2084 2084 "(" + typeEntry->qualifiedTargetLangName() + "." + expr + ")";
2085 2085 }
2086 2086 }
2087 2087 }
2088 2088
2089 2089 QString warn = QString("unsupported default value '%3' of argument in function '%1', class '%2'")
2090 2090 .arg(function_name).arg(class_name).arg(item->defaultValueExpression());
2091 2091 ReportHandler::warning(warn);
2092 2092
2093 2093 return QString();
2094 2094 }
2095 2095
2096 2096
2097 2097 bool AbstractMetaBuilder::isQObject(const QString &qualified_name)
2098 2098 {
2099 2099 if (qualified_name == "QObject")
2100 2100 return true;
2101 2101
2102 2102 ClassModelItem class_item = m_dom->findClass(qualified_name);
2103 2103
2104 2104 if (!class_item) {
2105 2105 QStringList names = qualified_name.split(QLatin1String("::"));
2106 2106 NamespaceModelItem ns = model_dynamic_cast<NamespaceModelItem>(m_dom);
2107 2107 for (int i=0; i<names.size() - 1 && ns; ++i)
2108 2108 ns = ns->namespaceMap().value(names.at(i));
2109 2109 if (ns && names.size() >= 2)
2110 2110 class_item = ns->findClass(names.at(names.size() - 1));
2111 2111 }
2112 2112
2113 2113 bool isqobject = class_item && class_item->extendsClass("QObject");
2114 2114
2115 2115 if (class_item && !isqobject) {
2116 2116 QStringList baseClasses = class_item->baseClasses();
2117 2117 for (int i=0; i<baseClasses.count(); ++i) {
2118 2118
2119 2119 isqobject = isQObject(baseClasses.at(i));
2120 2120 if (isqobject)
2121 2121 break;
2122 2122 }
2123 2123 }
2124 2124
2125 2125 return isqobject;
2126 2126 }
2127 2127
2128 2128
2129 2129 bool AbstractMetaBuilder::isEnum(const QStringList &qualified_name)
2130 2130 {
2131 2131 CodeModelItem item = m_dom->model()->findItem(qualified_name, m_dom->toItem());
2132 2132 return item && item->kind() == _EnumModelItem::__node_kind;
2133 2133 }
2134 2134
2135 2135 AbstractMetaType *AbstractMetaBuilder::inheritTemplateType(const QList<AbstractMetaType *> &template_types,
2136 2136 AbstractMetaType *meta_type, bool *ok)
2137 2137 {
2138 2138 if (ok != 0)
2139 2139 *ok = true;
2140 2140 if (!meta_type || (!meta_type->typeEntry()->isTemplateArgument() && !meta_type->hasInstantiations()))
2141 2141 return meta_type ? meta_type->copy() : 0;
2142 2142
2143 2143 AbstractMetaType *returned = meta_type->copy();
2144 2144 returned->setOriginalTemplateType(meta_type->copy());
2145 2145
2146 2146 if (returned->typeEntry()->isTemplateArgument()) {
2147 2147 const TemplateArgumentEntry *tae = static_cast<const TemplateArgumentEntry *>(returned->typeEntry());
2148 2148
2149 2149 // If the template is intantiated with void we special case this as rejecting the functions that use this
2150 2150 // parameter from the instantiation.
2151 2151 if (template_types.size() <= tae->ordinal() || template_types.at(tae->ordinal())->typeEntry()->name() == "void") {
2152 2152 if (ok != 0)
2153 2153 *ok = false;
2154 2154 return 0;
2155 2155 }
2156 2156
2157 2157 AbstractMetaType *t = returned->copy();
2158 2158 t->setTypeEntry(template_types.at(tae->ordinal())->typeEntry());
2159 2159 t->setIndirections(template_types.at(tae->ordinal())->indirections() + t->indirections()
2160 2160 ? 1
2161 2161 : 0);
2162 2162 decideUsagePattern(t);
2163 2163
2164 2164 delete returned;
2165 2165 returned = inheritTemplateType(template_types, t, ok);
2166 2166 if (ok != 0 && !(*ok))
2167 2167 return 0;
2168 2168 }
2169 2169
2170 2170 if (returned->hasInstantiations()) {
2171 2171 QList<AbstractMetaType *> instantiations = returned->instantiations();
2172 2172 for (int i=0; i<instantiations.count(); ++i) {
2173 2173 instantiations[i] = inheritTemplateType(template_types, instantiations.at(i), ok);
2174 2174 if (ok != 0 && !(*ok))
2175 2175 return 0;
2176 2176 }
2177 2177 returned->setInstantiations(instantiations);
2178 2178 }
2179 2179
2180 2180 return returned;
2181 2181 }
2182 2182
2183 2183 bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass,
2184 2184 const AbstractMetaClass *template_class,
2185 2185 const TypeParser::Info &info)
2186 2186 {
2187 2187 QList<TypeParser::Info> targs = info.template_instantiations;
2188 2188
2189 2189 QList<AbstractMetaType *> template_types;
2190 2190 foreach (const TypeParser::Info &i, targs) {
2191 2191 TypeEntry *t = TypeDatabase::instance()->findType(i.qualified_name.join("::"));
2192 2192
2193 2193 if (t != 0) {
2194 2194 AbstractMetaType *temporary_type = createMetaType();
2195 2195 temporary_type->setTypeEntry(t);
2196 2196 temporary_type->setConstant(i.is_constant);
2197 2197 temporary_type->setReference(i.is_reference);
2198 2198 temporary_type->setIndirections(i.indirections);
2199 2199 template_types << temporary_type;
2200 2200 }
2201 2201 }
2202 2202
2203 2203 AbstractMetaFunctionList funcs = subclass->functions();
2204 2204 foreach (const AbstractMetaFunction *function, template_class->functions()) {
2205 2205
2206 2206 if (function->isModifiedRemoved(TypeSystem::All))
2207 2207 continue;
2208 2208
2209 2209 AbstractMetaFunction *f = function->copy();
2210 2210 f->setArguments(AbstractMetaArgumentList());
2211 2211
2212 2212 bool ok = true;
2213 2213 AbstractMetaType *ftype = function->type();
2214 2214 f->setType(inheritTemplateType(template_types, ftype, &ok));
2215 2215 if (!ok) {
2216 2216 delete f;
2217 2217 continue;
2218 2218 }
2219 2219
2220 2220 foreach (AbstractMetaArgument *argument, function->arguments()) {
2221 2221 AbstractMetaType *atype = argument->type();
2222 2222
2223 2223 AbstractMetaArgument *arg = argument->copy();
2224 2224 arg->setType(inheritTemplateType(template_types, atype, &ok));
2225 2225 if (!ok)
2226 2226 break;
2227 2227 f->addArgument(arg);
2228 2228 }
2229 2229
2230 2230 if (!ok) {
2231 2231 delete f;
2232 2232 continue ;
2233 2233 }
2234 2234
2235 2235 // There is no base class in java to inherit from here, so the
2236 2236 // template instantiation is the class that implements the function..
2237 2237 f->setImplementingClass(subclass);
2238 2238
2239 2239 // We also set it as the declaring class, since the superclass is
2240 2240 // supposed to disappear. This allows us to make certain function modifications
2241 2241 // on the inherited functions.
2242 2242 f->setDeclaringClass(subclass);
2243 2243
2244 2244
2245 2245 if (f->isConstructor() && subclass->isTypeAlias()) {
2246 2246 f->setName(subclass->name());
2247 2247 } else if (f->isConstructor()) {
2248 2248 delete f;
2249 2249 continue;
2250 2250 }
2251 2251
2252 2252 // if the instantiation has a function named the same as an existing
2253 2253 // function we have shadowing so we need to skip it.
2254 2254 bool found = false;
2255 2255 for (int i=0; i<funcs.size(); ++i) {
2256 2256 if (funcs.at(i)->name() == f->name()) {
2257 2257 found = true;
2258 2258 continue;
2259 2259 }
2260 2260 }
2261 2261 if (found) {
2262 2262 delete f;
2263 2263 continue;
2264 2264 }
2265 2265
2266 2266 ComplexTypeEntry *te = subclass->typeEntry();
2267 2267 FunctionModificationList mods = function->modifications(template_class);
2268 2268 for (int i=0; i<mods.size(); ++i) {
2269 2269 FunctionModification mod = mods.at(i);
2270 2270 mod.signature = f->minimalSignature();
2271 2271
2272 2272 // If we ever need it... Below is the code to do
2273 2273 // substitution of the template instantation type inside
2274 2274 // injected code..
2275 2275 #if 0
2276 2276 if (mod.modifiers & Modification::CodeInjection) {
2277 2277 for (int j=0; j<template_types.size(); ++j) {
2278 2278 CodeSnip &snip = mod.snips.last();
2279 2279 QString code = snip.code();
2280 2280 code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
2281 2281 template_types.at(j)->typeEntry()->qualifiedCppName());
2282 2282 snip.codeList.clear();
2283 2283 snip.addCode(code);
2284 2284 }
2285 2285 }
2286 2286 #endif
2287 2287 te->addFunctionModification(mod);
2288 2288 }
2289 2289
2290 2290 subclass->addFunction(f);
2291 2291 }
2292 2292
2293 2293 // Clean up
2294 2294 foreach (AbstractMetaType *type, template_types) {
2295 2295 delete type;
2296 2296 }
2297 2297
2298 2298
2299 2299 {
2300 2300 subclass->setTemplateBaseClass(template_class);
2301 2301
2302 2302 subclass->setInterfaces(template_class->interfaces());
2303 2303 subclass->setBaseClass(template_class->baseClass());
2304 2304 }
2305 2305
2306 2306 return true;
2307 2307 }
2308 2308
2309 2309 void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *meta_class, const QStringList &declarations)
2310 2310 {
2311 2311 for (int i=0; i<declarations.size(); ++i) {
2312 2312 QString p = declarations.at(i);
2313 2313
2314 2314 QStringList l = p.split(QLatin1String(" "));
2315 2315
2316 2316
2317 2317 QStringList qualifiedScopeName = currentScope()->qualifiedName();
2318 2318 bool ok = false;
2319 2319 AbstractMetaType *type = 0;
2320 2320 QString scope;
2321 2321 for (int j=qualifiedScopeName.size(); j>=0; --j) {
2322 2322 scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join("::") + "::" : QString();
2323 2323 TypeInfo info;
2324 2324 info.setQualifiedName((scope + l.at(0)).split("::"));
2325 2325
2326 2326 type = translateType(info, &ok);
2327 2327 if (type != 0 && ok) {
2328 2328 break;
2329 2329 }
2330 2330 }
2331 2331
2332 2332 if (type == 0 || !ok) {
2333 2333 ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'")
2334 2334 .arg(l.at(0)).arg(meta_class->name()));
2335 2335 continue;
2336 2336 }
2337 2337
2338 2338 QString typeName = scope + l.at(0);
2339 2339
2340 2340 QPropertySpec *spec = new QPropertySpec(type->typeEntry());
2341 2341 spec->setName(l.at(1));
2342 2342 spec->setIndex(i);
2343 2343
2344 2344 for (int pos=2; pos+1<l.size(); pos+=2) {
2345 2345 if (l.at(pos) == QLatin1String("READ"))
2346 2346 spec->setRead(l.at(pos+1));
2347 2347 else if (l.at(pos) == QLatin1String("WRITE"))
2348 2348 spec->setWrite(l.at(pos+1));
2349 2349 else if (l.at(pos) == QLatin1String("DESIGNABLE"))
2350 2350 spec->setDesignable(l.at(pos+1));
2351 2351 else if (l.at(pos) == QLatin1String("RESET"))
2352 2352 spec->setReset(l.at(pos+1));
2353 2353 }
2354 2354
2355 2355 meta_class->addPropertySpec(spec);
2356 2356 delete type;
2357 2357 }
2358 2358 }
2359 2359
2360 2360 static void hide_functions(const AbstractMetaFunctionList &l) {
2361 2361 foreach (AbstractMetaFunction *f, l) {
2362 2362 FunctionModification mod;
2363 2363 mod.signature = f->minimalSignature();
2364 2364 mod.modifiers = FunctionModification::Private;
2365 2365 ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
2366 2366 }
2367 2367 }
2368 2368
2369 2369 static void remove_function(AbstractMetaFunction *f) {
2370 2370 FunctionModification mod;
2371 2371 mod.removal = TypeSystem::All;
2372 2372 mod.signature = f->minimalSignature();
2373 2373 ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
2374 2374 }
2375 2375
2376 2376 static AbstractMetaFunctionList filter_functions(const AbstractMetaFunctionList &lst, QSet<QString> *signatures)
2377 2377 {
2378 2378 AbstractMetaFunctionList functions;
2379 2379 foreach (AbstractMetaFunction *f, lst) {
2380 2380 QString signature = f->minimalSignature();
2381 2381 int start = signature.indexOf(QLatin1Char('(')) + 1;
2382 2382 int end = signature.lastIndexOf(QLatin1Char(')'));
2383 2383 signature = signature.mid(start, end - start);
2384 2384 if (signatures->contains(signature)) {
2385 2385 remove_function(f);
2386 2386 continue;
2387 2387 }
2388 2388 (*signatures) << signature;
2389 2389 functions << f;
2390 2390 }
2391 2391 return functions;
2392 2392 }
2393 2393
2394 2394 void AbstractMetaBuilder::setupEquals(AbstractMetaClass *cls)
2395 2395 {
2396 2396 AbstractMetaFunctionList equals;
2397 2397 AbstractMetaFunctionList nequals;
2398 2398
2399 2399 QString op_equals = QLatin1String("operator_equal");
2400 2400 QString op_nequals = QLatin1String("operator_not_equal");
2401 2401
2402 2402 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
2403 2403 | AbstractMetaClass::NotRemovedFromTargetLang);
2404 2404 foreach (AbstractMetaFunction *f, functions) {
2405 2405 if (f->name() == op_equals)
2406 2406 equals << f;
2407 2407 else if (f->name() == op_nequals)
2408 2408 nequals << f;
2409 2409 }
2410 2410
2411 2411 if (equals.size() || nequals.size()) {
2412 2412 if (!cls->hasHashFunction()) {
2413 2413 ReportHandler::warning(QString::fromLatin1("Class '%1' has equals operators but no qHash() function")
2414 2414 .arg(cls->name()));
2415 2415 }
2416 2416
2417 2417 hide_functions(equals);
2418 2418 hide_functions(nequals);
2419 2419
2420 2420 // We only need == if we have both == and !=, and one == for
2421 2421 // each signature type, like QDateTime::==(QDate) and (QTime)
2422 2422 // if such a thing exists...
2423 2423 QSet<QString> func_signatures;
2424 2424 cls->setEqualsFunctions(filter_functions(equals, &func_signatures));
2425 2425 cls->setNotEqualsFunctions(filter_functions(nequals, &func_signatures));
2426 2426 }
2427 2427 }
2428 2428
2429 2429 void AbstractMetaBuilder::setupComparable(AbstractMetaClass *cls)
2430 2430 {
2431 2431 AbstractMetaFunctionList greater;
2432 2432 AbstractMetaFunctionList greaterEquals;
2433 2433 AbstractMetaFunctionList less;
2434 2434 AbstractMetaFunctionList lessEquals;
2435 2435
2436 2436 QString op_greater = QLatin1String("operator_greater");
2437 2437 QString op_greater_eq = QLatin1String("operator_greater_or_equal");
2438 2438 QString op_less = QLatin1String("operator_less");
2439 2439 QString op_less_eq = QLatin1String("operator_less_or_equal");
2440 2440
2441 2441 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
2442 2442 | AbstractMetaClass::NotRemovedFromTargetLang);
2443 2443 foreach (AbstractMetaFunction *f, functions) {
2444 2444 if (f->name() == op_greater)
2445 2445 greater << f;
2446 2446 else if (f->name() == op_greater_eq)
2447 2447 greaterEquals << f;
2448 2448 else if (f->name() == op_less)
2449 2449 less << f;
2450 2450 else if (f->name() == op_less_eq)
2451 2451 lessEquals << f;
2452 2452 }
2453 2453
2454 2454 bool hasEquals = cls->equalsFunctions().size() || cls->notEqualsFunctions().size();
2455 2455
2456 2456 // Conditions for comparable is:
2457 2457 // >, ==, < - The basic case
2458 2458 // >, == - Less than becomes else case
2459 2459 // <, == - Greater than becomes else case
2460 2460 // >=, <= - if (<= && >=) -> equal
2461 2461 bool mightBeComparable = greater.size() || greaterEquals.size() || less.size() || lessEquals.size()
2462 2462 || greaterEquals.size() == 1 || lessEquals.size() == 1;
2463 2463
2464 2464 if (mightBeComparable) {
2465 2465 QSet<QString> signatures;
2466 2466
2467 2467 // We only hide the original functions if we are able to make a compareTo() method
2468 2468 bool wasComparable = false;
2469 2469
2470 2470 // The three upper cases, prefer the <, == approach
2471 2471 if (hasEquals && (greater.size() || less.size())) {
2472 2472 cls->setLessThanFunctions(filter_functions(less, &signatures));
2473 2473 cls->setGreaterThanFunctions(filter_functions(greater, &signatures));
2474 2474 filter_functions(greaterEquals, &signatures);
2475 2475 filter_functions(lessEquals, &signatures);
2476 2476 wasComparable = true;
2477 2477 } else if (hasEquals && (greaterEquals.size() || lessEquals.size())) {
2478 2478 cls->setLessThanEqFunctions(filter_functions(lessEquals, &signatures));
2479 2479 cls->setGreaterThanEqFunctions(filter_functions(greaterEquals, &signatures));
2480 2480 wasComparable = true;
2481 2481 } else if (greaterEquals.size() == 1 || lessEquals.size() == 1) {
2482 2482 cls->setGreaterThanEqFunctions(greaterEquals);
2483 2483 cls->setLessThanEqFunctions(lessEquals);
2484 2484 filter_functions(less, &signatures);
2485 2485 filter_functions(greater, &signatures);
2486 2486 wasComparable = true;
2487 2487 }
2488 2488
2489 2489 if (wasComparable) {
2490 2490 hide_functions(greater);
2491 2491 hide_functions(greaterEquals);
2492 2492 hide_functions(less);
2493 2493 hide_functions(lessEquals);
2494 2494 }
2495 2495 }
2496 2496
2497 2497 }
2498 2498
2499 2499 void AbstractMetaBuilder::setupClonable(AbstractMetaClass *cls)
2500 2500 {
2501 2501 QString op_assign = QLatin1String("operator_assign");
2502 2502
2503 2503 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements);
2504 2504 foreach (AbstractMetaFunction *f, functions) {
2505 2505 if ((f->name() == op_assign || f->isConstructor()) && f->isPublic()) {
2506 2506 AbstractMetaArgumentList arguments = f->arguments();
2507 2507 if (arguments.size() == 1) {
2508 2508 if (cls->typeEntry()->qualifiedCppName() == arguments.at(0)->type()->typeEntry()->qualifiedCppName()) {
2509 2509 if (cls->typeEntry()->isValue()) {
2510 2510 cls->setHasCloneOperator(true);
2511 2511 return;
2512 2512 }
2513 2513 }
2514 2514 }
2515 2515 }
2516 2516 }
2517 2517 }
2518 2518
2519 2519 static void write_reject_log_file(const QString &name,
2520 2520 const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects)
2521 2521 {
2522 2522 QFile f(name);
2523 2523 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
2524 2524 ReportHandler::warning(QString("failed to write log file: '%1'")
2525 2525 .arg(f.fileName()));
2526 2526 return;
2527 2527 }
2528 2528
2529 2529 QTextStream s(&f);
2530 2530
2531 2531
2532 2532 for (int reason=0; reason<AbstractMetaBuilder::NoReason; ++reason) {
2533 2533 s << QString(72, '*') << endl;
2534 2534 switch (reason) {
2535 2535 case AbstractMetaBuilder::NotInTypeSystem:
2536 2536 s << "Not in type system";
2537 2537 break;
2538 2538 case AbstractMetaBuilder::GenerationDisabled:
2539 2539 s << "Generation disabled by type system";
2540 2540 break;
2541 2541 case AbstractMetaBuilder::RedefinedToNotClass:
2542 2542 s << "Type redefined to not be a class";
2543 2543 break;
2544 2544
2545 2545 case AbstractMetaBuilder::UnmatchedReturnType:
2546 2546 s << "Unmatched return type";
2547 2547 break;
2548 2548
2549 2549 case AbstractMetaBuilder::UnmatchedArgumentType:
2550 2550 s << "Unmatched argument type";
2551 2551 break;
2552 2552
2553 2553 default:
2554 2554 s << "unknown reason";
2555 2555 break;
2556 2556 }
2557 2557
2558 2558 s << endl;
2559 2559
2560 2560 for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin();
2561 2561 it != rejects.constEnd(); ++it) {
2562 2562 if (it.value() != reason)
2563 2563 continue;
2564 2564 s << " - " << it.key() << endl;
2565 2565 }
2566 2566
2567 2567 s << QString(72, '*') << endl << endl;
2568 2568 }
2569 2569
2570 2570 }
2571 2571
2572 2572
2573 2573 void AbstractMetaBuilder::dumpLog()
2574 2574 {
2575 2575 write_reject_log_file("mjb_rejected_classes.log", m_rejected_classes);
2576 2576 write_reject_log_file("mjb_rejected_enums.log", m_rejected_enums);
2577 2577 write_reject_log_file("mjb_rejected_functions.log", m_rejected_functions);
2578 2578 write_reject_log_file("mjb_rejected_fields.log", m_rejected_fields);
2579 2579 }
2580 2580
2581 2581 AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted() const
2582 2582 {
2583 2583 AbstractMetaClassList res;
2584 2584
2585 2585 AbstractMetaClassList classes = m_meta_classes;
2586 2586 qSort(classes);
2587 2587
2588 2588 QSet<AbstractMetaClass*> noDependency;
2589 2589 QHash<AbstractMetaClass*, QSet<AbstractMetaClass* >* > hash;
2590 2590 foreach (AbstractMetaClass *cls, classes) {
2591 2591 QSet<AbstractMetaClass* > *depends = new QSet<AbstractMetaClass* >();
2592 2592
2593 2593 if (cls->baseClass())
2594 2594 depends->insert(cls->baseClass());
2595 2595
2596 2596 foreach (AbstractMetaClass *interface, cls->interfaces()) {
2597 2597 AbstractMetaClass *impl = interface->primaryInterfaceImplementor();
2598 2598 if (impl == cls)
2599 2599 continue;
2600 2600 depends->insert(impl);
2601 2601 }
2602 2602
2603 2603 if (depends->empty()) {
2604 2604 noDependency.insert(cls);
2605 2605 } else {
2606 2606 hash.insert(cls, depends);
2607 2607 }
2608 2608 }
2609 2609
2610 2610 while (!noDependency.empty()) {
2611 2611 foreach (AbstractMetaClass *cls, noDependency.values()) {
2612 2612 if(!cls->isInterface())
2613 2613 res.append(cls);
2614 2614 noDependency.remove(cls);
2615 2615 QHashIterator<AbstractMetaClass*, QSet<AbstractMetaClass* >* > i(hash);
2616 2616 while (i.hasNext()) {
2617 2617 i.next();
2618 2618 i.value()->remove(cls);
2619 2619 if (i.value()->empty()) {
2620 2620 AbstractMetaClass *key = i.key();
2621 2621 noDependency.insert(key);
2622 2622 hash.remove(key);
2623 2623 delete(i.value());
2624 2624 }
2625 2625 }
2626 2626 }
2627 2627 }
2628 2628
2629 2629 if (!noDependency.empty() || !hash.empty()) {
2630 2630 qWarning("dependency graph was cyclic.");
2631 2631 }
2632 2632
2633 2633 return res;
2634 2634 }
@@ -1,1976 +1,1986
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #include "abstractmetalang.h"
43 43 #include "reporthandler.h"
44 44
45 45 /*******************************************************************************
46 46 * AbstractMetaType
47 47 */
48 48 AbstractMetaType *AbstractMetaType::copy() const
49 49 {
50 50 AbstractMetaType *cpy = new AbstractMetaType;
51 51
52 52 cpy->setTypeUsagePattern(typeUsagePattern());
53 53 cpy->setConstant(isConstant());
54 54 cpy->setReference(isReference());
55 55 cpy->setIndirections(indirections());
56 56 cpy->setInstantiations(instantiations());
57 57 cpy->setArrayElementCount(arrayElementCount());
58 58 cpy->setOriginalTypeDescription(originalTypeDescription());
59 59 cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0);
60 60
61 61 cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : 0);
62 62
63 63 cpy->setTypeEntry(typeEntry());
64 64
65 65 return cpy;
66 66 }
67 67
68 68 QString AbstractMetaType::cppSignature() const
69 69 {
70 70 QString s;
71 71
72 72 if (isConstant())
73 73 s += "const ";
74 74
75 75 s += typeEntry()->qualifiedCppName();
76 76
77 77 if (hasInstantiationInCpp()) {
78 78 QList<AbstractMetaType *> types = instantiations();
79 79 s += "<";
80 80 for (int i=0; i<types.count(); ++i) {
81 81 if (i > 0)
82 82 s += ", ";
83 83 s += types.at(i)->cppSignature();
84 84 }
85 85 s += " >";
86 86 }
87 87
88 88 if (actualIndirections()) {
89 89 s += ' ';
90 90 if (indirections())
91 91 s += QString(indirections(), '*');
92 92 if (isReference())
93 93 s += '&';
94 94 }
95 95 return s;
96 96 }
97 97
98 98 /*******************************************************************************
99 99 * AbstractMetaArgument
100 100 */
101 101 AbstractMetaArgument *AbstractMetaArgument::copy() const
102 102 {
103 103 AbstractMetaArgument *cpy = new AbstractMetaArgument;
104 104 cpy->setName(AbstractMetaVariable::name());
105 105 cpy->setDefaultValueExpression(defaultValueExpression());
106 106 cpy->setType(type()->copy());
107 107 cpy->setArgumentIndex(argumentIndex());
108 108
109 109 return cpy;
110 110 }
111 111
112 112
113 113 QString AbstractMetaArgument::argumentName() const
114 114 {
115 115 QString n = AbstractMetaVariable::name();
116 116 if (n.isEmpty()) {
117 117 return QString("arg__%2").arg(m_argument_index + 1);
118 118 }
119 119 return n;
120 120 }
121 121
122 122
123 123 QString AbstractMetaArgument::indexedName() const
124 124 {
125 125 QString n = AbstractMetaVariable::name();
126 126 if (n.isEmpty())
127 127 return argumentName();
128 128 return QString("%1%2").arg(n).arg(m_argument_index);
129 129 }
130 130
131 131 QString AbstractMetaArgument::name() const
132 132 {
133 133 Q_ASSERT_X(0, "AbstractMetaArgument::name()", "use argumentName() or indexedName() instead");
134 134 return QString();
135 135 }
136 136
137 137
138 138 /*******************************************************************************
139 139 * AbstractMetaFunction
140 140 */
141 141 AbstractMetaFunction::~AbstractMetaFunction()
142 142 {
143 143 qDeleteAll(m_arguments);
144 144 delete m_type;
145 145 }
146 146
147 147 /*******************************************************************************
148 148 * Indicates that this function has a modification that removes it
149 149 */
150 150 bool AbstractMetaFunction::isModifiedRemoved(int types) const
151 151 {
152 152 FunctionModificationList mods = modifications(implementingClass());
153 153 foreach (FunctionModification mod, mods) {
154 154 if (!mod.isRemoveModifier())
155 155 continue;
156 156
157 157 if ((mod.removal & types) == types)
158 158 return true;
159 159 }
160 160
161 161 return false;
162 162 }
163 163
164 164 bool AbstractMetaFunction::needsCallThrough() const
165 165 {
166 166 if (ownerClass()->isInterface())
167 167 return false;
168 168 if (referenceCounts(implementingClass()).size() > 0)
169 169 return true;
170 170 if (argumentsHaveNativeId() || !isStatic())
171 171 return true;
172 172
173 173 foreach (const AbstractMetaArgument *arg, arguments()) {
174 174 if (arg->type()->isArray() || arg->type()->isTargetLangEnum() || arg->type()->isTargetLangFlags())
175 175 return true;
176 176 }
177 177
178 178 if (type() && (type()->isArray() || type()->isTargetLangEnum() || type()->isTargetLangFlags()))
179 179 return true;
180 180
181 181 for (int i=-1; i<=arguments().size(); ++i) {
182 182 TypeSystem::Ownership owner = this->ownership(implementingClass(), TypeSystem::TargetLangCode, i);
183 183 if (owner != TypeSystem::InvalidOwnership)
184 184 return true;
185 185 }
186 186
187 187 return false;
188 188 }
189 189
190 190 bool AbstractMetaFunction::needsSuppressUncheckedWarning() const
191 191 {
192 192 for (int i=-1; i<=arguments().size(); ++i) {
193 193 QList<ReferenceCount> referenceCounts = this->referenceCounts(implementingClass(), i);
194 194 foreach (ReferenceCount referenceCount, referenceCounts) {
195 195 if (referenceCount.action != ReferenceCount::Set)
196 196 return true;
197 197 }
198 198 }
199 199 return false;
200 200 }
201 201
202 202 QString AbstractMetaFunction::marshalledName() const
203 203 {
204 204 QString returned = "__qt_" + name();
205 205 AbstractMetaArgumentList arguments = this->arguments();
206 206 foreach (const AbstractMetaArgument *arg, arguments) {
207 207 returned += "_";
208 208 if (arg->type()->isNativePointer()) {
209 209 returned += "nativepointer";
210 210 } else if (arg->type()->isIntegerEnum() || arg->type()->isIntegerFlags()) {
211 211 returned += "int";
212 212 } else {
213 213 returned += arg->type()->name().replace("[]", "_3").replace(".", "_");
214 214 }
215 215 }
216 216 return returned;
217 217 }
218 218
219 219 bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const
220 220 {
221 221 uint result = compareTo(&other);
222 222 return result & NameLessThan;
223 223 }
224 224
225 225
226 226 /*!
227 227 Returns a mask of CompareResult describing how this function is
228 228 compares to another function
229 229 */
230 230 uint AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const
231 231 {
232 232 uint result = 0;
233 233
234 234 // Enclosing class...
235 235 if (ownerClass() == other->ownerClass()) {
236 236 result |= EqualImplementor;
237 237 }
238 238
239 239 // Attributes
240 240 if (attributes() == other->attributes()) {
241 241 result |= EqualAttributes;
242 242 }
243 243
244 244 // Compare types
245 245 AbstractMetaType *t = type();
246 246 AbstractMetaType *ot = other->type();
247 247 if ((!t && !ot) || ((t && ot && t->name() == ot->name()))) {
248 248 result |= EqualReturnType;
249 249 }
250 250
251 251 // Compare names
252 252 int cmp = originalName().compare(other->originalName());
253 253
254 254 if (cmp < 0) {
255 255 result |= NameLessThan;
256 256 } else if (cmp == 0) {
257 257 result |= EqualName;
258 258 }
259 259
260 260 // compare name after modification...
261 261 cmp = modifiedName().compare(other->modifiedName());
262 262 if (cmp == 0)
263 263 result |= EqualModifiedName;
264 264
265 265 // Compare arguments...
266 266 AbstractMetaArgumentList min_arguments;
267 267 AbstractMetaArgumentList max_arguments;
268 268 if (arguments().size() < other->arguments().size()) {
269 269 min_arguments = arguments();
270 270 max_arguments = other->arguments();
271 271 } else {
272 272 min_arguments = other->arguments();
273 273 max_arguments = arguments();
274 274 }
275 275
276 276 int min_count = min_arguments.size();
277 277 int max_count = max_arguments.size();
278 278 bool same = true;
279 279 for (int i=0; i<max_count; ++i) {
280 280 if (i < min_count) {
281 281 const AbstractMetaArgument *min_arg = min_arguments.at(i);
282 282 const AbstractMetaArgument *max_arg = max_arguments.at(i);
283 283 if (min_arg->type()->name() != max_arg->type()->name()
284 284 && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) {
285 285 same = false;
286 286 break;
287 287 }
288 288 } else {
289 289 if (max_arguments.at(i)->defaultValueExpression().isEmpty()) {
290 290 same = false;
291 291 break;
292 292 }
293 293 }
294 294 }
295 295
296 296 if (same)
297 297 result |= min_count == max_count ? EqualArguments : EqualDefaultValueOverload;
298 298
299 299 return result;
300 300 }
301 301
302 302 AbstractMetaFunction *AbstractMetaFunction::copy() const
303 303 {
304 304 AbstractMetaFunction *cpy = new AbstractMetaFunction;
305 305 cpy->setName(name());
306 306 cpy->setOriginalName(originalName());
307 307 cpy->setOwnerClass(ownerClass());
308 308 cpy->setImplementingClass(implementingClass());
309 309 cpy->setInterfaceClass(interfaceClass());
310 310 cpy->setFunctionType(functionType());
311 311 cpy->setAttributes(attributes());
312 312 cpy->setDeclaringClass(declaringClass());
313 313 if (type())
314 314 cpy->setType(type()->copy());
315 315 cpy->setConstant(isConstant());
316 316 cpy->setOriginalAttributes(originalAttributes());
317 317
318 318 foreach (AbstractMetaArgument *arg, arguments())
319 319 cpy->addArgument(arg->copy());
320 320
321 321 Q_ASSERT((!type() && !cpy->type())
322 322 || (type()->instantiations() == cpy->type()->instantiations()));
323 323
324 324 return cpy;
325 325 }
326 326
327 327 QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const
328 328 {
329 329 AbstractMetaArgumentList arguments = this->arguments();
330 330 if (arguments.size() == resolvedArguments.size()) {
331 331 return (QStringList() << QMetaObject::normalizedSignature((name() + "(" + resolvedArguments.join(",") + ")").toUtf8().constData()));
332 332 } else {
333 333 QStringList returned;
334 334
335 335 AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
336 336 QStringList minimalTypeSignature = argument->type()->minimalSignature().split("::");
337 337 for (int i=0; i<minimalTypeSignature.size(); ++i) {
338 338 returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
339 339 << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join("::"));
340 340 }
341 341
342 342 return returned;
343 343 }
344 344 }
345 345
346 346 QString AbstractMetaFunction::signature() const
347 347 {
348 348 QString s(m_original_name);
349 349
350 350 s += "(";
351 351
352 352 for (int i=0; i<m_arguments.count(); ++i) {
353 353 if (i > 0)
354 354 s += ", ";
355 355 AbstractMetaArgument *a = m_arguments.at(i);
356 356 s += a->type()->cppSignature();
357 357
358 358 // We need to have the argument names in the qdoc files
359 359 s += " ";
360 360 s += a->argumentName();
361 361 }
362 362 s += ")";
363 363
364 364 if (isConstant())
365 365 s += " const";
366 366
367 367 return s;
368 368 }
369 369
370 370 int AbstractMetaFunction::actualMinimumArgumentCount() const
371 371 {
372 372 AbstractMetaArgumentList arguments = this->arguments();
373 373
374 374 int count = 0;
375 375 for (int i=0; i<arguments.size(); ++i && ++count) {
376 376 if (argumentRemoved(i + 1)) --count;
377 377 else if (!arguments.at(i)->defaultValueExpression().isEmpty()) break;
378 378 }
379 379
380 380 return count;
381 381 }
382 382
383 383 // Returns reference counts for argument at idx, or all arguments if idx == -2
384 384 QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const
385 385 {
386 386 QList<ReferenceCount> returned;
387 387
388 388 FunctionModificationList mods = this->modifications(cls);
389 389 foreach (FunctionModification mod, mods) {
390 390 QList<ArgumentModification> argument_mods = mod.argument_mods;
391 391 foreach (ArgumentModification argument_mod, argument_mods) {
392 392 if (argument_mod.index != idx && idx != -2)
393 393 continue;
394 394 returned += argument_mod.referenceCounts;
395 395 }
396 396 }
397 397
398 398 return returned;
399 399 }
400 400
401 401 QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const
402 402 {
403 403 FunctionModificationList modifications = this->modifications(cls);
404 404 foreach (FunctionModification modification, modifications) {
405 405 QList<ArgumentModification> argument_modifications = modification.argument_mods;
406 406 foreach (ArgumentModification argument_modification, argument_modifications) {
407 407 if (argument_modification.index == key
408 408 && !argument_modification.replaced_default_expression.isEmpty()) {
409 409 return argument_modification.replaced_default_expression;
410 410 }
411 411 }
412 412 }
413 413
414 414 return QString();
415 415 }
416 416
417 417 bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const
418 418 {
419 419 FunctionModificationList modifications = this->modifications(cls);
420 420 foreach (FunctionModification modification, modifications) {
421 421 QList<ArgumentModification> argument_modifications = modification.argument_mods;
422 422 foreach (ArgumentModification argument_modification, argument_modifications) {
423 423 if (argument_modification.index == key
424 424 && argument_modification.removed_default_expression) {
425 425 return true;
426 426 }
427 427 }
428 428 }
429 429
430 430 return false;
431 431 }
432 432
433 433 bool AbstractMetaFunction::resetObjectAfterUse(int argument_idx) const
434 434 {
435 435 const AbstractMetaClass *cls = declaringClass();
436 436 FunctionModificationList modifications = this->modifications(cls);
437 437 foreach (FunctionModification modification, modifications) {
438 438 QList<ArgumentModification> argumentModifications = modification.argument_mods;
439 439 foreach (ArgumentModification argumentModification, argumentModifications) {
440 440 if (argumentModification.index == argument_idx && argumentModification.reset_after_use)
441 441 return true;
442 442 }
443 443 }
444 444
445 445 return false;
446 446 }
447 447
448 448 QString AbstractMetaFunction::nullPointerDefaultValue(const AbstractMetaClass *mainClass, int argument_idx) const
449 449 {
450 450 Q_ASSERT(nullPointersDisabled(mainClass, argument_idx));
451 451
452 452 const AbstractMetaClass *cls = mainClass;
453 453 if (cls == 0)
454 454 cls = implementingClass();
455 455
456 456 do {
457 457 FunctionModificationList modifications = this->modifications(cls);
458 458 foreach (FunctionModification modification, modifications) {
459 459 QList<ArgumentModification> argument_modifications = modification.argument_mods;
460 460 foreach (ArgumentModification argument_modification, argument_modifications) {
461 461 if (argument_modification.index == argument_idx
462 462 && argument_modification.no_null_pointers) {
463 463 return argument_modification.null_pointer_default_value;
464 464 }
465 465 }
466 466 }
467 467
468 468 cls = cls->baseClass();
469 469 } while (cls != 0 && mainClass == 0); // Once when mainClass != 0, or once for all base classes of implementing class
470 470
471 471 return QString();
472 472
473 473 }
474 474
475 475 bool AbstractMetaFunction::nullPointersDisabled(const AbstractMetaClass *mainClass, int argument_idx) const
476 476 {
477 477 const AbstractMetaClass *cls = mainClass;
478 478 if (cls == 0)
479 479 cls = implementingClass();
480 480
481 481 do {
482 482 FunctionModificationList modifications = this->modifications(cls);
483 483 foreach (FunctionModification modification, modifications) {
484 484 QList<ArgumentModification> argument_modifications = modification.argument_mods;
485 485 foreach (ArgumentModification argument_modification, argument_modifications) {
486 486 if (argument_modification.index == argument_idx
487 487 && argument_modification.no_null_pointers) {
488 488 return true;
489 489 }
490 490 }
491 491 }
492 492
493 493 cls = cls->baseClass();
494 494 } while (cls != 0 && mainClass == 0); // Once when mainClass != 0, or once for all base classes of implementing class
495 495
496 496 return false;
497 497 }
498 498
499 499 QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
500 500 {
501 501 FunctionModificationList modifications = this->modifications(declaringClass());
502 502 foreach (FunctionModification modification, modifications) {
503 503 QList<ArgumentModification> argument_modifications = modification.argument_mods;
504 504 foreach (ArgumentModification argument_modification, argument_modifications) {
505 505 if (argument_modification.index != key)
506 506 continue;
507 507
508 508 foreach (CodeSnip snip, argument_modification.conversion_rules) {
509 509 if (snip.language == language && !snip.code().isEmpty())
510 510 return snip.code();
511 511 }
512 512 }
513 513 }
514 514
515 515 return QString();
516 516 }
517 517
518 518 QString AbstractMetaFunction::argumentReplaced(int key) const
519 519 {
520 520 FunctionModificationList modifications = this->modifications(declaringClass());
521 521 foreach (FunctionModification modification, modifications) {
522 522 QList<ArgumentModification> argument_modifications = modification.argument_mods;
523 523 foreach (ArgumentModification argument_modification, argument_modifications) {
524 524 if (argument_modification.index == key && !argument_modification.replace_value.isEmpty()) {
525 525 return argument_modification.replace_value;
526 526 }
527 527 }
528 528 }
529 529
530 530 return "";
531 531 }
532 532
533 533 bool AbstractMetaFunction::argumentRemoved(int key) const
534 534 {
535 535 FunctionModificationList modifications = this->modifications(declaringClass());
536 536 foreach (FunctionModification modification, modifications) {
537 537 QList<ArgumentModification> argument_modifications = modification.argument_mods;
538 538 foreach (ArgumentModification argument_modification, argument_modifications) {
539 539 if (argument_modification.index == key) {
540 540 if (argument_modification.removed) {
541 541 return true;
542 542 }
543 543 }
544 544 }
545 545 }
546 546
547 547 return false;
548 548 }
549 549
550 550 bool AbstractMetaFunction::isVirtualSlot() const
551 551 {
552 552 FunctionModificationList modifications = this->modifications(declaringClass());
553 553 foreach (FunctionModification modification, modifications) {
554 554 if (modification.isVirtualSlot())
555 555 return true;
556 556 }
557 557
558 558 return false;
559 559 }
560 560
561 561 bool AbstractMetaFunction::disabledGarbageCollection(const AbstractMetaClass *cls, int key) const
562 562 {
563 563 FunctionModificationList modifications = this->modifications(cls);
564 564 foreach (FunctionModification modification, modifications) {
565 565 QList<ArgumentModification> argument_modifications = modification.argument_mods;
566 566 foreach (ArgumentModification argument_modification, argument_modifications) {
567 567 if (argument_modification.index != key)
568 568 continue;
569 569
570 570 foreach (TypeSystem::Ownership ownership, argument_modification.ownerships.values()) {
571 571 if (ownership == TypeSystem::CppOwnership)
572 572 return true;
573 573 }
574 574
575 575 }
576 576 }
577 577
578 578 return false;
579 579 }
580 580
581 581 bool AbstractMetaFunction::isDeprecated() const
582 582 {
583 583 FunctionModificationList modifications = this->modifications(declaringClass());
584 584 foreach (FunctionModification modification, modifications) {
585 585 if (modification.isDeprecated())
586 586 return true;
587 587 }
588 588 return false;
589 589 }
590 590
591 591 TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
592 592 {
593 593 FunctionModificationList modifications = this->modifications(cls);
594 594 foreach (FunctionModification modification, modifications) {
595 595 QList<ArgumentModification> argument_modifications = modification.argument_mods;
596 596 foreach (ArgumentModification argument_modification, argument_modifications) {
597 597 if (argument_modification.index == key)
598 598 return argument_modification.ownerships.value(language, TypeSystem::InvalidOwnership);
599 599 }
600 600 }
601 601
602 602 return TypeSystem::InvalidOwnership;
603 603 }
604 604
605 605 bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const
606 606 {
607 607 return isRemovedFrom(cls, TypeSystem::All);
608 608 }
609 609
610 610 bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const
611 611 {
612 612 FunctionModificationList modifications = this->modifications(cls);
613 613 foreach (FunctionModification modification, modifications) {
614 614 if ((modification.removal & language) == language)
615 615 return true;
616 616 }
617 617
618 618 return false;
619 619
620 620 }
621 621
622 622 QString AbstractMetaFunction::typeReplaced(int key) const
623 623 {
624 624 FunctionModificationList modifications = this->modifications(declaringClass());
625 625 foreach (FunctionModification modification, modifications) {
626 626 QList<ArgumentModification> argument_modifications = modification.argument_mods;
627 627 foreach (ArgumentModification argument_modification, argument_modifications) {
628 628 if (argument_modification.index == key
629 629 && !argument_modification.modified_type.isEmpty()) {
630 630 return argument_modification.modified_type;
631 631 }
632 632 }
633 633 }
634 634
635 635 return QString();
636 636 }
637 637
638 638 QString AbstractMetaFunction::minimalSignature() const
639 639 {
640 640 if (!m_cached_minimal_signature.isEmpty())
641 641 return m_cached_minimal_signature;
642 642
643 643 QString minimalSignature = originalName() + "(";
644 644 AbstractMetaArgumentList arguments = this->arguments();
645 645
646 646 for (int i=0; i<arguments.count(); ++i) {
647 647 AbstractMetaType *t = arguments.at(i)->type();
648 648
649 649 if (i > 0)
650 650 minimalSignature += ",";
651 651
652 652 minimalSignature += t->minimalSignature();
653 653 }
654 654 minimalSignature += ")";
655 655 if (isConstant())
656 656 minimalSignature += "const";
657 657
658 658 minimalSignature = QMetaObject::normalizedSignature(minimalSignature.toLocal8Bit().constData());
659 659 m_cached_minimal_signature = minimalSignature;
660 660
661 661 return minimalSignature;
662 662 }
663 663
664 664 FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const
665 665 {
666 666 Q_ASSERT(implementor);
667 667 return implementor->typeEntry()->functionModifications(minimalSignature());
668 668 }
669 669
670 670 bool AbstractMetaFunction::hasModifications(const AbstractMetaClass *implementor) const
671 671 {
672 672 FunctionModificationList mods = modifications(implementor);
673 673 return mods.count() > 0;
674 674 }
675 675
676 676 QString AbstractMetaFunction::modifiedName() const
677 677 {
678 678 if (m_cached_modified_name.isEmpty()) {
679 679 FunctionModificationList mods = modifications(implementingClass());
680 680 foreach (FunctionModification mod, mods) {
681 681 if (mod.isRenameModifier()) {
682 682 m_cached_modified_name = mod.renamedToName;
683 683 break;
684 684 }
685 685 }
686 686 if (m_cached_modified_name.isEmpty())
687 687 m_cached_modified_name = name();
688 688 }
689 689 return m_cached_modified_name;
690 690 }
691 691
692 692 QString AbstractMetaFunction::targetLangSignature(bool minimal) const
693 693 {
694 694 QString s;
695 695
696 696 // Attributes...
697 697 if (!minimal) {
698 698 #if 0 // jambi
699 699 if (isPublic()) s += "public ";
700 700 else if (isProtected()) s += "protected ";
701 701 else if (isPrivate()) s += "private ";
702 702
703 703 // if (isNative()) s += "native ";
704 704 // else
705 705 if (isFinalInTargetLang()) s += "final ";
706 706 else if (isAbstract()) s += "abstract ";
707 707
708 708 if (isStatic()) s += "static ";
709 709 #endif
710 710 // Return type
711 711 if (type())
712 712 s += type()->name() + " ";
713 713 else
714 714 s += "void ";
715 715 }
716 716
717 717 s += modifiedName();
718 718 s += "(";
719 719
720 720 int j = 0;
721 721 for (int i=0; i<m_arguments.size(); ++i) {
722 722 if (argumentRemoved(i+1))
723 723 continue;
724 724 if (j != 0) {
725 725 s += ",";
726 726 if (!minimal)
727 727 s += QLatin1Char(' ');
728 728 }
729 729 s += m_arguments.at(i)->type()->name();
730 730
731 731 if (!minimal) {
732 732 s += " ";
733 733 s += m_arguments.at(i)->argumentName();
734 734 }
735 735 ++j;
736 736 }
737 737
738 738 s += ")";
739 739
740 740 return s;
741 741 }
742 742
743 743
744 744 bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
745 745 {
746 746 return a->signature() < b->signature();
747 747 }
748 748
749 749 /*******************************************************************************
750 750 * AbstractMetaClass
751 751 */
752 752 AbstractMetaClass::~AbstractMetaClass()
753 753 {
754 754 qDeleteAll(m_functions);
755 755 qDeleteAll(m_fields);
756 756 }
757 757
758 758 /*AbstractMetaClass *AbstractMetaClass::copy() const
759 759 {
760 760 AbstractMetaClass *cls = new AbstractMetaClass;
761 761 cls->setAttributes(attributes());
762 762 cls->setBaseClass(baseClass());
763 763 cls->setTypeEntry(typeEntry());
764 764 foreach (AbstractMetaFunction *function, functions()) {
765 765 AbstractMetaFunction *copy = function->copy();
766 766 function->setImplementingClass(cls);
767 767 cls->addFunction(copy);
768 768 }
769 769 cls->setEnums(enums());
770 770 foreach (const AbstractMetaField *field, fields()) {
771 771 AbstractMetaField *copy = field->copy();
772 772 copy->setEnclosingClass(cls);
773 773 cls->addField(copy);
774 774 }
775 775 cls->setInterfaces(interfaces());
776 776
777 777 return cls;
778 778 }*/
779 779
780 780 /*******************************************************************************
781 781 * Returns true if this class is a subclass of the given class
782 782 */
783 783 bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const
784 784 {
785 785 Q_ASSERT(cls != 0);
786 786
787 787 const AbstractMetaClass *clazz = this;
788 788 while (clazz != 0) {
789 789 if (clazz == cls)
790 790 return true;
791 791
792 792 clazz = clazz->baseClass();
793 793 }
794 794
795 795 return false;
796 796 }
797 797
798 798 /*******************************************************************************
799 799 * Constructs an interface based on the functions and enums in this
800 800 * class and returns it...
801 801 */
802 802 AbstractMetaClass *AbstractMetaClass::extractInterface()
803 803 {
804 804 Q_ASSERT(typeEntry()->designatedInterface());
805 805
806 806 if (m_extracted_interface == 0) {
807 807 AbstractMetaClass *iface = new AbstractMetaClass;
808 808 iface->setAttributes(attributes());
809 809 iface->setBaseClass(0);
810 810 iface->setPrimaryInterfaceImplementor(this);
811 811
812 812 iface->setTypeEntry(typeEntry()->designatedInterface());
813 813
814 814 foreach (AbstractMetaFunction *function, functions()) {
815 815 if (!function->isConstructor())
816 816 iface->addFunction(function->copy());
817 817 }
818 818
819 819 // iface->setEnums(enums());
820 820 // setEnums(AbstractMetaEnumList());
821 821
822 822 foreach (const AbstractMetaField *field, fields()) {
823 823 if (field->isPublic()) {
824 824 AbstractMetaField *new_field = field->copy();
825 825 new_field->setEnclosingClass(iface);
826 826 iface->addField(new_field);
827 827 }
828 828 }
829 829
830 830 m_extracted_interface = iface;
831 831 addInterface(iface);
832 832 }
833 833
834 834 return m_extracted_interface;
835 835 }
836 836
837 837 /*******************************************************************************
838 838 * Returns a list of all the functions with a given name
839 839 */
840 840 AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const
841 841 {
842 842 AbstractMetaFunctionList returned;
843 843 AbstractMetaFunctionList functions = this->functions();
844 844 foreach (AbstractMetaFunction *function, functions) {
845 845 if (function->name() == name)
846 846 returned.append(function);
847 847 }
848 848
849 849 return returned;
850 850 }
851 851
852 bool AbstractMetaClass::hasDefaultIsNull() const
853 {
854 foreach(const AbstractMetaFunction* fun, queryFunctionsByName("isNull")) {
855 if (fun->actualMinimumArgumentCount()==0) {
856 return true;
857 }
858 }
859 return false;
860 }
861
852 862 /*******************************************************************************
853 863 * Returns all reference count modifications for any function in the class
854 864 */
855 865 QList<ReferenceCount> AbstractMetaClass::referenceCounts() const
856 866 {
857 867 QList<ReferenceCount> returned;
858 868
859 869 AbstractMetaFunctionList functions = this->functions();
860 870 foreach (AbstractMetaFunction *function, functions) {
861 871 returned += function->referenceCounts(this);
862 872 }
863 873
864 874 return returned;
865 875 }
866 876
867 877 /*******************************************************************************
868 878 * Returns a list of all the functions retrieved during parsing which should
869 879 * be added to the Java API.
870 880 */
871 881 AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const
872 882 {
873 883 int default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang;
874 884
875 885 // Interfaces don't implement functions
876 886 default_flags |= isInterface() ? 0 : ClassImplements;
877 887
878 888 // Only public functions in final classes
879 889 // default_flags |= isFinal() ? WasPublic : 0;
880 890 int public_flags = isFinal() ? WasPublic : 0;
881 891
882 892 // Constructors
883 893 AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags);
884 894
885 895 // Final functions
886 896 returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
887 897
888 898 // Virtual functions
889 899 returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
890 900
891 901 // Static functions
892 902 returned += queryFunctions(StaticFunctions | default_flags | public_flags);
893 903
894 904 // Empty, private functions, since they aren't caught by the other ones
895 905 returned += queryFunctions(Empty | Invisible);
896 906
897 907 return returned;
898 908 }
899 909
900 910 AbstractMetaFunctionList AbstractMetaClass::virtualFunctions() const
901 911 {
902 912 AbstractMetaFunctionList list = functionsInShellClass();
903 913
904 914 AbstractMetaFunctionList returned;
905 915 foreach (AbstractMetaFunction *f, list) {
906 916 if (!f->isFinalInCpp() || f->isVirtualSlot())
907 917 returned += f;
908 918 }
909 919
910 920 return returned;
911 921 }
912 922
913 923 AbstractMetaFunctionList AbstractMetaClass::nonVirtualShellFunctions() const
914 924 {
915 925 AbstractMetaFunctionList list = functionsInShellClass();
916 926 AbstractMetaFunctionList returned;
917 927 foreach (AbstractMetaFunction *f, list) {
918 928 if (f->isFinalInCpp() && !f->isVirtualSlot())
919 929 returned += f;
920 930 }
921 931
922 932 return returned;
923 933 }
924 934
925 935 /*******************************************************************************
926 936 * Returns a list of all functions that should be declared and implemented in
927 937 * the shell class which is generated as a wrapper on top of the actual C++ class
928 938 */
929 939 AbstractMetaFunctionList AbstractMetaClass::functionsInShellClass() const
930 940 {
931 941 // Only functions and only protected and public functions
932 942 int default_flags = NormalFunctions | Visible | WasVisible | NotRemovedFromShell;
933 943
934 944 // All virtual functions
935 945 AbstractMetaFunctionList returned = queryFunctions(VirtualFunctions | default_flags);
936 946
937 947 // All functions explicitly set to be implemented by the shell class
938 948 // (mainly superclass functions that are hidden by other declarations)
939 949 returned += queryFunctions(ForcedShellFunctions | default_flags);
940 950
941 951 // All functions explicitly set to be virtual slots
942 952 returned += queryFunctions(VirtualSlots | default_flags);
943 953
944 954 return returned;
945 955 }
946 956
947 957 /*******************************************************************************
948 958 * Returns a list of all functions that require a public override function to
949 959 * be generated in the shell class. This includes all functions that were originally
950 960 * protected in the superclass.
951 961 */
952 962 AbstractMetaFunctionList AbstractMetaClass::publicOverrideFunctions() const
953 963 {
954 964 return queryFunctions(NormalFunctions | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang)
955 965 + queryFunctions(Signals | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang);
956 966 }
957 967
958 968 AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const
959 969 {
960 970 return queryFunctions(NormalFunctions | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell) +
961 971 queryFunctions(Signals | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell);
962 972 }
963 973
964 974 void AbstractMetaClass::sortFunctions()
965 975 {
966 976 qSort(m_functions.begin(), m_functions.end(), function_sorter);
967 977 }
968 978
969 979 void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
970 980 {
971 981 m_functions = functions;
972 982
973 983 // Functions must be sorted by name before next loop
974 984 sortFunctions();
975 985
976 986 QString currentName;
977 987 bool hasVirtuals = false;
978 988 AbstractMetaFunctionList final_functions;
979 989 foreach (AbstractMetaFunction *f, m_functions) {
980 990 f->setOwnerClass(this);
981 991
982 992 m_has_virtual_slots |= f->isVirtualSlot();
983 993 m_has_virtuals |= !f->isFinal() || f->isVirtualSlot();
984 994 m_has_nonpublic |= !f->isPublic();
985 995
986 996 // If we have non-virtual overloads of a virtual function, we have to implement
987 997 // all the overloads in the shell class to override the hiding rule
988 998 if (currentName == f->name()) {
989 999 hasVirtuals = hasVirtuals || !f->isFinal();
990 1000 if (f->isFinal())
991 1001 final_functions += f;
992 1002 } else {
993 1003 if (hasVirtuals && final_functions.size() > 0) {
994 1004 foreach (AbstractMetaFunction *final_function, final_functions) {
995 1005 *final_function += AbstractMetaAttributes::ForceShellImplementation;
996 1006
997 1007 QString warn = QString("hiding of function '%1' in class '%2'")
998 1008 .arg(final_function->name()).arg(name());
999 1009 ReportHandler::warning(warn);
1000 1010 }
1001 1011 }
1002 1012
1003 1013 hasVirtuals = !f->isFinal();
1004 1014 final_functions.clear();
1005 1015 if (f->isFinal())
1006 1016 final_functions += f;
1007 1017 currentName = f->name();
1008 1018 }
1009 1019 }
1010 1020
1011 1021 #ifndef QT_NO_DEBUG
1012 1022 bool duplicate_function = false;
1013 1023 for (int j=0; j<m_functions.size(); ++j) {
1014 1024 FunctionModificationList mods = m_functions.at(j)->modifications(m_functions.at(j)->implementingClass());
1015 1025
1016 1026 bool removed = false;
1017 1027 foreach (const FunctionModification &mod, mods) {
1018 1028 if (mod.isRemoveModifier()) {
1019 1029 removed = true;
1020 1030 break ;
1021 1031 }
1022 1032 }
1023 1033 if (removed)
1024 1034 continue ;
1025 1035
1026 1036 for (int i=0; i<m_functions.size() - 1; ++i) {
1027 1037 if (j == i)
1028 1038 continue;
1029 1039
1030 1040 mods = m_functions.at(i)->modifications(m_functions.at(i)->implementingClass());
1031 1041 bool removed = false;
1032 1042 foreach (const FunctionModification &mod, mods) {
1033 1043 if (mod.isRemoveModifier()) {
1034 1044 removed = true;
1035 1045 break ;
1036 1046 }
1037 1047 }
1038 1048 if (removed)
1039 1049 continue ;
1040 1050
1041 1051 uint cmp = m_functions.at(i)->compareTo(m_functions.at(j));
1042 1052 if ((cmp & AbstractMetaFunction::EqualName) && (cmp & AbstractMetaFunction::EqualArguments)) {
1043 1053 printf("%s.%s mostly equal to %s.%s\n",
1044 1054 qPrintable(m_functions.at(i)->implementingClass()->typeEntry()->qualifiedCppName()),
1045 1055 qPrintable(m_functions.at(i)->signature()),
1046 1056 qPrintable(m_functions.at(j)->implementingClass()->typeEntry()->qualifiedCppName()),
1047 1057 qPrintable(m_functions.at(j)->signature()));
1048 1058 duplicate_function = true;
1049 1059 }
1050 1060 }
1051 1061 }
1052 1062 //Q_ASSERT(!duplicate_function);
1053 1063 #endif
1054 1064 }
1055 1065
1056 1066 bool AbstractMetaClass::hasFieldAccessors() const
1057 1067 {
1058 1068 foreach (const AbstractMetaField *field, fields()) {
1059 1069 if (field->getter() || field->setter())
1060 1070 return true;
1061 1071 }
1062 1072
1063 1073 return false;
1064 1074 }
1065 1075
1066 1076 bool AbstractMetaClass::hasDefaultToStringFunction() const
1067 1077 {
1068 1078 foreach (AbstractMetaFunction *f, queryFunctionsByName("toString")) {
1069 1079 if (f->actualMinimumArgumentCount() == 0) {
1070 1080 return true;
1071 1081 }
1072 1082
1073 1083 }
1074 1084 return false;
1075 1085 }
1076 1086
1077 1087 void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
1078 1088 {
1079 1089 function->setOwnerClass(this);
1080 1090
1081 1091 if (!function->isDestructor()) {
1082 1092 m_functions << function;
1083 1093 qSort(m_functions.begin(), m_functions.end(), function_sorter);
1084 1094 }
1085 1095
1086 1096
1087 1097 m_has_virtual_slots |= function->isVirtualSlot();
1088 1098 m_has_virtuals |= !function->isFinal() || function->isVirtualSlot();
1089 1099 m_has_nonpublic |= !function->isPublic();
1090 1100 }
1091 1101
1092 1102 bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
1093 1103 {
1094 1104 if (!other->isSignal())
1095 1105 return false;
1096 1106
1097 1107 foreach (const AbstractMetaFunction *f, functions()) {
1098 1108 if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName)
1099 1109 return other->modifiedName() == f->modifiedName();
1100 1110 }
1101 1111
1102 1112 return false;
1103 1113 }
1104 1114
1105 1115
1106 1116 QString AbstractMetaClass::name() const
1107 1117 {
1108 1118 return QString(m_type_entry->targetLangName()).replace("::", "_");
1109 1119 }
1110 1120
1111 1121 bool AbstractMetaClass::hasFunction(const QString &str) const
1112 1122 {
1113 1123 foreach (const AbstractMetaFunction *f, functions())
1114 1124 if (f->name() == str)
1115 1125 return true;
1116 1126 return false;
1117 1127 }
1118 1128
1119 1129 /* Returns true if this class has one or more functions that are
1120 1130 protected. If a class has protected members we need to generate a
1121 1131 shell class with public accessors to the protected functions, so
1122 1132 they can be called from the native functions.
1123 1133 */
1124 1134 bool AbstractMetaClass::hasProtectedFunctions() const {
1125 1135 foreach (AbstractMetaFunction *func, m_functions) {
1126 1136 if (func->isProtected())
1127 1137 return true;
1128 1138 }
1129 1139 return false;
1130 1140 }
1131 1141
1132 1142 bool AbstractMetaClass::generateShellClass() const
1133 1143 {
1134 1144 return m_force_shell_class ||
1135 1145 (!isFinal()
1136 1146 && (hasVirtualFunctions()
1137 1147 || hasProtectedFunctions()
1138 1148 || hasFieldAccessors()));
1139 1149 }
1140 1150
1141 1151 QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const
1142 1152 {
1143 1153 for (int i=0; i<m_property_specs.size(); ++i)
1144 1154 if (name == m_property_specs.at(i)->read())
1145 1155 return m_property_specs.at(i);
1146 1156 return 0;
1147 1157 }
1148 1158
1149 1159 QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const
1150 1160 {
1151 1161 for (int i=0; i<m_property_specs.size(); ++i)
1152 1162 if (name == m_property_specs.at(i)->write())
1153 1163 return m_property_specs.at(i);
1154 1164 return 0;
1155 1165 }
1156 1166
1157 1167 QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const
1158 1168 {
1159 1169 for (int i=0; i<m_property_specs.size(); ++i) {
1160 1170 if (name == m_property_specs.at(i)->reset())
1161 1171 return m_property_specs.at(i);
1162 1172 }
1163 1173 return 0;
1164 1174 }
1165 1175
1166 1176
1167 1177
1168 1178 static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
1169 1179 {
1170 1180 foreach (const AbstractMetaFunction *f, l) {
1171 1181 if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar)
1172 1182 return true;
1173 1183 }
1174 1184 return false;
1175 1185 }
1176 1186
1177 1187 AbstractMetaField::AbstractMetaField() : m_getter(0), m_setter(0), m_class(0)
1178 1188 {
1179 1189 }
1180 1190
1181 1191 AbstractMetaField::~AbstractMetaField()
1182 1192 {
1183 1193 delete m_setter;
1184 1194 delete m_getter;
1185 1195 }
1186 1196 ushort painters; // refcount
1187 1197 AbstractMetaField *AbstractMetaField::copy() const
1188 1198 {
1189 1199 AbstractMetaField *returned = new AbstractMetaField;
1190 1200 returned->setEnclosingClass(0);
1191 1201 returned->setAttributes(attributes());
1192 1202 returned->setName(name());
1193 1203 returned->setType(type()->copy());
1194 1204 returned->setOriginalAttributes(originalAttributes());
1195 1205
1196 1206 return returned;
1197 1207 }
1198 1208
1199 1209 static QString upCaseFirst(const QString &str) {
1200 1210 Q_ASSERT(!str.isEmpty());
1201 1211 QString s = str;
1202 1212 s[0] = s.at(0).toUpper();
1203 1213 return s;
1204 1214 }
1205 1215
1206 1216 static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name, uint type) {
1207 1217 AbstractMetaFunction *f = new AbstractMetaFunction;
1208 1218
1209 1219
1210 1220
1211 1221 f->setName(name);
1212 1222 f->setOriginalName(name);
1213 1223 f->setOwnerClass(g->enclosingClass());
1214 1224 f->setImplementingClass(g->enclosingClass());
1215 1225 f->setDeclaringClass(g->enclosingClass());
1216 1226
1217 1227 uint attr = AbstractMetaAttributes::Native
1218 1228 | AbstractMetaAttributes::Final
1219 1229 | type;
1220 1230 if (g->isStatic())
1221 1231 attr |= AbstractMetaAttributes::Static;
1222 1232 if (g->isPublic())
1223 1233 attr |= AbstractMetaAttributes::Public;
1224 1234 else if (g->isProtected())
1225 1235 attr |= AbstractMetaAttributes::Protected;
1226 1236 else
1227 1237 attr |= AbstractMetaAttributes::Private;
1228 1238 f->setAttributes(attr);
1229 1239 f->setOriginalAttributes(attr);
1230 1240
1231 1241 FieldModificationList mods = g->modifications();
1232 1242 foreach (FieldModification mod, mods) {
1233 1243 if (mod.isRenameModifier())
1234 1244 f->setName(mod.renamedTo());
1235 1245 if (mod.isAccessModifier()) {
1236 1246 if (mod.isPrivate())
1237 1247 f->setVisibility(AbstractMetaAttributes::Private);
1238 1248 else if (mod.isProtected())
1239 1249 f->setVisibility(AbstractMetaAttributes::Protected);
1240 1250 else if (mod.isPublic())
1241 1251 f->setVisibility(AbstractMetaAttributes::Public);
1242 1252 else if (mod.isFriendly())
1243 1253 f->setVisibility(AbstractMetaAttributes::Friendly);
1244 1254 }
1245 1255
1246 1256 }
1247 1257 return f;
1248 1258 }
1249 1259
1250 1260 FieldModificationList AbstractMetaField::modifications() const
1251 1261 {
1252 1262 FieldModificationList mods = enclosingClass()->typeEntry()->fieldModifications();
1253 1263 FieldModificationList returned;
1254 1264
1255 1265 foreach (FieldModification mod, mods) {
1256 1266 if (mod.name == name())
1257 1267 returned += mod;
1258 1268 }
1259 1269
1260 1270 return returned;
1261 1271 }
1262 1272
1263 1273 const AbstractMetaFunction *AbstractMetaField::setter() const
1264 1274 {
1265 1275 if (m_setter == 0) {
1266 1276 m_setter = createXetter(this,
1267 1277 name(),
1268 1278 AbstractMetaAttributes::SetterFunction);
1269 1279 AbstractMetaArgumentList arguments;
1270 1280 AbstractMetaArgument *argument = new AbstractMetaArgument;
1271 1281 argument->setType(type()->copy());
1272 1282 argument->setName(name());
1273 1283 arguments.append(argument);
1274 1284 m_setter->setArguments(arguments);
1275 1285 }
1276 1286 return m_setter;
1277 1287 }
1278 1288
1279 1289 const AbstractMetaFunction *AbstractMetaField::getter() const
1280 1290 {
1281 1291 if (m_getter == 0) {
1282 1292 m_getter = createXetter(this,
1283 1293 name(),
1284 1294 AbstractMetaAttributes::GetterFunction);
1285 1295 m_getter->setType(type());
1286 1296 }
1287 1297
1288 1298 return m_getter;
1289 1299 }
1290 1300
1291 1301
1292 1302 bool AbstractMetaClass::hasConstructors() const
1293 1303 {
1294 1304 return queryFunctions(Constructors).size() != 0;
1295 1305 }
1296 1306
1297 1307 void AbstractMetaClass::addDefaultConstructor()
1298 1308 {
1299 1309 AbstractMetaFunction *f = new AbstractMetaFunction;
1300 1310 f->setName(name());
1301 1311 f->setOwnerClass(this);
1302 1312 f->setFunctionType(AbstractMetaFunction::ConstructorFunction);
1303 1313 f->setArguments(AbstractMetaArgumentList());
1304 1314 f->setDeclaringClass(this);
1305 1315
1306 1316 uint attr = AbstractMetaAttributes::Native;
1307 1317 attr |= AbstractMetaAttributes::Public;
1308 1318 f->setAttributes(attr);
1309 1319 f->setImplementingClass(this);
1310 1320 f->setOriginalAttributes(f->attributes());
1311 1321
1312 1322 addFunction(f);
1313 1323 }
1314 1324
1315 1325 bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
1316 1326 {
1317 1327 return functions_contains(m_functions, f);
1318 1328 }
1319 1329
1320 1330 /* Goes through the list of functions and returns a list of all
1321 1331 functions matching all of the criteria in \a query.
1322 1332 */
1323 1333
1324 1334 AbstractMetaFunctionList AbstractMetaClass::queryFunctions(uint query) const
1325 1335 {
1326 1336 AbstractMetaFunctionList functions;
1327 1337
1328 1338 foreach (AbstractMetaFunction *f, m_functions) {
1329 1339
1330 1340 if ((query & VirtualSlots) && !f->isVirtualSlot())
1331 1341 continue;
1332 1342
1333 1343 if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) {
1334 1344 continue;
1335 1345 }
1336 1346
1337 1347 if ((query & NotRemovedFromTargetLang) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) {
1338 1348 continue;
1339 1349 }
1340 1350
1341 1351 if ((query & NotRemovedFromShell) && f->isRemovedFrom(f->implementingClass(), TypeSystem::ShellCode)) {
1342 1352 continue;
1343 1353 }
1344 1354
1345 1355 if ((query & NotRemovedFromShell) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::ShellCode)) {
1346 1356 continue;
1347 1357 }
1348 1358
1349 1359 if ((query & Visible) && f->isPrivate()) {
1350 1360 continue;
1351 1361 }
1352 1362
1353 1363 if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang()) {
1354 1364 continue;
1355 1365 }
1356 1366
1357 1367 if ((query & Invisible) && !f->isPrivate()) {
1358 1368 continue;
1359 1369 }
1360 1370
1361 1371 if ((query & Empty) && !f->isEmptyFunction()) {
1362 1372 continue;
1363 1373 }
1364 1374
1365 1375 if ((query & WasPublic) && !f->wasPublic()) {
1366 1376 continue;
1367 1377 }
1368 1378
1369 1379 if ((query & WasVisible) && f->wasPrivate()) {
1370 1380 continue;
1371 1381 }
1372 1382
1373 1383 if ((query & WasProtected) && !f->wasProtected()) {
1374 1384 continue;
1375 1385 }
1376 1386
1377 1387 if ((query & ClassImplements) && f->ownerClass() != f->implementingClass()) {
1378 1388 continue;
1379 1389 }
1380 1390
1381 1391 if ((query & Inconsistent) && (f->isFinalInTargetLang() || !f->isFinalInCpp() || f->isStatic())) {
1382 1392 continue;
1383 1393 }
1384 1394
1385 1395 if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang()) {
1386 1396 continue;
1387 1397 }
1388 1398
1389 1399 if ((query & FinalInCppFunctions) && !f->isFinalInCpp()) {
1390 1400 continue;
1391 1401 }
1392 1402
1393 1403 if ((query & VirtualInCppFunctions) && f->isFinalInCpp()) {
1394 1404 continue;
1395 1405 }
1396 1406
1397 1407 if ((query & Signals) && (!f->isSignal())) {
1398 1408 continue;
1399 1409 }
1400 1410
1401 1411 if ((query & ForcedShellFunctions)
1402 1412 && (!f->isForcedShellImplementation()
1403 1413 || !f->isFinal())) {
1404 1414 continue;
1405 1415 }
1406 1416
1407 1417 if (((query & Constructors) && (!f->isConstructor()
1408 1418 || f->ownerClass() != f->implementingClass()))
1409 1419 || (f->isConstructor() && (query & Constructors) == 0)) {
1410 1420 continue;
1411 1421 }
1412 1422
1413 1423 // Destructors are never included in the functions of a class currently
1414 1424 /*
1415 1425 if ((query & Destructors) && (!f->isDestructor()
1416 1426 || f->ownerClass() != f->implementingClass())
1417 1427 || f->isDestructor() && (query & Destructors) == 0) {
1418 1428 continue;
1419 1429 }*/
1420 1430
1421 1431 if ((query & VirtualFunctions) && (f->isFinal() || f->isSignal() || f->isStatic())) {
1422 1432 continue;
1423 1433 }
1424 1434
1425 1435 if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal())) {
1426 1436 continue;
1427 1437 }
1428 1438
1429 1439 if ((query & NonStaticFunctions) && (f->isStatic())) {
1430 1440 continue;
1431 1441 }
1432 1442
1433 1443 if ((query & NonEmptyFunctions) && (f->isEmptyFunction())) {
1434 1444 continue;
1435 1445 }
1436 1446
1437 1447 if ((query & NormalFunctions) && (f->isSignal())) {
1438 1448 continue;
1439 1449 }
1440 1450
1441 1451 if ((query & AbstractFunctions) && !f->isAbstract()) {
1442 1452 continue;
1443 1453 }
1444 1454
1445 1455 functions << f;
1446 1456 }
1447 1457
1448 1458 // qDebug() << "queried" << m_type_entry->qualifiedCppName() << "got" << functions.size() << "out of" << m_functions.size();
1449 1459
1450 1460 return functions;
1451 1461 }
1452 1462
1453 1463
1454 1464 bool AbstractMetaClass::hasInconsistentFunctions() const
1455 1465 {
1456 1466 return cppInconsistentFunctions().size() > 0;
1457 1467 }
1458 1468
1459 1469 bool AbstractMetaClass::hasSignals() const
1460 1470 {
1461 1471 return cppSignalFunctions().size() > 0;
1462 1472 }
1463 1473
1464 1474
1465 1475 /**
1466 1476 * Adds the specified interface to this class by adding all the
1467 1477 * functions in the interface to this class.
1468 1478 */
1469 1479 void AbstractMetaClass::addInterface(AbstractMetaClass *interface)
1470 1480 {
1471 1481 Q_ASSERT(!m_interfaces.contains(interface));
1472 1482 m_interfaces << interface;
1473 1483
1474 1484 if (m_extracted_interface != 0 && m_extracted_interface != interface)
1475 1485 m_extracted_interface->addInterface(interface);
1476 1486
1477 1487 foreach (AbstractMetaFunction *function, interface->functions())
1478 1488 if (!hasFunction(function) && !function->isConstructor()) {
1479 1489 AbstractMetaFunction *cpy = function->copy();
1480 1490 // We do not want this in PythonQt:
1481 1491 //cpy->setImplementingClass(this);
1482 1492
1483 1493 // Setup that this function is an interface class.
1484 1494 cpy->setInterfaceClass(interface);
1485 1495 *cpy += AbstractMetaAttributes::InterfaceFunction;
1486 1496
1487 1497 // Copy the modifications in interface into the implementing classes.
1488 1498 FunctionModificationList mods = function->modifications(interface);
1489 1499 foreach (const FunctionModification &mod, mods) {
1490 1500 m_type_entry->addFunctionModification(mod);
1491 1501 }
1492 1502
1493 1503 // It should be mostly safe to assume that when we implement an interface
1494 1504 // we don't "pass on" pure virtual functions to our sublcasses...
1495 1505 // *cpy -= AbstractMetaAttributes::Abstract;
1496 1506
1497 1507 addFunction(cpy);
1498 1508 }
1499 1509 }
1500 1510
1501 1511
1502 1512 void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces)
1503 1513 {
1504 1514 m_interfaces = interfaces;
1505 1515 }
1506 1516
1507 1517
1508 1518 AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
1509 1519 {
1510 1520 foreach (AbstractMetaEnum *e, m_enums) {
1511 1521 if (e->name() == enumName)
1512 1522 return e;
1513 1523 }
1514 1524
1515 1525 if (typeEntry()->designatedInterface())
1516 1526 return extractInterface()->findEnum(enumName);
1517 1527
1518 1528 return 0;
1519 1529 }
1520 1530
1521 1531
1522 1532
1523 1533
1524 1534 /*! Recursivly searches for the enum value named \a enumValueName in
1525 1535 this class and its superclasses and interfaces. Values belonging to
1526 1536 \a meta_enum are excluded from the search.
1527 1537 */
1528 1538 AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName, AbstractMetaEnum *meta_enum)
1529 1539 {
1530 1540 foreach (AbstractMetaEnum *e, m_enums) {
1531 1541 if (e == meta_enum)
1532 1542 continue;
1533 1543 foreach (AbstractMetaEnumValue *v, e->values()) {
1534 1544 if (v->name() == enumValueName)
1535 1545 return v;
1536 1546 }
1537 1547 }
1538 1548
1539 1549 if (typeEntry()->designatedInterface())
1540 1550 return extractInterface()->findEnumValue(enumValueName, meta_enum);
1541 1551
1542 1552 if (baseClass() != 0)
1543 1553 return baseClass()->findEnumValue(enumValueName, meta_enum);
1544 1554
1545 1555 return 0;
1546 1556 }
1547 1557
1548 1558
1549 1559 /*!
1550 1560 * Searches through all of this class' enums for a value matching the
1551 1561 * name \a enumValueName. The name is excluding the class/namespace
1552 1562 * prefix. The function recursivly searches interfaces and baseclasses
1553 1563 * of this class.
1554 1564 */
1555 1565 AbstractMetaEnum *AbstractMetaClass::findEnumForValue(const QString &enumValueName)
1556 1566 {
1557 1567 foreach (AbstractMetaEnum *e, m_enums) {
1558 1568 foreach (AbstractMetaEnumValue *v, e->values()) {
1559 1569 if (v->name() == enumValueName)
1560 1570 return e;
1561 1571 }
1562 1572 }
1563 1573
1564 1574 if (typeEntry()->designatedInterface())
1565 1575 return extractInterface()->findEnumForValue(enumValueName);
1566 1576
1567 1577 if (baseClass() != 0)
1568 1578 return baseClass()->findEnumForValue(enumValueName);
1569 1579
1570 1580 return 0;
1571 1581 }
1572 1582
1573 1583
1574 1584 static void add_extra_include_for_type(AbstractMetaClass *meta_class, const AbstractMetaType *type)
1575 1585 {
1576 1586
1577 1587 if (type == 0)
1578 1588 return;
1579 1589
1580 1590 Q_ASSERT(meta_class != 0);
1581 1591 const TypeEntry *entry = (type ? type->typeEntry() : 0);
1582 1592 if (entry != 0 && entry->isComplex()) {
1583 1593 const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry);
1584 1594 ComplexTypeEntry *class_entry = meta_class->typeEntry();
1585 1595 if (class_entry != 0 && centry->include().isValid())
1586 1596 class_entry->addExtraInclude(centry->include());
1587 1597 }
1588 1598
1589 1599 if (type->hasInstantiations()) {
1590 1600 QList<AbstractMetaType *> instantiations = type->instantiations();
1591 1601 foreach (AbstractMetaType *instantiation, instantiations)
1592 1602 add_extra_include_for_type(meta_class, instantiation);
1593 1603 }
1594 1604 }
1595 1605
1596 1606 static void add_extra_includes_for_function(AbstractMetaClass *meta_class, const AbstractMetaFunction *meta_function)
1597 1607 {
1598 1608 Q_ASSERT(meta_class != 0);
1599 1609 Q_ASSERT(meta_function != 0);
1600 1610 add_extra_include_for_type(meta_class, meta_function->type());
1601 1611
1602 1612 AbstractMetaArgumentList arguments = meta_function->arguments();
1603 1613 foreach (AbstractMetaArgument *argument, arguments)
1604 1614 add_extra_include_for_type(meta_class, argument->type());
1605 1615 }
1606 1616
1607 1617 void AbstractMetaClass::fixFunctions()
1608 1618 {
1609 1619 if (m_functions_fixed)
1610 1620 return;
1611 1621 else
1612 1622 m_functions_fixed = true;
1613 1623
1614 1624 AbstractMetaClass *super_class = baseClass();
1615 1625 AbstractMetaFunctionList funcs = functions();
1616 1626
1617 1627 // printf("fix functions for %s\n", qPrintable(name()));
1618 1628
1619 1629 if (super_class != 0)
1620 1630 super_class->fixFunctions();
1621 1631 int iface_idx = 0;
1622 1632 while (super_class || iface_idx < interfaces().size()) {
1623 1633 // printf(" - base: %s\n", qPrintable(super_class->name()));
1624 1634
1625 1635 // Since we always traverse the complete hierarchy we are only
1626 1636 // interrested in what each super class implements, not what
1627 1637 // we may have propagated from their base classes again.
1628 1638 AbstractMetaFunctionList super_funcs;
1629 1639 if (super_class) {
1630 1640
1631 1641 // Super classes can never be final
1632 1642 if (super_class->isFinalInTargetLang()) {
1633 1643 ReportHandler::warning("Final class '" + super_class->name() + "' set to non-final, as it is extended by other classes");
1634 1644 *super_class -= AbstractMetaAttributes::FinalInTargetLang;
1635 1645 }
1636 1646 super_funcs = super_class->queryFunctions(AbstractMetaClass::ClassImplements);
1637 1647 } else {
1638 1648 super_funcs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions);
1639 1649 }
1640 1650
1641 1651 QSet<AbstractMetaFunction *> funcs_to_add;
1642 1652 for (int sfi=0; sfi<super_funcs.size(); ++sfi) {
1643 1653 AbstractMetaFunction *sf = super_funcs.at(sfi);
1644 1654
1645 1655 if (sf->isRemovedFromAllLanguages(sf->implementingClass()))
1646 1656 continue;
1647 1657
1648 1658 // we generally don't care about private functions, but we have to get the ones that are
1649 1659 // virtual in case they override abstract functions.
1650 1660 bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
1651 1661 for (int fi=0; fi<funcs.size(); ++fi) {
1652 1662 AbstractMetaFunction *f = funcs.at(fi);
1653 1663 if (f->isRemovedFromAllLanguages(f->implementingClass()))
1654 1664 continue;
1655 1665
1656 1666 uint cmp = f->compareTo(sf);
1657 1667
1658 1668 if (cmp & AbstractMetaFunction::EqualModifiedName) {
1659 1669 // printf(" - %s::%s similar to %s::%s %x vs %x\n",
1660 1670 // qPrintable(sf->implementingClass()->typeEntry()->qualifiedCppName()),
1661 1671 // qPrintable(sf->name()),
1662 1672 // qPrintable(f->implementingClass()->typeEntry()->qualifiedCppName()),
1663 1673 // qPrintable(f->name()),
1664 1674 // sf->attributes(),
1665 1675 // f->attributes());
1666 1676
1667 1677 add = false;
1668 1678 if (cmp & AbstractMetaFunction::EqualArguments) {
1669 1679
1670 1680 // if (!(cmp & AbstractMetaFunction::EqualReturnType)) {
1671 1681 // ReportHandler::warning(QString("%1::%2 and %3::%4 differ in retur type")
1672 1682 // .arg(sf->implementingClass()->name())
1673 1683 // .arg(sf->name())
1674 1684 // .arg(f->implementingClass()->name())
1675 1685 // .arg(f->name()));
1676 1686 // }
1677 1687
1678 1688 // Same function, propegate virtual...
1679 1689 if (!(cmp & AbstractMetaFunction::EqualAttributes)) {
1680 1690 if (!f->isEmptyFunction()) {
1681 1691 if (!sf->isFinalInCpp() && f->isFinalInCpp()) {
1682 1692 *f -= AbstractMetaAttributes::FinalInCpp;
1683 1693 // printf(" --- inherit virtual\n");
1684 1694 }
1685 1695 if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) {
1686 1696 *f -= AbstractMetaAttributes::FinalInTargetLang;
1687 1697 // printf(" --- inherit virtual\n");
1688 1698 }
1689 1699 if (!f->isFinalInTargetLang() && f->isPrivate()) {
1690 1700 f->setFunctionType(AbstractMetaFunction::EmptyFunction);
1691 1701 f->setVisibility(AbstractMetaAttributes::Protected);
1692 1702 *f += AbstractMetaAttributes::FinalInTargetLang;
1693 1703 ReportHandler::warning(QString("private virtual function '%1' in '%2'")
1694 1704 .arg(f->signature())
1695 1705 .arg(f->implementingClass()->name()));
1696 1706 }
1697 1707 }
1698 1708 }
1699 1709
1700 1710 if (f->visibility() != sf->visibility()) {
1701 1711 QString warn = QString("visibility of function '%1' modified in class '%2'")
1702 1712 .arg(f->name()).arg(name());
1703 1713 ReportHandler::warning(warn);
1704 1714
1705 1715 // If new visibility is private, we can't
1706 1716 // do anything. If it isn't, then we
1707 1717 // prefer the parent class's visibility
1708 1718 // setting for the function.
1709 1719 if (!f->isPrivate() && !sf->isPrivate())
1710 1720 f->setVisibility(sf->visibility());
1711 1721
1712 1722 // Private overrides of abstract functions have to go into the class or
1713 1723 // the subclasses will not compile as non-abstract classes.
1714 1724 // But they don't need to be implemented, since they can never be called.
1715 1725 if (f->isPrivate() && sf->isAbstract()) {
1716 1726 f->setFunctionType(AbstractMetaFunction::EmptyFunction);
1717 1727 f->setVisibility(sf->visibility());
1718 1728 *f += AbstractMetaAttributes::FinalInTargetLang;
1719 1729 *f += AbstractMetaAttributes::FinalInCpp;
1720 1730 }
1721 1731 }
1722 1732
1723 1733 // Set the class which first declares this function, afawk
1724 1734 f->setDeclaringClass(sf->declaringClass());
1725 1735
1726 1736 if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) {
1727 1737 // Shadowed funcion, need to make base class
1728 1738 // function non-virtual
1729 1739 if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) {
1730 1740
1731 1741 // Check whether the superclass method has been redefined to non-final
1732 1742
1733 1743 bool hasNonFinalModifier = false;
1734 1744 bool isBaseImplPrivate = false;
1735 1745 FunctionModificationList mods = sf->modifications(sf->implementingClass());
1736 1746 foreach (FunctionModification mod, mods) {
1737 1747 if (mod.isNonFinal()) {
1738 1748 hasNonFinalModifier = true;
1739 1749 break;
1740 1750 } else if (mod.isPrivate()) {
1741 1751 isBaseImplPrivate = true;
1742 1752 break;
1743 1753 }
1744 1754 }
1745 1755
1746 1756 if (!hasNonFinalModifier && !isBaseImplPrivate) {
1747 1757 ReportHandler::warning(QString::fromLatin1("Shadowing: %1::%2 and %3::%4; Java code will not compile")
1748 1758 .arg(sf->implementingClass()->name())
1749 1759 .arg(sf->signature())
1750 1760 .arg(f->implementingClass()->name())
1751 1761 .arg(f->signature()));
1752 1762 }
1753 1763 }
1754 1764 }
1755 1765
1756 1766 }
1757 1767
1758 1768 if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
1759 1769 AbstractMetaArgumentList arguments;
1760 1770 if (f->arguments().size() < sf->arguments().size())
1761 1771 arguments = sf->arguments();
1762 1772 else
1763 1773 arguments = f->arguments();
1764 1774
1765 1775 for (int i=0; i<arguments.size(); ++i)
1766 1776 arguments[i]->setDefaultValueExpression(QString());
1767 1777 }
1768 1778
1769 1779
1770 1780 // Otherwise we have function shadowing and we can
1771 1781 // skip the thing...
1772 1782 } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) {
1773 1783
1774 1784 // In the case of function shadowing where the function name has been altered to
1775 1785 // avoid conflict, we don't copy in the original.
1776 1786 add = false;
1777 1787 }
1778 1788
1779 1789 }
1780 1790
1781 1791 if (add)
1782 1792 funcs_to_add << sf;
1783 1793 }
1784 1794
1785 1795 foreach (AbstractMetaFunction *f, funcs_to_add)
1786 1796 funcs << f->copy();
1787 1797
1788 1798 if (super_class)
1789 1799 super_class = super_class->baseClass();
1790 1800 else
1791 1801 iface_idx++;
1792 1802 }
1793 1803
1794 1804 bool hasPrivateConstructors = false;
1795 1805 bool hasPublicConstructors = false;
1796 1806 foreach (AbstractMetaFunction *func, funcs) {
1797 1807 FunctionModificationList mods = func->modifications(this);
1798 1808 foreach (const FunctionModification &mod, mods) {
1799 1809 if (mod.isRenameModifier()) {
1800 1810 // qDebug() << name() << func->originalName() << func << " from "
1801 1811 // << func->implementingClass()->name() << "renamed to" << mod.renamedTo();
1802 1812 func->setName(mod.renamedTo());
1803 1813 }
1804 1814 }
1805 1815
1806 1816 // Make sure class is abstract if one of the functions is
1807 1817 if (func->isAbstract()) {
1808 1818 (*this) += AbstractMetaAttributes::Abstract;
1809 1819 (*this) -= AbstractMetaAttributes::Final;
1810 1820 }
1811 1821
1812 1822 if (func->isConstructor()) {
1813 1823 if (func->isPrivate())
1814 1824 hasPrivateConstructors = true;
1815 1825 else
1816 1826 hasPublicConstructors = true;
1817 1827 }
1818 1828
1819 1829
1820 1830
1821 1831 // Make sure that we include files for all classes that are in use
1822 1832
1823 1833 if (!func->isRemovedFrom(this, TypeSystem::ShellCode))
1824 1834 add_extra_includes_for_function(this, func);
1825 1835 }
1826 1836
1827 1837 if (hasPrivateConstructors && !hasPublicConstructors) {
1828 1838 (*this) += AbstractMetaAttributes::Abstract;
1829 1839 (*this) -= AbstractMetaAttributes::Final;
1830 1840 }
1831 1841
1832 1842 foreach (AbstractMetaFunction *f1, funcs) {
1833 1843 foreach (AbstractMetaFunction *f2, funcs) {
1834 1844 if (f1 != f2) {
1835 1845 uint cmp = f1->compareTo(f2);
1836 1846 if ((cmp & AbstractMetaFunction::EqualName)
1837 1847 && !f1->isFinalInCpp()
1838 1848 && f2->isFinalInCpp()) {
1839 1849 *f2 += AbstractMetaAttributes::FinalOverload;
1840 1850 // qDebug() << f2 << f2->implementingClass()->name() << "::" << f2->name() << f2->arguments().size() << " vs " << f1 << f1->implementingClass()->name() << "::" << f1->name() << f1->arguments().size();
1841 1851 // qDebug() << " " << f2;
1842 1852 // AbstractMetaArgumentList f2Args = f2->arguments();
1843 1853 // foreach (AbstractMetaArgument *a, f2Args)
1844 1854 // qDebug() << " " << a->type()->name() << a->name();
1845 1855 // qDebug() << " " << f1;
1846 1856 // AbstractMetaArgumentList f1Args = f1->arguments();
1847 1857 // foreach (AbstractMetaArgument *a, f1Args)
1848 1858 // qDebug() << " " << a->type()->name() << a->name();
1849 1859
1850 1860 }
1851 1861 }
1852 1862 }
1853 1863 }
1854 1864
1855 1865 setFunctions(funcs);
1856 1866 }
1857 1867
1858 1868
1859 1869 QString AbstractMetaType::minimalSignature() const
1860 1870 {
1861 1871 QString minimalSignature;
1862 1872 if (isConstant())
1863 1873 minimalSignature += "const ";
1864 1874 minimalSignature += typeEntry()->qualifiedCppName();
1865 1875 if (hasInstantiations()) {
1866 1876 QList<AbstractMetaType *> instantiations = this->instantiations();
1867 1877 minimalSignature += "<";
1868 1878 for (int i=0;i<instantiations.size();++i) {
1869 1879 if (i > 0)
1870 1880 minimalSignature += ",";
1871 1881 minimalSignature += instantiations.at(i)->minimalSignature();
1872 1882 }
1873 1883 minimalSignature += ">";
1874 1884 }
1875 1885
1876 1886 if (isReference())
1877 1887 minimalSignature += "&";
1878 1888 for (int j=0; j<indirections(); ++j)
1879 1889 minimalSignature += "*";
1880 1890
1881 1891 return minimalSignature;
1882 1892 }
1883 1893
1884 1894 bool AbstractMetaType::hasNativeId() const
1885 1895 {
1886 1896 return (isQObject() || isValue() || isObject()) && typeEntry()->isNativeIdBased();
1887 1897 }
1888 1898
1889 1899
1890 1900 /*******************************************************************************
1891 1901 * Other stuff...
1892 1902 */
1893 1903
1894 1904
1895 1905 AbstractMetaEnum *AbstractMetaClassList::findEnum(const EnumTypeEntry *entry) const
1896 1906 {
1897 1907 Q_ASSERT(entry->isEnum());
1898 1908
1899 1909 QString qualified_name = entry->qualifiedCppName();
1900 1910 int pos = qualified_name.lastIndexOf("::");
1901 1911
1902 1912 QString enum_name;
1903 1913 QString class_name;
1904 1914
1905 1915 if (pos > 0) {
1906 1916 enum_name = qualified_name.mid(pos + 2);
1907 1917 class_name = qualified_name.mid(0, pos);
1908 1918 } else {
1909 1919 enum_name = qualified_name;
1910 1920 class_name = TypeDatabase::globalNamespaceClassName(entry);
1911 1921 }
1912 1922
1913 1923 AbstractMetaClass *meta_class = findClass(class_name);
1914 1924 if (!meta_class) {
1915 1925 ReportHandler::warning(QString("AbstractMeta::findEnum(), unknown class '%1' in '%2'")
1916 1926 .arg(class_name).arg(entry->qualifiedCppName()));
1917 1927 return 0;
1918 1928 }
1919 1929
1920 1930 return meta_class->findEnum(enum_name);
1921 1931 }
1922 1932
1923 1933 AbstractMetaEnumValue *AbstractMetaEnumValueList::find(const QString &name) const
1924 1934 {
1925 1935 for (int i=0; i<size(); ++i) {
1926 1936 if (name == at(i)->name())
1927 1937 return at(i);
1928 1938 }
1929 1939 return 0;
1930 1940 }
1931 1941
1932 1942 AbstractMetaEnumValue *AbstractMetaClassList::findEnumValue(const QString &name) const
1933 1943 {
1934 1944 QStringList lst = name.split(QLatin1String("::"));
1935 1945
1936 1946 Q_ASSERT_X(lst.size() == 2, "AbstractMetaClassList::findEnumValue()", "Expected qualified enum");
1937 1947
1938 1948
1939 1949 QString prefixName = lst.at(0);
1940 1950 QString enumName = lst.at(1);
1941 1951
1942 1952 AbstractMetaClass *cl = findClass(prefixName);
1943 1953 if (cl)
1944 1954 return cl->findEnumValue(enumName, 0);
1945 1955
1946 1956 ReportHandler::warning(QString("no matching enum '%1'").arg(name));
1947 1957 return 0;
1948 1958 }
1949 1959
1950 1960 /*!
1951 1961 * Searches the list after a class that mathces \a name; either as
1952 1962 * C++, Java base name or complete Java package.class name.
1953 1963 */
1954 1964
1955 1965 AbstractMetaClass *AbstractMetaClassList::findClass(const QString &name) const
1956 1966 {
1957 1967 if (name.isEmpty())
1958 1968 return 0;
1959 1969
1960 1970 foreach (AbstractMetaClass *c, *this) {
1961 1971 if (c->qualifiedCppName() == name)
1962 1972 return c;
1963 1973 }
1964 1974
1965 1975 foreach (AbstractMetaClass *c, *this) {
1966 1976 if (c->fullName() == name)
1967 1977 return c;
1968 1978 }
1969 1979
1970 1980 foreach (AbstractMetaClass *c, *this) {
1971 1981 if (c->name() == name)
1972 1982 return c;
1973 1983 }
1974 1984
1975 1985 return 0;
1976 1986 }
@@ -1,944 +1,946
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #ifndef ABSTRACTMETALANG_H
43 43 #define ABSTRACTMETALANG_H
44 44
45 45 #include "codemodel.h"
46 46
47 47 #include "typesystem.h"
48 48
49 49 #include <QSet>
50 50 #include <QStringList>
51 51 #include <QTextStream>
52 52
53 53
54 54 class AbstractMeta;
55 55 class AbstractMetaClass;
56 56 class AbstractMetaField;
57 57 class AbstractMetaFunction;
58 58 class AbstractMetaType;
59 59 class AbstractMetaVariable;
60 60 class AbstractMetaArgument;
61 61 class AbstractMetaEnumValue;
62 62 class AbstractMetaEnum;
63 63 class QPropertySpec;
64 64
65 65 typedef QList<AbstractMetaField *> AbstractMetaFieldList;
66 66 typedef QList<AbstractMetaArgument *> AbstractMetaArgumentList;
67 67 typedef QList<AbstractMetaFunction *> AbstractMetaFunctionList;
68 68 class AbstractMetaClassList : public QList<AbstractMetaClass *>
69 69 {
70 70 public:
71 71 AbstractMetaClass *findClass(const QString &name) const;
72 72 AbstractMetaEnumValue *findEnumValue(const QString &string) const;
73 73 AbstractMetaEnum *findEnum(const EnumTypeEntry *entry) const;
74 74
75 75 };
76 76
77 77
78 78
79 79 class AbstractMetaAttributes
80 80 {
81 81 public:
82 82 AbstractMetaAttributes() : m_attributes(0) { };
83 83
84 84 enum Attribute {
85 85 None = 0x00000000,
86 86
87 87 Private = 0x00000001,
88 88 Protected = 0x00000002,
89 89 Public = 0x00000004,
90 90 Friendly = 0x00000008,
91 91 Visibility = 0x0000000f,
92 92
93 93 Native = 0x00000010,
94 94 Abstract = 0x00000020,
95 95 Static = 0x00000040,
96 96
97 97 FinalInTargetLang = 0x00000080,
98 98 FinalInCpp = 0x00000100,
99 99 ForceShellImplementation = 0x00000200,
100 100
101 101 GetterFunction = 0x00000400,
102 102 SetterFunction = 0x00000800,
103 103
104 104 FinalOverload = 0x00001000,
105 105 InterfaceFunction = 0x00002000,
106 106
107 107 PropertyReader = 0x00004000,
108 108 PropertyWriter = 0x00008000,
109 109 PropertyResetter = 0x00010000,
110 110
111 111 Fake = 0x00020000,
112 112
113 113 Invokable = 0x00040000,
114 114
115 115 Final = FinalInTargetLang | FinalInCpp
116 116 };
117 117
118 118 uint attributes() const { return m_attributes; }
119 119 void setAttributes(uint attributes) { m_attributes = attributes; }
120 120
121 121 uint originalAttributes() const { return m_originalAttributes; }
122 122 void setOriginalAttributes(uint attributes) { m_originalAttributes = attributes; }
123 123
124 124 uint visibility() const { return m_attributes & Visibility; }
125 125 void setVisibility(uint visi) { m_attributes = (m_attributes & ~Visibility) | visi; }
126 126
127 127 void operator+=(Attribute attribute) { m_attributes |= attribute; }
128 128 void operator-=(Attribute attribute) { m_attributes &= ~attribute; }
129 129
130 130 bool isNative() const { return m_attributes & Native; }
131 131 bool isFinal() const { return (m_attributes & Final) == Final; }
132 132 bool isFinalInTargetLang() const { return m_attributes & FinalInTargetLang; }
133 133 bool isFinalInCpp() const { return m_attributes & FinalInCpp; }
134 134 bool isAbstract() const { return m_attributes & Abstract; }
135 135 bool isStatic() const { return m_attributes & Static; }
136 136 bool isForcedShellImplementation() const { return m_attributes & ForceShellImplementation; }
137 137 bool isInterfaceFunction() const { return m_attributes & InterfaceFunction; }
138 138 bool isFinalOverload() const { return m_attributes & FinalOverload; }
139 139 bool isInvokable() const { return m_attributes & Invokable; }
140 140
141 141 bool isPropertyReader() const { return m_attributes & PropertyReader; }
142 142 bool isPropertyWriter() const { return m_attributes & PropertyWriter; }
143 143 bool isPropertyResetter() const { return m_attributes & PropertyResetter; }
144 144
145 145 bool isPrivate() const { return m_attributes & Private; }
146 146 bool isProtected() const { return m_attributes & Protected; }
147 147 bool isPublic() const { return m_attributes & Public; }
148 148 bool isFriendly() const { return m_attributes & Friendly; }
149 149
150 150 bool wasPrivate() const { return m_originalAttributes & Private; }
151 151 bool wasProtected() const { return m_originalAttributes & Protected; }
152 152 bool wasPublic() const { return m_originalAttributes & Public; }
153 153 bool wasFriendly() const { return m_originalAttributes & Friendly; }
154 154
155 155 private:
156 156 uint m_attributes;
157 157 uint m_originalAttributes;
158 158 };
159 159
160 160
161 161 class AbstractMetaType
162 162 {
163 163 public:
164 164 enum TypeUsagePattern {
165 165 InvalidPattern,
166 166 PrimitivePattern,
167 167 FlagsPattern,
168 168 EnumPattern,
169 169 ValuePattern,
170 170 StringPattern,
171 171 CharPattern,
172 172 ObjectPattern,
173 173 QObjectPattern,
174 174 NativePointerPattern,
175 175 ContainerPattern,
176 176 VariantPattern,
177 177 JObjectWrapperPattern,
178 178 ArrayPattern,
179 179 ThreadPattern
180 180 };
181 181
182 182 AbstractMetaType() :
183 183 m_type_entry(0),
184 184 m_array_element_count(0),
185 185 m_array_element_type(0),
186 186 m_original_template_type(0),
187 187 m_pattern(InvalidPattern),
188 188 m_constant(false),
189 189 m_reference(false),
190 190 m_cpp_instantiation(true),
191 191 m_indirections(0),
192 192 m_reserved(0)
193 193 {
194 194 }
195 195
196 196 QString package() const { return m_type_entry->javaPackage(); }
197 197 QString name() const { return m_type_entry->targetLangName(); }
198 198 QString fullName() const { return m_type_entry->qualifiedTargetLangName(); }
199 199
200 200 void setTypeUsagePattern(TypeUsagePattern pattern) { m_pattern = pattern; }
201 201 TypeUsagePattern typeUsagePattern() const { return m_pattern; }
202 202
203 203 // true when use pattern is container
204 204 bool hasInstantiations() const { return !m_instantiations.isEmpty(); }
205 205 void addInstantiation(AbstractMetaType *inst) { m_instantiations << inst; }
206 206 void setInstantiations(const QList<AbstractMetaType *> &insts) { m_instantiations = insts; }
207 207 QList<AbstractMetaType *> instantiations() const { return m_instantiations; }
208 208 void setInstantiationInCpp(bool incpp) { m_cpp_instantiation = incpp; }
209 209 bool hasInstantiationInCpp() const { return hasInstantiations() && m_cpp_instantiation; }
210 210
211 211 QString minimalSignature() const;
212 212
213 213 // true when the type is a QtJambiObject subclass
214 214 bool hasNativeId() const;
215 215
216 216 // returns true if the typs is used as a non complex primitive, no & or *'s
217 217 bool isPrimitive() const { return m_pattern == PrimitivePattern; }
218 218
219 219 // returns true if the type is used as an enum
220 220 bool isEnum() const { return m_pattern == EnumPattern; }
221 221
222 222 // returns true if the type is used as a QObject *
223 223 bool isQObject() const { return m_pattern == QObjectPattern; }
224 224
225 225 // returns true if the type is used as an object, e.g. Xxx *
226 226 bool isObject() const { return m_pattern == ObjectPattern; }
227 227
228 228 // returns true if the type is used as an array, e.g. Xxx[42]
229 229 bool isArray() const { return m_pattern == ArrayPattern; }
230 230
231 231 // returns true if the type is used as a value type (X or const X &)
232 232 bool isValue() const { return m_pattern == ValuePattern; }
233 233
234 234 // returns true for more complex types...
235 235 bool isNativePointer() const { return m_pattern == NativePointerPattern; }
236 236
237 237 // returns true if the type was originally a QString or const QString & or equivalent for QLatin1String
238 238 bool isTargetLangString() const { return m_pattern == StringPattern; }
239 239
240 240 // returns true if the type was originally a QChar or const QChar &
241 241 bool isTargetLangChar() const { return m_pattern == CharPattern; }
242 242
243 243 // return true if the type was originally a QVariant or const QVariant &
244 244 bool isVariant() const { return m_pattern == VariantPattern; }
245 245
246 246 // return true if the type was originally a JObjectWrapper or const JObjectWrapper &
247 247 bool isJObjectWrapper() const { return m_pattern == JObjectWrapperPattern; }
248 248
249 249 // returns true if the type was used as a container
250 250 bool isContainer() const { return m_pattern == ContainerPattern; }
251 251
252 252 // returns true if the type was used as a flag
253 253 bool isFlags() const { return m_pattern == FlagsPattern; }
254 254
255 255 // returns true if the type was used as a thread
256 256 bool isThread() const { return m_pattern == ThreadPattern; }
257 257
258 258 bool isConstant() const { return m_constant; }
259 259 void setConstant(bool constant) { m_constant = constant; }
260 260
261 261 bool isReference() const { return m_reference; }
262 262 void setReference(bool ref) { m_reference = ref; }
263 263
264 264 // Returns true if the type is to be implemented using Java enums, e.g. not plain ints.
265 265 bool isTargetLangEnum() const { return isEnum() && !((EnumTypeEntry *) typeEntry())->forceInteger(); }
266 266 bool isIntegerEnum() const { return isEnum() && !isTargetLangEnum(); }
267 267
268 268 // Returns true if the type is to be implemented using Java QFlags, e.g. not plain ints.
269 269 bool isTargetLangFlags() const {
270 270 return isFlags() && !((FlagsTypeEntry *) typeEntry())->forceInteger(); }
271 271 bool isIntegerFlags() const { return isFlags() && !isTargetLangFlags(); }
272 272
273 273 int actualIndirections() const { return m_indirections + (isReference() ? 1 : 0); }
274 274 int indirections() const { return m_indirections; }
275 275 void setIndirections(int indirections) { m_indirections = indirections; }
276 276
277 277 void setArrayElementCount(int n) { m_array_element_count = n; }
278 278 int arrayElementCount() const { return m_array_element_count; }
279 279
280 280 AbstractMetaType *arrayElementType() const { return m_array_element_type; }
281 281 void setArrayElementType(AbstractMetaType *t) { m_array_element_type = t; }
282 282
283 283 QString cppSignature() const;
284 284
285 285 AbstractMetaType *copy() const;
286 286
287 287 const TypeEntry *typeEntry() const { return m_type_entry; }
288 288 void setTypeEntry(const TypeEntry *type) { m_type_entry = type; }
289 289
290 290 void setOriginalTypeDescription(const QString &otd) { m_original_type_description = otd; }
291 291 QString originalTypeDescription() const { return m_original_type_description; }
292 292
293 293 void setOriginalTemplateType(const AbstractMetaType *type) { m_original_template_type = type; }
294 294 const AbstractMetaType *originalTemplateType() const { return m_original_template_type; }
295 295
296 296 private:
297 297 const TypeEntry *m_type_entry;
298 298 QList <AbstractMetaType *> m_instantiations;
299 299 QString m_package;
300 300 QString m_original_type_description;
301 301
302 302 int m_array_element_count;
303 303 AbstractMetaType *m_array_element_type;
304 304 const AbstractMetaType *m_original_template_type;
305 305
306 306 TypeUsagePattern m_pattern;
307 307 uint m_constant : 1;
308 308 uint m_reference : 1;
309 309 uint m_cpp_instantiation : 1;
310 310 int m_indirections : 4;
311 311 uint m_reserved : 25; // unused
312 312 };
313 313
314 314 class AbstractMetaVariable
315 315 {
316 316 public:
317 317 AbstractMetaVariable() : m_type(0) { }
318 318
319 319 AbstractMetaType *type() const { return m_type; }
320 320 void setType(AbstractMetaType *type) { m_type = type; }
321 321
322 322 QString name() const { return m_name; }
323 323 void setName(const QString &name) { m_name = name; }
324 324
325 325 private:
326 326 QString m_name;
327 327 AbstractMetaType *m_type;
328 328 };
329 329
330 330
331 331
332 332 class AbstractMetaArgument : public AbstractMetaVariable
333 333 {
334 334 public:
335 335 AbstractMetaArgument() : m_argument_index(0) { };
336 336
337 337 QString defaultValueExpression() const { return m_expression; }
338 338 void setDefaultValueExpression(const QString &expr) { m_expression = expr; }
339 339
340 340 QString originalDefaultValueExpression() const { return m_original_expression; }
341 341 void setOriginalDefaultValueExpression(const QString &expr) { m_original_expression = expr; }
342 342
343 343 QString toString() const { return type()->name() + " " + AbstractMetaVariable::name() +
344 344 (m_expression.isEmpty() ? "" : " = " + m_expression); }
345 345
346 346 int argumentIndex() const { return m_argument_index; }
347 347 void setArgumentIndex(int argIndex) { m_argument_index = argIndex; }
348 348
349 349 QString argumentName() const;
350 350 QString indexedName() const;
351 351
352 352 AbstractMetaArgument *copy() const;
353 353
354 354 private:
355 355 // Just to force people to call argumentName() And indexedName();
356 356 QString name() const;
357 357
358 358 QString m_expression;
359 359 QString m_original_expression;
360 360 int m_argument_index;
361 361 };
362 362
363 363
364 364 class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttributes
365 365 {
366 366 public:
367 367 AbstractMetaField();
368 368 ~AbstractMetaField();
369 369
370 370 const AbstractMetaClass *enclosingClass() const { return m_class; }
371 371 void setEnclosingClass(const AbstractMetaClass *cls) { m_class = cls; }
372 372
373 373 const AbstractMetaFunction *getter() const;
374 374 const AbstractMetaFunction *setter() const;
375 375
376 376 FieldModificationList modifications() const;
377 377
378 378 AbstractMetaField *copy() const;
379 379
380 380 private:
381 381 mutable AbstractMetaFunction *m_getter;
382 382 mutable AbstractMetaFunction *m_setter;
383 383 const AbstractMetaClass *m_class;
384 384 };
385 385
386 386
387 387 class AbstractMetaFunction : public AbstractMetaAttributes
388 388 {
389 389 public:
390 390 enum FunctionType {
391 391 ConstructorFunction,
392 392 DestructorFunction,
393 393 NormalFunction,
394 394 SignalFunction,
395 395 EmptyFunction,
396 396 SlotFunction,
397 397 GlobalScopeFunction
398 398 };
399 399
400 400 enum CompareResult {
401 401 EqualName = 0x00000001,
402 402 EqualArguments = 0x00000002,
403 403 EqualAttributes = 0x00000004,
404 404 EqualImplementor = 0x00000008,
405 405 EqualReturnType = 0x00000010,
406 406 EqualDefaultValueOverload = 0x00000020,
407 407 EqualModifiedName = 0x00000040,
408 408
409 409 NameLessThan = 0x00001000,
410 410
411 411 PrettySimilar = EqualName | EqualArguments,
412 412 Equal = 0x0000001f,
413 413 NotEqual = 0x00001000
414 414 };
415 415
416 416 AbstractMetaFunction()
417 417 : m_function_type(NormalFunction),
418 418 m_type(0),
419 419 m_class(0),
420 420 m_implementing_class(0),
421 421 m_declaring_class(0),
422 422 m_interface_class(0),
423 423 m_property_spec(0),
424 424 m_constant(false),
425 425 m_invalid(false)
426 426 {
427 427 }
428 428
429 429 ~AbstractMetaFunction();
430 430
431 431 QString name() const { return m_name; }
432 432 void setName(const QString &name) { m_name = name; }
433 433
434 434 QString originalName() const { return m_original_name.isEmpty() ? name() : m_original_name; }
435 435 void setOriginalName(const QString &name) { m_original_name = name; }
436 436
437 437 QString modifiedName() const;
438 438
439 439 QString minimalSignature() const;
440 440 QStringList possibleIntrospectionCompatibleSignatures() const;
441 441
442 442 QString marshalledName() const;
443 443
444 444 // true if one or more of the arguments are of QtJambiObject subclasses
445 445 bool argumentsHaveNativeId() const
446 446 {
447 447 foreach (const AbstractMetaArgument *arg, m_arguments) {
448 448 if (arg->type()->hasNativeId())
449 449 return true;
450 450 }
451 451
452 452 return false;
453 453 }
454 454
455 455 bool isModifiedRemoved(int types = TypeSystem::All) const;
456 456
457 457 AbstractMetaType *type() const { return m_type; }
458 458 void setType(AbstractMetaType *type) { m_type = type; }
459 459
460 460 // The class that has this function as a member.
461 461 const AbstractMetaClass *ownerClass() const { return m_class; }
462 462 void setOwnerClass(const AbstractMetaClass *cls) { m_class = cls; }
463 463
464 464 // The first class in a hierarchy that declares the function
465 465 const AbstractMetaClass *declaringClass() const { return m_declaring_class; }
466 466 void setDeclaringClass(const AbstractMetaClass *cls) { m_declaring_class = cls; }
467 467
468 468 // The class that actually implements this function
469 469 const AbstractMetaClass *implementingClass() const { return m_implementing_class; }
470 470 void setImplementingClass(const AbstractMetaClass *cls) { m_implementing_class = cls; }
471 471
472 472 bool needsCallThrough() const;
473 473
474 474 AbstractMetaArgumentList arguments() const { return m_arguments; }
475 475 void setArguments(const AbstractMetaArgumentList &arguments) { m_arguments = arguments; }
476 476 void addArgument(AbstractMetaArgument *argument) { m_arguments << argument; }
477 477 int actualMinimumArgumentCount() const;
478 478
479 479 void setInvalid(bool on) { m_invalid = on; }
480 480 bool isInvalid() const { return m_invalid; }
481 481 bool isDeprecated() const;
482 482 bool isDestructor() const { return functionType() == DestructorFunction; }
483 483 bool isConstructor() const { return functionType() == ConstructorFunction; }
484 484 bool isNormal() const { return functionType() == NormalFunction || isSlot() || isInGlobalScope(); }
485 485 bool isInGlobalScope() const { return functionType() == GlobalScopeFunction; }
486 486 bool isSignal() const { return functionType() == SignalFunction; }
487 487 bool isSlot() const { return functionType() == SlotFunction; }
488 488 bool isEmptyFunction() const { return functionType() == EmptyFunction; }
489 489 FunctionType functionType() const { return m_function_type; }
490 490 void setFunctionType(FunctionType type) { m_function_type = type; }
491 491
492 492 bool isVirtual() { return !(isFinal() || isSignal() || isStatic()); }
493 493
494 494 QStringList introspectionCompatibleSignatures(const QStringList &resolvedArguments = QStringList()) const;
495 495 QString signature() const;
496 496 QString targetLangSignature(bool minimal = false) const;
497 497 bool shouldReturnThisObject() const { return QLatin1String("this") == argumentReplaced(0); }
498 498 bool shouldIgnoreReturnValue() const { return QLatin1String("void") == argumentReplaced(0); }
499 499
500 500 bool isConstant() const { return m_constant; }
501 501 void setConstant(bool constant) { m_constant = constant; }
502 502
503 503 QString toString() const { return m_name; }
504 504
505 505 uint compareTo(const AbstractMetaFunction *other) const;
506 506
507 507 bool operator <(const AbstractMetaFunction &a) const;
508 508
509 509 AbstractMetaFunction *copy() const;
510 510
511 511 QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
512 512 bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
513 513 QString conversionRule(TypeSystem::Language language, int idx) const;
514 514 QList<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const;
515 515
516 516 bool nullPointersDisabled(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
517 517 QString nullPointerDefaultValue(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
518 518
519 519 bool resetObjectAfterUse(int argument_idx) const;
520 520
521 521 // Returns whether garbage collection is disabled for the argument in any context
522 522 bool disabledGarbageCollection(const AbstractMetaClass *cls, int key) const;
523 523
524 524 // Returns the ownership rules for the given argument in the given context
525 525 TypeSystem::Ownership ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int idx) const;
526 526
527 527 bool isVirtualSlot() const;
528 528
529 529 QString typeReplaced(int argument_index) const;
530 530 bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
531 531 bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
532 532 bool argumentRemoved(int) const;
533 533
534 534 QString argumentReplaced(int key) const;
535 535 bool needsSuppressUncheckedWarning() const;
536 536
537 537 bool hasModifications(const AbstractMetaClass *implementor) const;
538 538 FunctionModificationList modifications(const AbstractMetaClass *implementor) const;
539 539
540 540 // If this function stems from an interface, this returns the
541 541 // interface that declares it.
542 542 const AbstractMetaClass *interfaceClass() const { return m_interface_class; }
543 543 void setInterfaceClass(const AbstractMetaClass *cl) { m_interface_class = cl; }
544 544
545 545 void setPropertySpec(QPropertySpec *spec) { m_property_spec = spec; }
546 546 QPropertySpec *propertySpec() const { return m_property_spec; }
547 547
548 548 private:
549 549 QString m_name;
550 550 QString m_original_name;
551 551 mutable QString m_cached_minimal_signature;
552 552 mutable QString m_cached_modified_name;
553 553
554 554 FunctionType m_function_type;
555 555 AbstractMetaType *m_type;
556 556 const AbstractMetaClass *m_class;
557 557 const AbstractMetaClass *m_implementing_class;
558 558 const AbstractMetaClass *m_declaring_class;
559 559 const AbstractMetaClass *m_interface_class;
560 560 QPropertySpec *m_property_spec;
561 561 AbstractMetaArgumentList m_arguments;
562 562 uint m_constant : 1;
563 563 uint m_invalid : 1;
564 564 };
565 565
566 566
567 567 class AbstractMetaEnumValue
568 568 {
569 569 public:
570 570 AbstractMetaEnumValue()
571 571 : m_value_set(false), m_value(0)
572 572 {
573 573 }
574 574
575 575 int value() const { return m_value; }
576 576 void setValue(int value) { m_value_set = true; m_value = value; }
577 577
578 578 QString stringValue() const { return m_string_value; }
579 579 void setStringValue(const QString &v) { m_string_value = v; }
580 580
581 581 QString name() const { return m_name; }
582 582 void setName(const QString &name) { m_name = name; }
583 583
584 584 bool isValueSet() const { return m_value_set; }
585 585
586 586 private:
587 587 QString m_name;
588 588 QString m_string_value;
589 589
590 590 bool m_value_set;
591 591 int m_value;
592 592 };
593 593
594 594
595 595 class AbstractMetaEnumValueList : public QList<AbstractMetaEnumValue *>
596 596 {
597 597 public:
598 598 AbstractMetaEnumValue *find(const QString &name) const;
599 599 };
600 600
601 601 class AbstractMetaEnum : public AbstractMetaAttributes
602 602 {
603 603 public:
604 604 AbstractMetaEnum() : m_type_entry(0), m_class(0), m_has_qenums_declaration(false) {}
605 605
606 606 AbstractMetaEnumValueList values() const { return m_enum_values; }
607 607 void addEnumValue(AbstractMetaEnumValue *enumValue) { m_enum_values << enumValue; }
608 608
609 609 QString name() const { return m_type_entry->targetLangName(); }
610 610 QString qualifier() const { return m_type_entry->javaQualifier(); }
611 611 QString package() const { return m_type_entry->javaPackage(); }
612 612 QString fullName() const { return package() + "." + qualifier() + "." + name(); }
613 613
614 614 // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class?
615 615 void setHasQEnumsDeclaration(bool on) { m_has_qenums_declaration = on; }
616 616 bool hasQEnumsDeclaration() const { return m_has_qenums_declaration; }
617 617
618 618 EnumTypeEntry *typeEntry() const { return m_type_entry; }
619 619 void setTypeEntry(EnumTypeEntry *entry) { m_type_entry = entry; }
620 620
621 621 AbstractMetaClass *enclosingClass() const { return m_class; }
622 622 void setEnclosingClass(AbstractMetaClass *c) { m_class = c; }
623 623
624 624 private:
625 625 AbstractMetaEnumValueList m_enum_values;
626 626 EnumTypeEntry *m_type_entry;
627 627 AbstractMetaClass *m_class;
628 628
629 629 uint m_has_qenums_declaration : 1;
630 630 uint m_reserved : 31;
631 631 };
632 632
633 633 typedef QList<AbstractMetaEnum *> AbstractMetaEnumList;
634 634
635 635 class AbstractMetaClass : public AbstractMetaAttributes
636 636 {
637 637 public:
638 638 enum FunctionQueryOption {
639 639 Constructors = 0x000001, // Only constructors
640 640 //Destructors = 0x000002, // Only destructors. Not included in class.
641 641 VirtualFunctions = 0x000004, // Only virtual functions (virtual in both TargetLang and C++)
642 642 FinalInTargetLangFunctions = 0x000008, // Only functions that are non-virtual in TargetLang
643 643 FinalInCppFunctions = 0x000010, // Only functions that are non-virtual in C++
644 644 ClassImplements = 0x000020, // Only functions implemented by the current class
645 645 Inconsistent = 0x000040, // Only inconsistent functions (inconsistent virtualness in TargetLang/C++)
646 646 StaticFunctions = 0x000080, // Only static functions
647 647 Signals = 0x000100, // Only signals
648 648 NormalFunctions = 0x000200, // Only functions that aren't signals
649 649 Visible = 0x000400, // Only public and protected functions
650 650 ForcedShellFunctions = 0x000800, // Only functions that are overridden to be implemented in the shell class
651 651 WasPublic = 0x001000, // Only functions that were originally public
652 652 WasProtected = 0x002000, // Only functions that were originally protected
653 653 NonStaticFunctions = 0x004000, // No static functions
654 654 Empty = 0x008000, // Empty overrides of abstract functions
655 655 Invisible = 0x010000, // Only private functions
656 656 VirtualInCppFunctions = 0x020000, // Only functions that are virtual in C++
657 657 NonEmptyFunctions = 0x040000, // Only functions with JNI implementations
658 658 VirtualInTargetLangFunctions = 0x080000, // Only functions which are virtual in TargetLang
659 659 AbstractFunctions = 0x100000, // Only abstract functions
660 660 WasVisible = 0x200000, // Only functions that were public or protected in the original code
661 661 NotRemovedFromTargetLang = 0x400000, // Only functions that have not been removed from TargetLang
662 662 NotRemovedFromShell = 0x800000, // Only functions that have not been removed from the shell class
663 663 VirtualSlots = 0x1000000 // Only functions that are set as virtual slots in the type system
664 664 };
665 665
666 666 AbstractMetaClass()
667 667 : m_namespace(false),
668 668 m_qobject(false),
669 669 m_has_virtuals(false),
670 670 m_has_nonpublic(false),
671 671 m_has_virtual_slots(false),
672 672 m_has_nonprivateconstructor(false),
673 673 m_functions_fixed(false),
674 674 m_has_public_destructor(true),
675 675 m_force_shell_class(false),
676 676 m_has_hash_function(false),
677 677 m_has_equals_operator(false),
678 678 m_has_clone_operator(false),
679 679 m_is_type_alias(false),
680 680 m_enclosing_class(0),
681 681 m_base_class(0),
682 682 m_template_base_class(0),
683 683 m_extracted_interface(0),
684 684 m_primary_interface_implementor(0),
685 685 m_type_entry(0),
686 686 m_qDebug_stream_function(0)
687 687 {
688 688 }
689 689
690 690 virtual ~AbstractMetaClass();
691 691
692 692 AbstractMetaClass *extractInterface();
693 693 void fixFunctions();
694 694
695 695 AbstractMetaFunctionList functions() const { return m_functions; }
696 696 void setFunctions(const AbstractMetaFunctionList &functions);
697 697 void addFunction(AbstractMetaFunction *function);
698 698 bool hasFunction(const AbstractMetaFunction *f) const;
699 699 bool hasFunction(const QString &str) const;
700 700 bool hasSignal(const AbstractMetaFunction *f) const;
701 701
702 702 bool hasConstructors() const;
703 703
704 704 void addDefaultConstructor();
705 705
706 706 bool hasNonPrivateConstructor() const { return m_has_nonprivateconstructor; }
707 707 void setHasNonPrivateConstructor(bool on) { m_has_nonprivateconstructor = on; }
708 708 bool hasPublicDestructor() const { return m_has_public_destructor; }
709 709 void setHasPublicDestructor(bool on) { m_has_public_destructor = on; }
710 710
711 711 AbstractMetaFunctionList queryFunctionsByName(const QString &name) const;
712 712 AbstractMetaFunctionList queryFunctions(uint query) const;
713 713 inline AbstractMetaFunctionList allVirtualFunctions() const;
714 714 inline AbstractMetaFunctionList allFinalFunctions() const;
715 715 AbstractMetaFunctionList functionsInTargetLang() const;
716 716 AbstractMetaFunctionList functionsInShellClass() const;
717 717 inline AbstractMetaFunctionList cppInconsistentFunctions() const;
718 718 inline AbstractMetaFunctionList cppSignalFunctions() const;
719 719 AbstractMetaFunctionList publicOverrideFunctions() const;
720 720 AbstractMetaFunctionList virtualOverrideFunctions() const;
721 721 AbstractMetaFunctionList virtualFunctions() const;
722 722 AbstractMetaFunctionList nonVirtualShellFunctions() const;
723 723
724 724 AbstractMetaFieldList fields() const { return m_fields; }
725 725 void setFields(const AbstractMetaFieldList &fields) { m_fields = fields; }
726 726 void addField(AbstractMetaField *field) { m_fields << field; }
727 727
728 728 AbstractMetaEnumList enums() const { return m_enums; }
729 729 void setEnums(const AbstractMetaEnumList &enums) { m_enums = enums; }
730 730 void addEnum(AbstractMetaEnum *e) { m_enums << e; }
731 731
732 732 AbstractMetaEnum *findEnum(const QString &enumName);
733 733 AbstractMetaEnum *findEnumForValue(const QString &enumName);
734 734 AbstractMetaEnumValue *findEnumValue(const QString &enumName, AbstractMetaEnum *meta_enum);
735 735
736 736 AbstractMetaClassList interfaces() const { return m_interfaces; }
737 737 void addInterface(AbstractMetaClass *interface);
738 738 void setInterfaces(const AbstractMetaClassList &interface);
739 739
740 740 QString fullName() const { return package() + "." + name(); }
741 741 QString name() const;
742 742
743 743 QString baseClassName() const { return m_base_class ? m_base_class->name() : QString(); }
744 744
745 745 AbstractMetaClass *baseClass() const { return m_base_class; }
746 746 void setBaseClass(AbstractMetaClass *base_class) { m_base_class = base_class; }
747 747
748 748 const AbstractMetaClass *enclosingClass() const { return m_enclosing_class; }
749 749 void setEnclosingClass(AbstractMetaClass *cl) { m_enclosing_class = cl; }
750 750
751 751 QString package() const { return m_type_entry->javaPackage(); }
752 752 bool isInterface() const { return m_type_entry->isInterface(); }
753 753 bool isNamespace() const { return m_type_entry->isNamespace(); }
754 754 bool isQObject() const { return m_type_entry->isQObject(); }
755 755 bool isQtNamespace() const { return isNamespace() && name() == "Qt"; }
756 756 QString qualifiedCppName() const { return m_type_entry->qualifiedCppName(); }
757 757
758 758 bool hasInconsistentFunctions() const;
759 759 bool hasSignals() const;
760 760 bool inheritsFrom(const AbstractMetaClass *other) const;
761 761
762 762 void setForceShellClass(bool on) { m_force_shell_class = on; }
763 763 bool generateShellClass() const;
764 764
765 765 bool hasVirtualSlots() const { return m_has_virtual_slots; }
766 766 bool hasVirtualFunctions() const { return !isFinal() && m_has_virtuals; }
767 767 bool hasProtectedFunctions() const;
768 768
769 769 QList<TypeEntry *> templateArguments() const { return m_template_args; }
770 770 void setTemplateArguments(const QList<TypeEntry *> &args) { m_template_args = args; }
771 771
772 772 bool hasFieldAccessors() const;
773 773
774 774 // only valid during metajavabuilder's run
775 775 QStringList baseClassNames() const { return m_base_class_names; }
776 776 void setBaseClassNames(const QStringList &names) { m_base_class_names = names; }
777 777
778 778 AbstractMetaClass *primaryInterfaceImplementor() const { return m_primary_interface_implementor; }
779 779 void setPrimaryInterfaceImplementor(AbstractMetaClass *cl) { m_primary_interface_implementor = cl; }
780 780
781 781 const ComplexTypeEntry *typeEntry() const { return m_type_entry; }
782 782 ComplexTypeEntry *typeEntry() { return m_type_entry; }
783 783 void setTypeEntry(ComplexTypeEntry *type) { m_type_entry = type; }
784 784
785 785 void setHasHashFunction(bool on) { m_has_hash_function = on; }
786 786 bool hasHashFunction() const { return m_has_hash_function; }
787 787
788 788 void setToStringCapability(FunctionModelItem fun) { m_qDebug_stream_function= fun; }
789 789 FunctionModelItem hasToStringCapability() const { return m_qDebug_stream_function; }
790 790
791 791 virtual bool hasDefaultToStringFunction() const;
792 792
793 793 void setHasEqualsOperator(bool on) { m_has_equals_operator = on; }
794 794 bool hasEqualsOperator() const { return m_has_equals_operator; }
795 795
796 796 void setHasCloneOperator(bool on) { m_has_clone_operator = on; }
797 797 bool hasCloneOperator() const { return m_has_clone_operator; }
798 798
799 bool hasDefaultIsNull() const;
800
799 801 void addPropertySpec(QPropertySpec *spec) { m_property_specs << spec; }
800 802 QList<QPropertySpec *> propertySpecs() const { return m_property_specs; }
801 803
802 804 QPropertySpec *propertySpecForRead(const QString &name) const;
803 805 QPropertySpec *propertySpecForWrite(const QString &name) const;
804 806 QPropertySpec *propertySpecForReset(const QString &name) const;
805 807
806 808 QList<ReferenceCount> referenceCounts() const;
807 809
808 810 void setEqualsFunctions(const AbstractMetaFunctionList &lst) { m_equals_functions = lst; }
809 811 AbstractMetaFunctionList equalsFunctions() const { return m_equals_functions; }
810 812
811 813 void setNotEqualsFunctions(const AbstractMetaFunctionList &lst) { m_nequals_functions = lst; }
812 814 AbstractMetaFunctionList notEqualsFunctions() const { return m_nequals_functions; }
813 815
814 816 void setLessThanFunctions(const AbstractMetaFunctionList &lst) { m_less_than_functions = lst; }
815 817 AbstractMetaFunctionList lessThanFunctions() const { return m_less_than_functions; }
816 818
817 819 void setGreaterThanFunctions(const AbstractMetaFunctionList &lst) { m_greater_than_functions = lst; }
818 820 AbstractMetaFunctionList greaterThanFunctions() const { return m_greater_than_functions; }
819 821
820 822 void setLessThanEqFunctions(const AbstractMetaFunctionList &lst) { m_less_than_eq_functions = lst; }
821 823 AbstractMetaFunctionList lessThanEqFunctions() const { return m_less_than_eq_functions; }
822 824
823 825 void setGreaterThanEqFunctions(const AbstractMetaFunctionList &lst) { m_greater_than_eq_functions = lst; }
824 826 AbstractMetaFunctionList greaterThanEqFunctions() const { return m_greater_than_eq_functions; }
825 827
826 828 void sortFunctions();
827 829
828 830 const AbstractMetaClass *templateBaseClass() const { return m_template_base_class; }
829 831 void setTemplateBaseClass(const AbstractMetaClass *cls) { m_template_base_class = cls; }
830 832
831 833 void setTypeAlias(bool typeAlias) { m_is_type_alias = typeAlias; }
832 834 bool isTypeAlias() const { return m_is_type_alias; }
833 835
834 836 bool operator <(const AbstractMetaClass &a) const {
835 837 return qualifiedCppName() < a.qualifiedCppName();
836 838 }
837 839
838 840 private:
839 841 uint m_namespace : 1;
840 842 uint m_qobject : 1;
841 843 uint m_has_virtuals : 1;
842 844 uint m_has_nonpublic : 1;
843 845 uint m_has_virtual_slots : 1;
844 846 uint m_has_nonprivateconstructor : 1;
845 847 uint m_functions_fixed : 1;
846 848 uint m_has_public_destructor : 1;
847 849 uint m_force_shell_class : 1;
848 850 uint m_has_hash_function : 1;
849 851 uint m_has_equals_operator : 1;
850 852 uint m_has_clone_operator :1;
851 853 uint m_is_type_alias : 1;
852 854 uint m_reserved : 19;
853 855
854 856 const AbstractMetaClass *m_enclosing_class;
855 857 AbstractMetaClass *m_base_class;
856 858 const AbstractMetaClass *m_template_base_class;
857 859 AbstractMetaFunctionList m_functions;
858 860 AbstractMetaFieldList m_fields;
859 861 AbstractMetaEnumList m_enums;
860 862 AbstractMetaClassList m_interfaces;
861 863 AbstractMetaClass *m_extracted_interface;
862 864 AbstractMetaClass *m_primary_interface_implementor;
863 865 QList<QPropertySpec *> m_property_specs;
864 866 AbstractMetaFunctionList m_equals_functions;
865 867 AbstractMetaFunctionList m_nequals_functions;
866 868
867 869 AbstractMetaFunctionList m_less_than_functions;
868 870 AbstractMetaFunctionList m_greater_than_functions;
869 871 AbstractMetaFunctionList m_less_than_eq_functions;
870 872 AbstractMetaFunctionList m_greater_than_eq_functions;
871 873
872 874 QStringList m_base_class_names;
873 875 QList<TypeEntry *> m_template_args;
874 876 ComplexTypeEntry *m_type_entry;
875 877 FunctionModelItem m_qDebug_stream_function;
876 878 };
877 879
878 880 class QPropertySpec {
879 881 public:
880 882 QPropertySpec(const TypeEntry *type)
881 883 : m_type(type),
882 884 m_index(-1)
883 885 {
884 886 }
885 887
886 888 const TypeEntry *type() const { return m_type; }
887 889
888 890 QString name() const { return m_name; }
889 891 void setName(const QString &name) { m_name = name; }
890 892
891 893 QString read() const { return m_read; }
892 894 void setRead(const QString &read) { m_read = read; }
893 895
894 896 QString write() const { return m_write; }
895 897 void setWrite(const QString &write) { m_write = write; }
896 898
897 899 QString designable() const { return m_designable; }
898 900 void setDesignable(const QString &designable) { m_designable = designable; }
899 901
900 902 QString reset() const { return m_reset; }
901 903 void setReset(const QString &reset) { m_reset = reset; }
902 904
903 905 int index() const { return m_index; }
904 906 void setIndex(int index) { m_index = index; }
905 907
906 908 private:
907 909 QString m_name;
908 910 QString m_read;
909 911 QString m_write;
910 912 QString m_designable;
911 913 QString m_reset;
912 914 const TypeEntry *m_type;
913 915 int m_index;
914 916 };
915 917
916 918 inline AbstractMetaFunctionList AbstractMetaClass::allVirtualFunctions() const
917 919 {
918 920 return queryFunctions(VirtualFunctions
919 921 | NotRemovedFromTargetLang);
920 922 }
921 923
922 924 inline AbstractMetaFunctionList AbstractMetaClass::allFinalFunctions() const
923 925 {
924 926 return queryFunctions(FinalInTargetLangFunctions
925 927 | FinalInCppFunctions
926 928 | NotRemovedFromTargetLang);
927 929 }
928 930
929 931 inline AbstractMetaFunctionList AbstractMetaClass::cppInconsistentFunctions() const
930 932 {
931 933 return queryFunctions(Inconsistent
932 934 | NormalFunctions
933 935 | Visible
934 936 | NotRemovedFromTargetLang);
935 937 }
936 938
937 939 inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
938 940 {
939 941 return queryFunctions(Signals
940 942 | Visible
941 943 | NotRemovedFromTargetLang);
942 944 }
943 945
944 946 #endif // ABSTRACTMETALANG_H
@@ -1,235 +1,297
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #include "setupgenerator.h"
43 43 #include "shellgenerator.h"
44 44 #include "reporthandler.h"
45 45 #include "fileout.h"
46 46
47 47 //#define Q_SCRIPT_LAZY_GENERATOR
48 48
49 49 void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls)
50 50 {
51 51 packHash[package].append(cls);
52 52 }
53 53
54 54 void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
55 55 QSet<QString> &registeredTypeNames);
56 56 bool hasDefaultConstructor(const AbstractMetaClass *meta_class);
57 57
58 static QStringList getOperatorCodes(const AbstractMetaClass* cls) {
59 QSet<QString> operatorCodes;
60 AbstractMetaFunctionList returned;
61 AbstractMetaFunctionList functions = cls->functions();
62 foreach (AbstractMetaFunction *function, functions) {
63 if (function->originalName().startsWith("operator")) {
64 QString op = function->originalName().mid(8);
65 operatorCodes.insert(op);
66 }
67 }
68 QSet<QString> r;
69 foreach(QString op, operatorCodes.toList()) {
70 if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") {
71 r.insert("PythonQt::Type_RichCompare");
72 } else if (op == "+") {
73 r.insert("PythonQt::Type_Add");
74 } else if (op == "-") {
75 r.insert("PythonQt::Type_Subtract");
76 } else if (op == "/") {
77 r.insert("PythonQt::Type_Divide");
78 } else if (op == "*") {
79 r.insert("PythonQt::Type_Multiply");
80 } else if (op == "%") {
81 r.insert("PythonQt::Type_Mod");
82 } else if (op == "&") {
83 r.insert("PythonQt::Type_And");
84 } else if (op == "|") {
85 r.insert("PythonQt::Type_Or");
86 } else if (op == "^") {
87 r.insert("PythonQt::Type_Xor");
88 } else if (op == "~") {
89 r.insert("PythonQt::Type_Invert");
90
91 } else if (op == "+=") {
92 r.insert("PythonQt::Type_InplaceAdd");
93 } else if (op == "-=") {
94 r.insert("PythonQt::Type_InplaceSubtract");
95 } else if (op == "/=") {
96 r.insert("PythonQt::Type_InplaceDivide");
97 } else if (op == "*=") {
98 r.insert("PythonQt::Type_InplaceMultiply");
99 } else if (op == "%=") {
100 r.insert("PythonQt::Type_InplaceMod");
101 } else if (op == "&=") {
102 r.insert("PythonQt::Type_InplaceAnd");
103 } else if (op == "|=") {
104 r.insert("PythonQt::Type_InplaceOr");
105 } else if (op == "^=") {
106 r.insert("PythonQt::Type_InplaceXor");
107 }
108 }
109 if (cls->hasDefaultIsNull()) {
110 r.insert("PythonQt::Type_NonZero");
111 }
112 QStringList result = r.toList();
113 return result;
114 }
115
58 116 void SetupGenerator::generate()
59 117 {
60 118 AbstractMetaClassList classes_with_polymorphic_id;
61 119 {
62 120 QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
63 121 while (pack.hasNext()) {
64 122 pack.next();
65 123 QList<const AbstractMetaClass*> list = pack.value();
66 124 foreach (const AbstractMetaClass *cls, list) {
67 125 if (cls->typeEntry()->isPolymorphicBase()) {
68 126 classes_with_polymorphic_id.append((AbstractMetaClass*)cls);
69 127 }
70 128 }
71 129 }
72 130 }
73 131
74 132 QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
75 133 while (pack.hasNext()) {
76 134 pack.next();
77 135 QList<const AbstractMetaClass*> list = pack.value();
78 136 if (list.isEmpty())
79 137 continue;
80 138
81 139 QString packKey = pack.key();
82 140 QString packName = pack.key();
83 141 QStringList components = packName.split("_");
84 142 if ((components.size() > 2) && (components.at(0) == "com")
85 143 && (components.at(1) == "trolltech")) {
86 144 // kill com.trolltech in key
87 145 components.removeAt(0);
88 146 components.removeAt(0);
89 147 }
90 148
91 149 QString shortPackName;
92 150 foreach (QString comp, components) {
93 151 comp[0] = comp[0].toUpper();
94 152 shortPackName += comp;
95 153 }
96 154 // add missing camel case (workaround..)
97 155 if (shortPackName == "QtWebkit") {
98 156 shortPackName = "QtWebKit";
99 157 } else if (shortPackName == "QtXmlpatterns") {
100 158 shortPackName = "QtXmlPatterns";
101 159 } else if (shortPackName == "QtOpengl") {
102 160 shortPackName = "QtOpenGL";
103 161 } else if (shortPackName == "QtUitools") {
104 162 shortPackName = "QtUiTools";
105 163 }
106 164
107 165
108 166 {
109 167 FileOut initFile(m_out_dir + "/generated_cpp/" + packName + "/" + packKey + "_init.cpp");
110 168 QTextStream &s = initFile.stream;
111 169
112 170 s << "#include <PythonQt.h>" << endl;
113 171
114 172 for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) {
115 173 s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl;
116 174 }
117 175 s << endl;
118 176
119 177 QStringList polymorphicHandlers;
120 178 if (!packName.endsWith("_builtin")) {
121 179 polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id);
122 180 s << endl;
123 181 }
124 182
125 183 // declare individual class creation functions
126 184 s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl;
127 185
128 186 if (shortPackName.endsWith("Builtin")) {
129 187 shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin"));
130 188 }
131 189
132 190 QStringList cppClassNames;
133 191 foreach (const AbstractMetaClass *cls, list) {
134 192
135 193 QString shellCreator;
136 194 if (cls->generateShellClass()) {
137 195 shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">";
138 196 } else {
139 197 shellCreator = ", NULL";
140 198 }
199 QString operatorCodes = getOperatorCodes(cls).join("|");
200 if (operatorCodes.isEmpty()) {
201 operatorCodes = "0";
202 }
141 203 if (cls->isQObject()) {
142 s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module);" << endl;
204 s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
143 205 } else {
144 206 QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
145 s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module);" << endl;
207 s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
146 208 }
147 209 foreach(AbstractMetaClass* interface, cls->interfaces()) {
148 210 // the interface might be our own class... (e.g. QPaintDevice)
149 211 if (interface->qualifiedCppName() != cls->qualifiedCppName()) {
150 212 s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<<interface->qualifiedCppName()<<">());" << endl;
151 213 }
152 214 }
153 215 }
154 216 s << endl;
155 217 foreach (QString handler, polymorphicHandlers) {
156 218 s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl;
157 219 }
158 220
159 221 s << "}";
160 222 s << endl;
161 223 }
162 224 }
163 225 }
164 226
165 227 QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package,
166 228 const AbstractMetaClassList &classes)
167 229 {
168 230 QStringList handlers;
169 231 foreach (AbstractMetaClass *cls, classes) {
170 232 const ComplexTypeEntry *centry = cls->typeEntry();
171 233 if (!centry->isPolymorphicBase())
172 234 continue;
173 235 bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem");
174 236
175 237 AbstractMetaClassList classList = this->classes();
176 238 bool first = true;
177 239 foreach (AbstractMetaClass *clazz, classList) {
178 240 bool inherits = false;
179 241 if (isGraphicsItem) {
180 242 foreach(AbstractMetaClass* interfaze, clazz->interfaces()) {
181 243 if (interfaze->qualifiedCppName()=="QGraphicsItem") {
182 244 inherits = true;
183 245 break;
184 246 }
185 247 }
186 248 } else {
187 249 inherits = clazz->inheritsFrom(cls);
188 250 }
189 251 if (clazz->package() == package && inherits) {
190 252 if (!clazz->typeEntry()->polymorphicIdValue().isEmpty() || isGraphicsItem) {
191 253 // On first find, open the function
192 254 if (first) {
193 255 first = false;
194 256
195 257 QString handler = cls->name();
196 258 handlers.append(handler);
197 259
198 260 s << "static void* polymorphichandler_" << handler
199 261 << "(const void *ptr, char **class_name)" << endl
200 262 << "{" << endl
201 263 << " Q_ASSERT(ptr != 0);" << endl
202 264 << " " << cls->qualifiedCppName() << " *object = ("
203 265 << cls->qualifiedCppName() << " *)ptr;" << endl;
204 266 }
205 267
206 268 // For each, add case label
207 269 QString polyId = clazz->typeEntry()->polymorphicIdValue();
208 270 if (isGraphicsItem) {
209 271 polyId = "%1->type() == " + clazz->qualifiedCppName() + "::Type";
210 272 }
211 273 s << " if ("
212 274 << polyId.replace("%1", "object")
213 275 << ") {" << endl
214 276 << " *class_name = \"" << clazz->name() << "\";" << endl
215 277 << " return (" << clazz->qualifiedCppName() << "*)object;" << endl
216 278 << " }" << endl;
217 279 } else {
218 280 QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set")
219 281 .arg(clazz->name())
220 282 .arg(cls->name());
221 283
222 284 ReportHandler::warning(warning);
223 285 }
224 286 }
225 287 }
226 288
227 289 // Close the function if it has been opened
228 290 if (!first) {
229 291 s << " return NULL;" << endl
230 292 << "}" << endl;
231 293 }
232 294 }
233 295
234 296 return handlers;
235 297 }
@@ -1,310 +1,313
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 4 ** All rights reserved.
5 5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 6 **
7 7 ** This file is part of the Qt Script Generator project on Qt Labs.
8 8 **
9 9 ** $QT_BEGIN_LICENSE:LGPL$
10 10 ** No Commercial Usage
11 11 ** This file contains pre-release code and may not be distributed.
12 12 ** You may use this file in accordance with the terms and conditions
13 13 ** contained in the Technology Preview License Agreement accompanying
14 14 ** this package.
15 15 **
16 16 ** GNU Lesser General Public License Usage
17 17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 18 ** General Public License version 2.1 as published by the Free Software
19 19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 20 ** packaging of this file. Please review the following information to
21 21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 23 **
24 24 ** In addition, as a special exception, Nokia gives you certain additional
25 25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 27 **
28 28 ** If you have questions regarding the use of this file, please contact
29 29 ** Nokia at qt-info@nokia.com.
30 30 **
31 31 **
32 32 **
33 33 **
34 34 **
35 35 **
36 36 **
37 37 **
38 38 ** $QT_END_LICENSE$
39 39 **
40 40 ****************************************************************************/
41 41
42 42 #include "shellheadergenerator.h"
43 43 #include "fileout.h"
44 44
45 45 #include <QtCore/QDir>
46 46
47 47 #include <qdebug.h>
48 48
49 49 QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
50 50 {
51 51 return QString("PythonQtWrapper_%1.h").arg(meta_class->name());
52 52 }
53 53
54 54
55 55 void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMetaField *field)
56 56 {
57 57 const AbstractMetaFunction *setter = field->setter();
58 58 const AbstractMetaFunction *getter = field->getter();
59 59
60 60 // static fields are not supported (yet?)
61 61 if (setter->isStatic()) return;
62 62
63 63 // Uuid data4 did not work (TODO: move to typesystem...(
64 64 if (field->enclosingClass()->name()=="QUuid" && setter->name()=="data4") return;
65 65 if (field->enclosingClass()->name()=="QIPv6Address") return;
66 66
67 67 if (!field->type()->isConstant()) {
68 68 writeFunctionSignature(s, setter, 0, QString(),
69 69 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | ShowStatic | UnderscoreSpaces));
70 70 s << "{ theWrappedObject->" << field->name() << " = " << setter->arguments()[0]->argumentName() << "; }\n";
71 71 }
72 72
73 73 writeFunctionSignature(s, getter, 0, QString(),
74 74 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
75 75 s << "{ return theWrappedObject->" << field->name() << "; }\n";
76 76 }
77 77
78 78 void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
79 79 {
80 80 QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":"";
81 81 QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri";
82 82 priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
83 83 setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class);
84 84
85 85 QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H";
86 86
87 87 s << "#ifndef " << include_block << endl
88 88 << "#define " << include_block << endl << endl;
89 89
90 90 Include inc = meta_class->typeEntry()->include();
91 91 ShellGenerator::writeInclude(s, inc);
92 92
93 93 s << "#include <QObject>" << endl << endl;
94 94 s << "#include <PythonQt.h>" << endl << endl;
95 95
96 96 IncludeList list = meta_class->typeEntry()->extraIncludes();
97 97 qSort(list.begin(), list.end());
98 98 foreach (const Include &inc, list) {
99 99 ShellGenerator::writeInclude(s, inc);
100 100 }
101 101 s << endl;
102 102
103 103 AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
104 104 | AbstractMetaClass::WasVisible
105 105 | AbstractMetaClass::NotRemovedFromTargetLang);
106 106
107 107 // Shell-------------------------------------------------------------------
108 108 if (meta_class->generateShellClass()) {
109 109
110 110 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
111 111
112 112 s << "class " << shellClassName(meta_class)
113 113 << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl;
114 114 s << "public:" << endl;
115 115 foreach(AbstractMetaFunction* fun, ctors) {
116 116 s << " ";
117 117 writeFunctionSignature(s, fun, 0,"PythonQtShell_",
118 118 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
119 119 s << ":" << meta_class->qualifiedCppName() << "(";
120 120 QString scriptFunctionName = fun->originalName();
121 121 AbstractMetaArgumentList args = fun->arguments();
122 122 for (int i = 0; i < args.size(); ++i) {
123 123 if (i > 0)
124 124 s << ", ";
125 125 s << args.at(i)->argumentName();
126 126 }
127 127 s << "),_wrapper(NULL) {};" << endl;
128 128 }
129 129 s << endl;
130 130
131 131 foreach(AbstractMetaFunction* fun, virtualsForShell) {
132 132 s << "virtual ";
133 133 writeFunctionSignature(s, fun, 0, QString(),
134 134 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
135 135 s << ";" << endl;
136 136 }
137 137 s << endl;
138 138 s << " PythonQtInstanceWrapper* _wrapper; " << endl;
139 139
140 140 s << "};" << endl << endl;
141 141 }
142 142
143 143 // Promoter-------------------------------------------------------------------
144 144 AbstractMetaFunctionList promoteFunctions = getProtectedFunctionsThatNeedPromotion(meta_class);
145 145 if (!promoteFunctions.isEmpty()) {
146 146 s << "class " << promoterClassName(meta_class)
147 147 << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl;
148 148
149 149 foreach(AbstractMetaFunction* fun, promoteFunctions) {
150 150 s << "inline ";
151 151 writeFunctionSignature(s, fun, 0, "promoted_",
152 152 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
153 153 s << " { ";
154 154 QString scriptFunctionName = fun->originalName();
155 155 AbstractMetaArgumentList args = fun->arguments();
156 156 if (fun->type())
157 157 s << "return ";
158 158 s << meta_class->qualifiedCppName() << "::";
159 159 s << fun->originalName() << "(";
160 160 for (int i = 0; i < args.size(); ++i) {
161 161 if (i > 0)
162 162 s << ", ";
163 163 s << args.at(i)->argumentName();
164 164 }
165 165 s << "); }" << endl;
166 166 }
167 167
168 168 s << "};" << endl << endl;
169 169 }
170 170
171 171 // Wrapper-------------------------------------------------------------------
172 172
173 173 s << "class " << wrapperClassName(meta_class)
174 174 << " : public QObject" << endl
175 175 << "{ Q_OBJECT" << endl;
176 176
177 177 s << "public:" << endl;
178 178
179 179 AbstractMetaEnumList enums1 = meta_class->enums();
180 180 AbstractMetaEnumList enums;
181 181 QList<FlagsTypeEntry*> flags;
182 182 foreach(AbstractMetaEnum* enum1, enums1) {
183 183 // catch gadgets and enums that are not exported on QObjects...
184 184 if (enum1->wasPublic() && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration())) {
185 185 enums << enum1;
186 186 if (enum1->typeEntry()->flags()) {
187 187 flags << enum1->typeEntry()->flags();
188 188 }
189 189 }
190 190 }
191 191 if (enums.count()) {
192 192 s << "Q_ENUMS(";
193 193 foreach(AbstractMetaEnum* enum1, enums) {
194 194 s << enum1->name() << " ";
195 195 }
196 196 s << ")" << endl;
197 197
198 198 if (flags.count()) {
199 199 s << "Q_FLAGS(";
200 200 foreach(FlagsTypeEntry* flag1, flags) {
201 201 QString origName = flag1->originalName();
202 202 int idx = origName.lastIndexOf("::");
203 203 if (idx!= -1) {
204 204 origName = origName.mid(idx+2);
205 205 }
206 206 s << origName << " ";
207 207 }
208 208 s << ")" << endl;
209 209 }
210 210
211 211 foreach(AbstractMetaEnum* enum1, enums) {
212 212 s << "enum " << enum1->name() << "{" << endl;
213 213 bool first = true;
214 214 foreach(AbstractMetaEnumValue* value, enum1->values()) {
215 215 if (first) { first = false; }
216 216 else { s << ", "; }
217 217 s << " " << value->name() << " = " << meta_class->qualifiedCppName() << "::" << value->name();
218 218 }
219 219 s << "};" << endl;
220 220 }
221 221 if (flags.count()) {
222 222 foreach(AbstractMetaEnum* enum1, enums) {
223 223 if (enum1->typeEntry()->flags()) {
224 224 QString origName = enum1->typeEntry()->flags()->originalName();
225 225 int idx = origName.lastIndexOf("::");
226 226 if (idx!= -1) {
227 227 origName = origName.mid(idx+2);
228 228 }
229 229 s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<<endl;
230 230 }
231 231 }
232 232 }
233 233 }
234 234 s << "public slots:" << endl;
235 235 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
236 236
237 237 bool copyConstructorSeen = false;
238 238 bool defaultConstructorSeen = false;
239 239 foreach (const AbstractMetaFunction *fun, ctors) {
240 240 if (!fun->isPublic() || fun->isAbstract()) { continue; }
241 241 s << meta_class->qualifiedCppName() << "* ";
242 242 writeFunctionSignature(s, fun, 0, "new_",
243 243 Option(IncludeDefaultExpression | OriginalName | ShowStatic));
244 244 s << ";" << endl;
245 245 if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) {
246 246 copyConstructorSeen = true;
247 247 }
248 248 if (fun->arguments().size()==0) {
249 249 defaultConstructorSeen = true;
250 250 }
251 251 }
252 252
253 253 if (meta_class->typeEntry()->isValue()
254 254 && !copyConstructorSeen && defaultConstructorSeen) {
255 255 QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName();
256 256 s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl;
257 257 s << className << "* a = new " << className << "();" << endl;
258 258 s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl;
259 259 s << "return a; }" << endl;
260 260 }
261 261 }
262 262 if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) {
263 263 s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } ";
264 264 s << endl;
265 265 }
266 266 if (meta_class->name()=="QTreeWidgetItem") {
267 267 s << "bool py_hasOwner(QTreeWidgetItem* theWrappedObject) { return theWrappedObject->treeWidget()!=NULL || theWrappedObject->parent()!=NULL; }" << endl;
268 268 } else if (meta_class->name()=="QGraphicsItem") {
269 269 s << "bool py_hasOwner(QGraphicsItem* theWrappedObject) { return theWrappedObject->scene()!=NULL || theWrappedObject->parentItem()!=NULL; }" << endl;
270 270 }
271 271
272 272 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
273 273
274 274 foreach (const AbstractMetaFunction *function, functions) {
275 275 if (!function->isSlot()) {
276 276 s << " ";
277 277 writeFunctionSignature(s, function, 0, QString(),
278 278 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
279 279 s << ";" << endl;
280 280 }
281 281 }
282 282 if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) {
283 283 s << " QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl;
284 284 }
285 if (meta_class->hasDefaultIsNull()) {
286 s << " bool __nonzero__(" << meta_class->qualifiedCppName() << "* obj) { return !obj->isNull(); }" << endl;
287 }
285 288
286 289 // Field accessors
287 290 foreach (const AbstractMetaField *field, meta_class->fields()) {
288 291 if (field->isPublic()) {
289 292 writeFieldAccessors(s, field);
290 293 }
291 294 }
292 295
293 296 // writeInjectedCode(s, meta_class);
294 297
295 298 // s << endl << " QScriptValue __qtscript_self;" << endl;
296 299
297 300 s << "};" << endl << endl
298 301 << "#endif // " << include_block << endl;
299 302
300 303 }
301 304
302 305 void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
303 306 {
304 307 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
305 308 foreach (const CodeSnip &cs, code_snips) {
306 309 if (cs.language == TypeSystem::ShellDeclaration) {
307 310 s << cs.code() << endl;
308 311 }
309 312 }
310 313 }
@@ -1,1217 +1,1219
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 "PythonQt.h"
43 43 #include "PythonQtImporter.h"
44 44 #include "PythonQtClassInfo.h"
45 45 #include "PythonQtMethodInfo.h"
46 46 #include "PythonQtSignalReceiver.h"
47 47 #include "PythonQtConversion.h"
48 48 #include "PythonQtStdOut.h"
49 49 #include "PythonQtCppWrapperFactory.h"
50 50 #include "PythonQtVariants.h"
51 51 #include "PythonQtStdDecorators.h"
52 52 #include "PythonQtQFileImporter.h"
53 53 #include <pydebug.h>
54 54 #include <vector>
55 55
56 56 PythonQt* PythonQt::_self = NULL;
57 57 int PythonQt::_uniqueModuleCount = 0;
58 58
59 59 void PythonQt_init_QtGuiBuiltin(PyObject*);
60 60 void PythonQt_init_QtCoreBuiltin(PyObject*);
61 61
62 62 void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
63 63 {
64 64 if (!_self) {
65 65 _self = new PythonQt(flags, pythonQtModuleName);
66 66
67 67 PythonQtMethodInfo::addParameterTypeAlias("QObjectList", "QList<QObject*>");
68 68 qRegisterMetaType<QList<QObject*> >("QList<void*>");
69 69
70 70 PythonQtRegisterToolClassesTemplateConverter(int);
71 71 PythonQtRegisterToolClassesTemplateConverter(float);
72 72 PythonQtRegisterToolClassesTemplateConverter(double);
73 73 PythonQtRegisterToolClassesTemplateConverter(qint32);
74 74 PythonQtRegisterToolClassesTemplateConverter(quint32);
75 75 PythonQtRegisterToolClassesTemplateConverter(qint64);
76 76 PythonQtRegisterToolClassesTemplateConverter(quint64);
77 77 // TODO: which other POD types should be available for QList etc.
78 78
79 79 PythonQt::self()->addDecorators(new PythonQtStdDecorators());
80 80
81 81 PythonQt_init_QtCoreBuiltin(NULL);
82 82 PythonQt_init_QtGuiBuiltin(NULL);
83 83
84 84 PythonQtRegisterToolClassesTemplateConverter(QDate);
85 85 PythonQtRegisterToolClassesTemplateConverter(QTime);
86 86 PythonQtRegisterToolClassesTemplateConverter(QDateTime);
87 87 PythonQtRegisterToolClassesTemplateConverter(QUrl);
88 88 PythonQtRegisterToolClassesTemplateConverter(QLocale);
89 89 PythonQtRegisterToolClassesTemplateConverter(QRect);
90 90 PythonQtRegisterToolClassesTemplateConverter(QRectF);
91 91 PythonQtRegisterToolClassesTemplateConverter(QSize);
92 92 PythonQtRegisterToolClassesTemplateConverter(QSizeF);
93 93 PythonQtRegisterToolClassesTemplateConverter(QLine);
94 94 PythonQtRegisterToolClassesTemplateConverter(QLineF);
95 95 PythonQtRegisterToolClassesTemplateConverter(QPoint);
96 96 PythonQtRegisterToolClassesTemplateConverter(QPointF);
97 97 PythonQtRegisterToolClassesTemplateConverter(QRegExp);
98 98
99 99 PythonQtRegisterToolClassesTemplateConverter(QFont);
100 100 PythonQtRegisterToolClassesTemplateConverter(QPixmap);
101 101 PythonQtRegisterToolClassesTemplateConverter(QBrush);
102 102 PythonQtRegisterToolClassesTemplateConverter(QColor);
103 103 PythonQtRegisterToolClassesTemplateConverter(QPalette);
104 104 PythonQtRegisterToolClassesTemplateConverter(QIcon);
105 105 PythonQtRegisterToolClassesTemplateConverter(QImage);
106 106 PythonQtRegisterToolClassesTemplateConverter(QPolygon);
107 107 PythonQtRegisterToolClassesTemplateConverter(QRegion);
108 108 PythonQtRegisterToolClassesTemplateConverter(QBitmap);
109 109 PythonQtRegisterToolClassesTemplateConverter(QCursor);
110 110 PythonQtRegisterToolClassesTemplateConverter(QSizePolicy);
111 111 PythonQtRegisterToolClassesTemplateConverter(QKeySequence);
112 112 PythonQtRegisterToolClassesTemplateConverter(QPen);
113 113 PythonQtRegisterToolClassesTemplateConverter(QTextLength);
114 114 PythonQtRegisterToolClassesTemplateConverter(QTextFormat);
115 115 PythonQtRegisterToolClassesTemplateConverter(QMatrix);
116 116
117 117
118 118 PyObject* pack = PythonQt::priv()->packageByName("QtCore");
119 119 PyObject* pack2 = PythonQt::priv()->packageByName("Qt");
120 120 PyObject* qtNamespace = PythonQt::priv()->getClassInfo("Qt")->pythonQtClassWrapper();
121 121 const char* names[16] = {"SIGNAL", "SLOT", "qAbs", "qBound","qDebug","qWarning","qCritical","qFatal"
122 122 ,"qFuzzyCompare", "qMax","qMin","qRound","qRound64","qVersion","qrand","qsrand"};
123 123 for (unsigned int i = 0;i<16; i++) {
124 124 PyObject* obj = PyObject_GetAttrString(qtNamespace, names[i]);
125 125 if (obj) {
126 126 PyModule_AddObject(pack, names[i], obj);
127 127 Py_INCREF(obj);
128 128 PyModule_AddObject(pack2, names[i], obj);
129 129 } else {
130 130 std::cerr << "method not found " << names[i];
131 131 }
132 132 }
133 133 }
134 134 }
135 135
136 136 void PythonQt::cleanup()
137 137 {
138 138 if (_self) {
139 139 delete _self;
140 140 _self = NULL;
141 141 }
142 142 }
143 143
144 144 PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName)
145 145 {
146 146 _p = new PythonQtPrivate;
147 147 _p->_initFlags = flags;
148 148
149 149 _p->_PythonQtObjectPtr_metaId = qRegisterMetaType<PythonQtObjectPtr>("PythonQtObjectPtr");
150 150
151 151 Py_SetProgramName("PythonQt");
152 152 if (flags & IgnoreSiteModule) {
153 153 // this prevents the automatic importing of Python site files
154 154 Py_NoSiteFlag = 1;
155 155 }
156 156 Py_Initialize();
157 157
158 158 // add our own python object types for qt object slots
159 159 if (PyType_Ready(&PythonQtSlotFunction_Type) < 0) {
160 160 std::cerr << "could not initialize PythonQtSlotFunction_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
161 161 }
162 162 Py_INCREF(&PythonQtSlotFunction_Type);
163 163
164 164 // according to Python docs, set the type late here, since it can not safely be stored in the struct when declaring it
165 165 PythonQtClassWrapper_Type.tp_base = &PyType_Type;
166 166 // add our own python object types for classes
167 167 if (PyType_Ready(&PythonQtClassWrapper_Type) < 0) {
168 168 std::cerr << "could not initialize PythonQtClassWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
169 169 }
170 170 Py_INCREF(&PythonQtClassWrapper_Type);
171 171
172 172 // add our own python object types for CPP instances
173 173 if (PyType_Ready(&PythonQtInstanceWrapper_Type) < 0) {
174 174 PythonQt::handleError();
175 175 std::cerr << "could not initialize PythonQtInstanceWrapper_Type" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
176 176 }
177 177 Py_INCREF(&PythonQtInstanceWrapper_Type);
178 178
179 179 // add our own python object types for redirection of stdout
180 180 if (PyType_Ready(&PythonQtStdOutRedirectType) < 0) {
181 181 std::cerr << "could not initialize PythonQtStdOutRedirectType" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
182 182 }
183 183 Py_INCREF(&PythonQtStdOutRedirectType);
184 184
185 185 initPythonQtModule(flags & RedirectStdOut, pythonQtModuleName);
186 186
187 187 _p->setupSharedLibrarySuffixes();
188 188
189 189 }
190 190
191 191 PythonQt::~PythonQt() {
192 192 delete _p;
193 193 _p = NULL;
194 194 }
195 195
196 196 PythonQtPrivate::~PythonQtPrivate() {
197 197 delete _defaultImporter;
198 198 _defaultImporter = NULL;
199 199
200 200 {
201 201 QHashIterator<QByteArray, PythonQtClassInfo *> i(_knownClassInfos);
202 202 while (i.hasNext()) {
203 203 delete i.next().value();
204 204 }
205 205 }
206 206 PythonQtConv::global_valueStorage.clear();
207 207 PythonQtConv::global_ptrStorage.clear();
208 208 PythonQtConv::global_variantStorage.clear();
209 209
210 210 PythonQtMethodInfo::cleanupCachedMethodInfos();
211 211 }
212 212
213 213 PythonQtImportFileInterface* PythonQt::importInterface()
214 214 {
215 215 return _self->_p->_importInterface?_self->_p->_importInterface:_self->_p->_defaultImporter;
216 216 }
217 217
218 218 void PythonQt::qObjectNoLongerWrappedCB(QObject* o)
219 219 {
220 220 if (_self->_p->_noLongerWrappedCB) {
221 221 (*_self->_p->_noLongerWrappedCB)(o);
222 222 };
223 223 }
224 224
225 225 void PythonQt::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
226 226 {
227 227 _p->registerClass(metaobject, package, wrapperCreator, shell);
228 228 }
229 229
230 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module)
230 void PythonQtPrivate::registerClass(const QMetaObject* metaobject, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
231 231 {
232 232 // we register all classes in the hierarchy
233 233 const QMetaObject* m = metaobject;
234 234 bool first = true;
235 235 while (m) {
236 236 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(m->className());
237 237 if (!info->pythonQtClassWrapper()) {
238 info->setTypeSlots(typeSlots);
238 239 info->setupQObject(m);
239 240 createPythonQtClassWrapper(info, package, module);
240 241 if (m->superClass()) {
241 242 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(m->superClass()->className());
242 243 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo));
243 244 }
244 245 }
245 246 if (first) {
246 247 first = false;
247 248 if (wrapperCreator) {
248 249 info->setDecoratorProvider(wrapperCreator);
249 250 }
250 251 if (shell) {
251 252 info->setShellSetInstanceWrapperCB(shell);
252 253 }
253 254 }
254 255 m = m->superClass();
255 256 }
256 257 }
257 258
258 259 void PythonQtPrivate::createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module)
259 260 {
260 261 PyObject* pack = module?module:packageByName(package);
261 262 PyObject* pyobj = (PyObject*)createNewPythonQtClassWrapper(info, pack);
262 263 PyModule_AddObject(pack, info->className(), pyobj);
263 264 if (!module && package && strncmp(package,"Qt",2)==0) {
264 265 // since PyModule_AddObject steals the reference, we need a incref once more...
265 266 Py_INCREF(pyobj);
266 267 // put all qt objects into Qt as well
267 268 PyModule_AddObject(packageByName("Qt"), info->className(), pyobj);
268 269 }
269 270 info->setPythonQtClassWrapper(pyobj);
270 271 }
271 272
272 273 PyObject* PythonQtPrivate::wrapQObject(QObject* obj)
273 274 {
274 275 if (!obj) {
275 276 Py_INCREF(Py_None);
276 277 return Py_None;
277 278 }
278 279 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(obj);
279 280 if (!wrap) {
280 281 // smuggling it in...
281 282 PythonQtClassInfo* classInfo = _knownClassInfos.value(obj->metaObject()->className());
282 283 if (!classInfo || classInfo->pythonQtClassWrapper()==NULL) {
283 284 registerClass(obj->metaObject());
284 285 classInfo = _knownClassInfos.value(obj->metaObject()->className());
285 286 }
286 287 wrap = createNewPythonQtInstanceWrapper(obj, classInfo);
287 288 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
288 289 } else {
289 290 Py_INCREF(wrap);
290 291 // mlabDebugConst("MLABPython","qobject wrapper reused " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
291 292 }
292 293 return (PyObject*)wrap;
293 294 }
294 295
295 296 PyObject* PythonQtPrivate::wrapPtr(void* ptr, const QByteArray& name)
296 297 {
297 298 if (!ptr) {
298 299 Py_INCREF(Py_None);
299 300 return Py_None;
300 301 }
301 302
302 303 PythonQtInstanceWrapper* wrap = findWrapperAndRemoveUnused(ptr);
303 304 if (!wrap) {
304 305 PythonQtClassInfo* info = _knownClassInfos.value(name);
305 306 if (!info) {
306 307 // maybe it is a PyObject, which we can return directly
307 308 if (name == "PyObject") {
308 309 PyObject* p = (PyObject*)ptr;
309 310 Py_INCREF(p);
310 311 return p;
311 312 }
312 313
313 314 // we do not know the metaobject yet, but we might know it by it's name:
314 315 if (_knownQObjectClassNames.find(name)!=_knownQObjectClassNames.end()) {
315 316 // yes, we know it, so we can convert to QObject
316 317 QObject* qptr = (QObject*)ptr;
317 318 registerClass(qptr->metaObject());
318 319 info = _knownClassInfos.value(qptr->metaObject()->className());
319 320 }
320 321 }
321 322 if (info && info->isQObject()) {
322 323 QObject* qptr = (QObject*)ptr;
323 324 // if the object is a derived object, we want to switch the class info to the one of the derived class:
324 325 if (name!=(qptr->metaObject()->className())) {
325 326 registerClass(qptr->metaObject());
326 327 info = _knownClassInfos.value(qptr->metaObject()->className());
327 328 }
328 329 wrap = createNewPythonQtInstanceWrapper(qptr, info);
329 330 // mlabDebugConst("MLABPython","new qobject wrapper added " << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
330 331 return (PyObject*)wrap;
331 332 }
332 333
333 334 // not a known QObject, so try our wrapper factory:
334 335 QObject* wrapper = NULL;
335 336 for (int i=0; i<_cppWrapperFactories.size(); i++) {
336 337 wrapper = _cppWrapperFactories.at(i)->create(name, ptr);
337 338 if (wrapper) {
338 339 break;
339 340 }
340 341 }
341 342
342 343 if (info) {
343 344 // try to downcast in the class hierarchy, which will modify info and ptr if it is successfull
344 345 ptr = info->castDownIfPossible(ptr, &info);
345 346 }
346 347
347 348 if (!info || info->pythonQtClassWrapper()==NULL) {
348 349 // still unknown, register as CPP class
349 350 registerCPPClass(name.constData());
350 351 info = _knownClassInfos.value(name);
351 352 }
352 353 if (wrapper && (info->metaObject() != wrapper->metaObject())) {
353 354 // if we a have a QObject wrapper and the metaobjects do not match, set the metaobject again!
354 355 info->setMetaObject(wrapper->metaObject());
355 356 }
356 357 wrap = createNewPythonQtInstanceWrapper(wrapper, info, ptr);
357 358 // mlabDebugConst("MLABPython","new c++ wrapper added " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
358 359 } else {
359 360 Py_INCREF(wrap);
360 361 //mlabDebugConst("MLABPython","c++ wrapper reused " << wrap->_wrappedPtr << " " << wrap->_obj->className() << " " << wrap->classInfo()->wrappedClassName().latin1());
361 362 }
362 363 return (PyObject*)wrap;
363 364 }
364 365
365 366 PyObject* PythonQtPrivate::dummyTuple() {
366 367 static PyObject* dummyTuple = NULL;
367 368 if (dummyTuple==NULL) {
368 369 dummyTuple = PyTuple_New(1);
369 370 PyTuple_SET_ITEM(dummyTuple, 0 , PyString_FromString("dummy"));
370 371 }
371 372 return dummyTuple;
372 373 }
373 374
374 375
375 376 PythonQtInstanceWrapper* PythonQtPrivate::createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr) {
376 377 // call the associated class type to create a new instance...
377 378 PythonQtInstanceWrapper* result = (PythonQtInstanceWrapper*)PyObject_Call(info->pythonQtClassWrapper(), dummyTuple(), NULL);
378 379
379 380 result->setQObject(obj);
380 381 result->_wrappedPtr = wrappedPtr;
381 382 result->_ownedByPythonQt = false;
382 383 result->_useQMetaTypeDestroy = false;
383 384
384 385 if (wrappedPtr) {
385 386 _wrappedObjects.insert(wrappedPtr, result);
386 387 } else {
387 388 _wrappedObjects.insert(obj, result);
388 389 if (obj->parent()== NULL && _wrappedCB) {
389 390 // tell someone who is interested that the qobject is wrapped the first time, if it has no parent
390 391 (*_wrappedCB)(obj);
391 392 }
392 393 }
393 394 return result;
394 395 }
395 396
396 397 PythonQtClassWrapper* PythonQtPrivate::createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* parentModule) {
397 398 PythonQtClassWrapper* result;
398 399
399 400 PyObject* className = PyString_FromString(info->className());
400 401
401 402 PyObject* baseClasses = PyTuple_New(1);
402 403 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PythonQtInstanceWrapper_Type);
403 404
404 405 PyObject* typeDict = PyDict_New();
405 406 PyObject* moduleName = PyObject_GetAttrString(parentModule, "__name__");
406 407 PyDict_SetItemString(typeDict, "__module__", moduleName);
407 408
408 409 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
409 410
410 411 // set the class info so that PythonQtClassWrapper_new can read it
411 412 _currentClassInfoForClassWrapperCreation = info;
412 413 // create the new type object by calling the type
413 414 result = (PythonQtClassWrapper *)PyObject_Call((PyObject *)&PythonQtClassWrapper_Type, args, NULL);
414 415
415 416 Py_DECREF(baseClasses);
416 417 Py_DECREF(typeDict);
417 418 Py_DECREF(args);
418 419 Py_DECREF(className);
419 420
420 421 return result;
421 422 }
422 423
423 424 PyObject* PythonQtPrivate::createEnumValueInstance(PyObject* enumType, unsigned int enumValue)
424 425 {
425 426 PyObject* args = Py_BuildValue("(i)", enumValue);
426 427 PyObject* result = PyObject_Call(enumType, args, NULL);
427 428 Py_DECREF(args);
428 429 return result;
429 430 }
430 431
431 432 PyObject* PythonQtPrivate::createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject) {
432 433 PyObject* result;
433 434
434 435 PyObject* className = PyString_FromString(enumName);
435 436
436 437 PyObject* baseClasses = PyTuple_New(1);
437 438 PyTuple_SET_ITEM(baseClasses, 0, (PyObject*)&PyInt_Type);
438 439
439 440 PyObject* module = PyObject_GetAttrString(parentObject, "__module__");
440 441 PyObject* typeDict = PyDict_New();
441 442 PyDict_SetItemString(typeDict, "__module__", module);
442 443
443 444 PyObject* args = Py_BuildValue("OOO", className, baseClasses, typeDict);
444 445
445 446 // create the new int derived type object by calling the core type
446 447 result = PyObject_Call((PyObject *)&PyType_Type, args, NULL);
447 448
448 449 Py_DECREF(baseClasses);
449 450 Py_DECREF(typeDict);
450 451 Py_DECREF(args);
451 452 Py_DECREF(className);
452 453
453 454 return result;
454 455 }
455 456
456 457 PythonQtSignalReceiver* PythonQt::getSignalReceiver(QObject* obj)
457 458 {
458 459 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
459 460 if (!r) {
460 461 r = new PythonQtSignalReceiver(obj);
461 462 _p->_signalReceivers.insert(obj, r);
462 463 }
463 464 return r;
464 465 }
465 466
466 467 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
467 468 {
468 469 bool flag = false;
469 470 PythonQtObjectPtr callable = lookupCallable(module, objectname);
470 471 if (callable) {
471 472 PythonQtSignalReceiver* r = getSignalReceiver(obj);
472 473 flag = r->addSignalHandler(signal, callable);
473 474 if (!flag) {
474 475 // signal not found
475 476 }
476 477 } else {
477 478 // callable not found
478 479 }
479 480 return flag;
480 481 }
481 482
482 483 bool PythonQt::addSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
483 484 {
484 485 bool flag = false;
485 486 PythonQtSignalReceiver* r = getSignalReceiver(obj);
486 487 if (r) {
487 488 flag = r->addSignalHandler(signal, receiver);
488 489 }
489 490 return flag;
490 491 }
491 492
492 493 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname)
493 494 {
494 495 bool flag = false;
495 496 PythonQtObjectPtr callable = lookupCallable(module, objectname);
496 497 if (callable) {
497 498 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
498 499 if (r) {
499 500 flag = r->removeSignalHandler(signal, callable);
500 501 }
501 502 } else {
502 503 // callable not found
503 504 }
504 505 return flag;
505 506 }
506 507
507 508 bool PythonQt::removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver)
508 509 {
509 510 bool flag = false;
510 511 PythonQtSignalReceiver* r = _p->_signalReceivers[obj];
511 512 if (r) {
512 513 flag = r->removeSignalHandler(signal, receiver);
513 514 }
514 515 return flag;
515 516 }
516 517
517 518 PythonQtObjectPtr PythonQt::lookupCallable(PyObject* module, const QString& name)
518 519 {
519 520 PythonQtObjectPtr p = lookupObject(module, name);
520 521 if (p) {
521 522 if (PyCallable_Check(p)) {
522 523 return p;
523 524 }
524 525 }
525 526 PyErr_Clear();
526 527 return NULL;
527 528 }
528 529
529 530 PythonQtObjectPtr PythonQt::lookupObject(PyObject* module, const QString& name)
530 531 {
531 532 QStringList l = name.split('.');
532 533 PythonQtObjectPtr p = module;
533 534 PythonQtObjectPtr prev;
534 535 QString s;
535 536 QByteArray b;
536 537 for (QStringList::ConstIterator i = l.begin(); i!=l.end() && p; ++i) {
537 538 prev = p;
538 539 b = (*i).toLatin1();
539 540 if (PyDict_Check(p)) {
540 541 p = PyDict_GetItemString(p, b.data());
541 542 } else {
542 543 p.setNewRef(PyObject_GetAttrString(p, b.data()));
543 544 }
544 545 }
545 546 PyErr_Clear();
546 547 return p;
547 548 }
548 549
549 550 PythonQtObjectPtr PythonQt::getMainModule() {
550 551 //both borrowed
551 552 PythonQtObjectPtr dict = PyImport_GetModuleDict();
552 553 return PyDict_GetItemString(dict, "__main__");
553 554 }
554 555
555 556 QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) {
556 557 QVariant result;
557 558 if (pycode) {
558 559 PyObject* dict = NULL;
559 560 if (PyModule_Check(object)) {
560 561 dict = PyModule_GetDict(object);
561 562 } else if (PyDict_Check(object)) {
562 563 dict = object;
563 564 }
564 565 PyObject* r = NULL;
565 566 if (dict) {
566 567 r = PyEval_EvalCode((PyCodeObject*)pycode, dict , dict);
567 568 }
568 569 if (r) {
569 570 result = PythonQtConv::PyObjToQVariant(r);
570 571 Py_DECREF(r);
571 572 } else {
572 573 handleError();
573 574 }
574 575 } else {
575 576 handleError();
576 577 }
577 578 return result;
578 579 }
579 580
580 581 QVariant PythonQt::evalScript(PyObject* object, const QString& script, int start)
581 582 {
582 583 QVariant result;
583 584 PythonQtObjectPtr p;
584 585 PyObject* dict = NULL;
585 586 if (PyModule_Check(object)) {
586 587 dict = PyModule_GetDict(object);
587 588 } else if (PyDict_Check(object)) {
588 589 dict = object;
589 590 }
590 591 if (dict) {
591 592 p.setNewRef(PyRun_String(script.toLatin1().data(), start, dict, dict));
592 593 }
593 594 if (p) {
594 595 result = PythonQtConv::PyObjToQVariant(p);
595 596 } else {
596 597 handleError();
597 598 }
598 599 return result;
599 600 }
600 601
601 602 void PythonQt::evalFile(PyObject* module, const QString& filename)
602 603 {
603 604 PythonQtObjectPtr code = parseFile(filename);
604 605 if (code) {
605 606 evalCode(module, code);
606 607 } else {
607 608 handleError();
608 609 }
609 610 }
610 611
611 612 PythonQtObjectPtr PythonQt::parseFile(const QString& filename)
612 613 {
613 614 PythonQtObjectPtr p;
614 615 p.setNewRef(PythonQtImport::getCodeFromPyc(filename));
615 616 if (!p) {
616 617 handleError();
617 618 }
618 619 return p;
619 620 }
620 621
621 622 PythonQtObjectPtr PythonQt::createModuleFromFile(const QString& name, const QString& filename)
622 623 {
623 624 PythonQtObjectPtr code = parseFile(filename);
624 625 PythonQtObjectPtr module = _p->createModule(name, code);
625 626 return module;
626 627 }
627 628
628 629 PythonQtObjectPtr PythonQt::createModuleFromScript(const QString& name, const QString& script)
629 630 {
630 631 PyErr_Clear();
631 632 QString scriptCode = script;
632 633 if (scriptCode.isEmpty()) {
633 634 // we always need at least a linefeed
634 635 scriptCode = "\n";
635 636 }
636 637 PythonQtObjectPtr pycode;
637 638 pycode.setNewRef(Py_CompileString((char*)scriptCode.toLatin1().data(), "", Py_file_input));
638 639 PythonQtObjectPtr module = _p->createModule(name, pycode);
639 640 return module;
640 641 }
641 642
642 643 PythonQtObjectPtr PythonQt::createUniqueModule()
643 644 {
644 645 static QString pyQtStr("PythonQt_module");
645 646 QString moduleName = pyQtStr+QString::number(_uniqueModuleCount++);
646 647 return createModuleFromScript(moduleName);
647 648 }
648 649
649 650 void PythonQt::addObject(PyObject* object, const QString& name, QObject* qObject)
650 651 {
651 652 if (PyModule_Check(object)) {
652 653 PyModule_AddObject(object, name.toLatin1().data(), _p->wrapQObject(qObject));
653 654 } else if (PyDict_Check(object)) {
654 655 PyDict_SetItemString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
655 656 } else {
656 657 PyObject_SetAttrString(object, name.toLatin1().data(), _p->wrapQObject(qObject));
657 658 }
658 659 }
659 660
660 661 void PythonQt::addVariable(PyObject* object, const QString& name, const QVariant& v)
661 662 {
662 663 if (PyModule_Check(object)) {
663 664 PyModule_AddObject(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
664 665 } else if (PyDict_Check(object)) {
665 666 PyDict_SetItemString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
666 667 } else {
667 668 PyObject_SetAttrString(object, name.toLatin1().data(), PythonQtConv::QVariantToPyObject(v));
668 669 }
669 670 }
670 671
671 672 void PythonQt::removeVariable(PyObject* object, const QString& name)
672 673 {
673 674 if (PyDict_Check(object)) {
674 675 PyDict_DelItemString(object, name.toLatin1().data());
675 676 } else {
676 677 PyObject_DelAttrString(object, name.toLatin1().data());
677 678 }
678 679 }
679 680
680 681 QVariant PythonQt::getVariable(PyObject* object, const QString& objectname)
681 682 {
682 683 QVariant result;
683 684 PythonQtObjectPtr obj = lookupObject(object, objectname);
684 685 if (obj) {
685 686 result = PythonQtConv::PyObjToQVariant(obj);
686 687 }
687 688 return result;
688 689 }
689 690
690 691 QStringList PythonQt::introspection(PyObject* module, const QString& objectname, PythonQt::ObjectType type)
691 692 {
692 693 QStringList results;
693 694
694 695 PythonQtObjectPtr object;
695 696 if (objectname.isEmpty()) {
696 697 object = module;
697 698 } else {
698 699 object = lookupObject(module, objectname);
699 700 if (!object && type == CallOverloads) {
700 701 PyObject* dict = lookupObject(module, "__builtins__");
701 702 if (dict) {
702 703 object = PyDict_GetItemString(dict, objectname.toLatin1().constData());
703 704 }
704 705 }
705 706 }
706 707
707 708 if (object) {
708 709 if (type == CallOverloads) {
709 710 if (PythonQtSlotFunction_Check(object)) {
710 711 PythonQtSlotFunctionObject* o = (PythonQtSlotFunctionObject*)object.object();
711 712 PythonQtSlotInfo* info = o->m_ml;
712 713
713 714 while (info) {
714 715 results << info->fullSignature();
715 716 info = info->nextInfo();
716 717 }
717 718 } else if (object->ob_type == &PythonQtClassWrapper_Type) {
718 719 PythonQtClassWrapper* o = (PythonQtClassWrapper*)object.object();
719 720 PythonQtSlotInfo* info = o->classInfo()->constructors();
720 721
721 722 while (info) {
722 723 results << info->fullSignature();
723 724 info = info->nextInfo();
724 725 }
725 726 } else {
726 727 //TODO: use pydoc!
727 728 PyObject* doc = PyObject_GetAttrString(object, "__doc__");
728 729 if (doc) {
729 730 results << PyString_AsString(doc);
730 731 Py_DECREF(doc);
731 732 }
732 733 }
733 734 } else {
734 735 PyObject* keys = NULL;
735 736 bool isDict = false;
736 737 if (PyDict_Check(object)) {
737 738 keys = PyDict_Keys(object);
738 739 isDict = true;
739 740 } else {
740 741 keys = PyObject_Dir(object);
741 742 }
742 743 if (keys) {
743 744 int count = PyList_Size(keys);
744 745 PyObject* key;
745 746 PyObject* value;
746 747 QString keystr;
747 748 for (int i = 0;i<count;i++) {
748 749 key = PyList_GetItem(keys,i);
749 750 if (isDict) {
750 751 value = PyDict_GetItem(object, key);
751 752 Py_INCREF(value);
752 753 } else {
753 754 value = PyObject_GetAttr(object, key);
754 755 }
755 756 if (!value) continue;
756 757 keystr = PyString_AsString(key);
757 758 static const QString underscoreStr("__tmp");
758 759 if (!keystr.startsWith(underscoreStr)) {
759 760 switch (type) {
760 761 case Anything:
761 762 results << keystr;
762 763 break;
763 764 case Class:
764 765 if (value->ob_type == &PyClass_Type) {
765 766 results << keystr;
766 767 }
767 768 break;
768 769 case Variable:
769 770 if (value->ob_type != &PyClass_Type
770 771 && value->ob_type != &PyCFunction_Type
771 772 && value->ob_type != &PyFunction_Type
772 773 && value->ob_type != &PyModule_Type
773 774 ) {
774 775 results << keystr;
775 776 }
776 777 break;
777 778 case Function:
778 779 if (value->ob_type == &PyFunction_Type ||
779 780 value->ob_type == &PyMethod_Type
780 781 ) {
781 782 results << keystr;
782 783 }
783 784 break;
784 785 case Module:
785 786 if (value->ob_type == &PyModule_Type) {
786 787 results << keystr;
787 788 }
788 789 break;
789 790 default:
790 791 std::cerr << "PythonQt: introspection: unknown case" << ", in " << __FILE__ << ":" << __LINE__ << std::endl;
791 792 }
792 793 }
793 794 Py_DECREF(value);
794 795 }
795 796 Py_DECREF(keys);
796 797 }
797 798 }
798 799 }
799 800 return results;
800 801 }
801 802
802 803 QVariant PythonQt::call(PyObject* object, const QString& name, const QVariantList& args)
803 804 {
804 805 PythonQtObjectPtr callable = lookupCallable(object, name);
805 806 if (callable) {
806 807 return call(callable, args);
807 808 } else {
808 809 return QVariant();
809 810 }
810 811 }
811 812
812 813 QVariant PythonQt::call(PyObject* callable, const QVariantList& args)
813 814 {
814 815 QVariant r;
815 816 PythonQtObjectPtr result;
816 817 result.setNewRef(callAndReturnPyObject(callable, args));
817 818 if (result) {
818 819 r = PythonQtConv::PyObjToQVariant(result);
819 820 } else {
820 821 PythonQt::self()->handleError();
821 822 }
822 823 return r;
823 824 }
824 825
825 826 PyObject* PythonQt::callAndReturnPyObject(PyObject* callable, const QVariantList& args)
826 827 {
827 828 PyObject* result = NULL;
828 829 if (callable) {
829 830 PythonQtObjectPtr pargs;
830 831 int count = args.size();
831 832 if (count>0) {
832 833 pargs.setNewRef(PyTuple_New(count));
833 834 }
834 835 bool err = false;
835 836 // transform QVariants to Python
836 837 for (int i = 0; i < count; i++) {
837 838 PyObject* arg = PythonQtConv::QVariantToPyObject(args.at(i));
838 839 if (arg) {
839 840 // steals reference, no unref
840 841 PyTuple_SetItem(pargs, i,arg);
841 842 } else {
842 843 err = true;
843 844 break;
844 845 }
845 846 }
846 847
847 848 if (!err) {
848 849 PyErr_Clear();
849 850 result = PyObject_CallObject(callable, pargs);
850 851 }
851 852 }
852 853 return result;
853 854 }
854 855
855 856 void PythonQt::addInstanceDecorators(QObject* o)
856 857 {
857 858 _p->addDecorators(o, PythonQtPrivate::InstanceDecorator);
858 859 }
859 860
860 861 void PythonQt::addClassDecorators(QObject* o)
861 862 {
862 863 _p->addDecorators(o, PythonQtPrivate::StaticDecorator | PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
863 864 }
864 865
865 866 void PythonQt::addDecorators(QObject* o)
866 867 {
867 868 _p->addDecorators(o, PythonQtPrivate::AllDecorators);
868 869 }
869 870
870 871 void PythonQt::registerQObjectClassNames(const QStringList& names)
871 872 {
872 873 _p->registerQObjectClassNames(names);
873 874 }
874 875
875 876 void PythonQt::setImporter(PythonQtImportFileInterface* importInterface)
876 877 {
877 878 _p->_importInterface = importInterface;
878 879 PythonQtImport::init();
879 880 }
880 881
881 882 void PythonQt::setImporterIgnorePaths(const QStringList& paths)
882 883 {
883 884 _p->_importIgnorePaths = paths;
884 885 }
885 886
886 887 const QStringList& PythonQt::getImporterIgnorePaths()
887 888 {
888 889 return _p->_importIgnorePaths;
889 890 }
890 891
891 892 void PythonQt::addWrapperFactory(PythonQtCppWrapperFactory* factory)
892 893 {
893 894 _p->_cppWrapperFactories.append(factory);
894 895 }
895 896
896 897 //---------------------------------------------------------------------------------------------------
897 898 PythonQtPrivate::PythonQtPrivate()
898 899 {
899 900 _importInterface = NULL;
900 901 _defaultImporter = new PythonQtQFileImporter;
901 902 _noLongerWrappedCB = NULL;
902 903 _wrappedCB = NULL;
903 904 _currentClassInfoForClassWrapperCreation = NULL;
904 905 }
905 906
906 907 void PythonQtPrivate::setupSharedLibrarySuffixes()
907 908 {
908 909 _sharedLibrarySuffixes.clear();
909 910 PythonQtObjectPtr imp;
910 911 imp.setNewRef(PyImport_ImportModule("imp"));
911 912 int cExtensionCode = imp.getVariable("C_EXTENSION").toInt();
912 913 QVariant result = imp.call("get_suffixes");
913 914 foreach (QVariant entry, result.toList()) {
914 915 QVariantList suffixEntry = entry.toList();
915 916 if (suffixEntry.count()==3) {
916 917 int code = suffixEntry.at(2).toInt();
917 918 if (code == cExtensionCode) {
918 919 _sharedLibrarySuffixes << suffixEntry.at(0).toString();
919 920 }
920 921 }
921 922 }
922 923 }
923 924
924 925 PythonQtClassInfo* PythonQtPrivate::currentClassInfoForClassWrapperCreation()
925 926 {
926 927 PythonQtClassInfo* info = _currentClassInfoForClassWrapperCreation;
927 928 _currentClassInfoForClassWrapperCreation = NULL;
928 929 return info;
929 930 }
930 931
931 932 void PythonQtPrivate::addDecorators(QObject* o, int decoTypes)
932 933 {
933 934 o->setParent(this);
934 935 int numMethods = o->metaObject()->methodCount();
935 936 for (int i = 0; i < numMethods; i++) {
936 937 QMetaMethod m = o->metaObject()->method(i);
937 938 if ((m.methodType() == QMetaMethod::Method ||
938 939 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
939 940 if (qstrncmp(m.signature(), "new_", 4)==0) {
940 941 if ((decoTypes & ConstructorDecorator) == 0) continue;
941 942 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
942 943 if (info->parameters().at(0).isPointer) {
943 944 QByteArray signature = m.signature();
944 945 QByteArray nameOfClass = signature.mid(4, signature.indexOf('(')-4);
945 946 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
946 947 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
947 948 classInfo->addConstructor(newSlot);
948 949 }
949 950 } else if (qstrncmp(m.signature(), "delete_", 7)==0) {
950 951 if ((decoTypes & DestructorDecorator) == 0) continue;
951 952 QByteArray signature = m.signature();
952 953 QByteArray nameOfClass = signature.mid(7, signature.indexOf('(')-7);
953 954 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
954 955 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
955 956 classInfo->setDestructor(newSlot);
956 957 } else if (qstrncmp(m.signature(), "static_", 7)==0) {
957 958 if ((decoTypes & StaticDecorator) == 0) continue;
958 959 QByteArray signature = m.signature();
959 960 QByteArray nameOfClass = signature.mid(signature.indexOf('_')+1);
960 961 nameOfClass = nameOfClass.mid(0, nameOfClass.indexOf('_'));
961 962 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(nameOfClass);
962 963 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::ClassDecorator);
963 964 classInfo->addDecoratorSlot(newSlot);
964 965 } else {
965 966 if ((decoTypes & InstanceDecorator) == 0) continue;
966 967 const PythonQtMethodInfo* info = PythonQtMethodInfo::getCachedMethodInfo(m, NULL);
967 968 if (info->parameters().count()>1) {
968 969 PythonQtMethodInfo::ParameterInfo p = info->parameters().at(1);
969 970 if (p.isPointer) {
970 971 PythonQtClassInfo* classInfo = lookupClassInfoAndCreateIfNotPresent(p.name);
971 972 PythonQtSlotInfo* newSlot = new PythonQtSlotInfo(NULL, m, i, o, PythonQtSlotInfo::InstanceDecorator);
972 973 classInfo->addDecoratorSlot(newSlot);
973 974 }
974 975 }
975 976 }
976 977 }
977 978 }
978 979 }
979 980
980 981 void PythonQtPrivate::registerQObjectClassNames(const QStringList& names)
981 982 {
982 983 foreach(QString name, names) {
983 984 _knownQObjectClassNames.insert(name.toLatin1(), true);
984 985 }
985 986 }
986 987
987 988 void PythonQtPrivate::removeSignalEmitter(QObject* obj)
988 989 {
989 990 _signalReceivers.remove(obj);
990 991 }
991 992
992 993 bool PythonQt::handleError()
993 994 {
994 995 bool flag = false;
995 996 if (PyErr_Occurred()) {
996 997
997 998 // currently we just print the error and the stderr handler parses the errors
998 999 PyErr_Print();
999 1000
1000 1001 /*
1001 1002 // EXTRA: the format of the ptype and ptraceback is not really documented, so I use PyErr_Print() above
1002 1003 PyObject *ptype;
1003 1004 PyObject *pvalue;
1004 1005 PyObject *ptraceback;
1005 1006 PyErr_Fetch( &ptype, &pvalue, &ptraceback);
1006 1007
1007 1008 Py_XDECREF(ptype);
1008 1009 Py_XDECREF(pvalue);
1009 1010 Py_XDECREF(ptraceback);
1010 1011 */
1011 1012 PyErr_Clear();
1012 1013 flag = true;
1013 1014 }
1014 1015 return flag;
1015 1016 }
1016 1017
1017 1018 void PythonQt::addSysPath(const QString& path)
1018 1019 {
1019 1020 PythonQtObjectPtr sys;
1020 1021 sys.setNewRef(PyImport_ImportModule("sys"));
1021 1022 PythonQtObjectPtr obj = lookupObject(sys, "path");
1022 1023 PyList_Insert(obj, 0, PythonQtConv::QStringToPyObject(path));
1023 1024 }
1024 1025
1025 1026 void PythonQt::overwriteSysPath(const QStringList& paths)
1026 1027 {
1027 1028 PythonQtObjectPtr sys;
1028 1029 sys.setNewRef(PyImport_ImportModule("sys"));
1029 1030 PyModule_AddObject(sys, "path", PythonQtConv::QStringListToPyList(paths));
1030 1031 }
1031 1032
1032 1033 void PythonQt::setModuleImportPath(PyObject* module, const QStringList& paths)
1033 1034 {
1034 1035 PyModule_AddObject(module, "__path__", PythonQtConv::QStringListToPyList(paths));
1035 1036 }
1036 1037
1037 1038 void PythonQt::stdOutRedirectCB(const QString& str)
1038 1039 {
1039 1040 emit PythonQt::self()->pythonStdOut(str);
1040 1041 }
1041 1042
1042 1043 void PythonQt::stdErrRedirectCB(const QString& str)
1043 1044 {
1044 1045 emit PythonQt::self()->pythonStdErr(str);
1045 1046 }
1046 1047
1047 1048 void PythonQt::setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb)
1048 1049 {
1049 1050 _p->_wrappedCB = cb;
1050 1051 }
1051 1052
1052 1053 void PythonQt::setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb)
1053 1054 {
1054 1055 _p->_noLongerWrappedCB = cb;
1055 1056 }
1056 1057
1057 1058
1058 1059
1059 1060 static PyMethodDef PythonQtMethods[] = {
1060 1061 {NULL, NULL, 0, NULL}
1061 1062 };
1062 1063
1063 1064 void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName)
1064 1065 {
1065 1066 QByteArray name = "PythonQt";
1066 1067 if (!pythonQtModuleName.isEmpty()) {
1067 1068 name = pythonQtModuleName;
1068 1069 }
1069 1070 _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods);
1070 1071 _p->_pythonQtModuleName = name;
1071 1072
1072 1073 if (redirectStdOut) {
1073 1074 PythonQtObjectPtr sys;
1074 1075 PythonQtObjectPtr out;
1075 1076 PythonQtObjectPtr err;
1076 1077 sys.setNewRef(PyImport_ImportModule("sys"));
1077 1078 // create a redirection object for stdout and stderr
1078 1079 out = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1079 1080 ((PythonQtStdOutRedirect*)out.object())->_cb = stdOutRedirectCB;
1080 1081 err = PythonQtStdOutRedirectType.tp_new(&PythonQtStdOutRedirectType,NULL, NULL);
1081 1082 ((PythonQtStdOutRedirect*)err.object())->_cb = stdErrRedirectCB;
1082 1083 // replace the built in file objects with our own objects
1083 1084 PyModule_AddObject(sys, "stdout", out);
1084 1085 PyModule_AddObject(sys, "stderr", err);
1085 1086 }
1086 1087 }
1087 1088
1088 1089 void PythonQt::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell)
1089 1090 {
1090 1091 _p->registerCPPClass(typeName, parentTypeName, package, wrapperCreator, shell);
1091 1092 }
1092 1093
1093 1094
1094 1095 PythonQtClassInfo* PythonQtPrivate::lookupClassInfoAndCreateIfNotPresent(const char* typeName)
1095 1096 {
1096 1097 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1097 1098 if (!info) {
1098 1099 info = new PythonQtClassInfo();
1099 1100 info->setupCPPObject(typeName);
1100 1101 _knownClassInfos.insert(typeName, info);
1101 1102 }
1102 1103 return info;
1103 1104 }
1104 1105
1105 1106 void PythonQt::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1106 1107 {
1107 1108 _p->addPolymorphicHandler(typeName, cb);
1108 1109 }
1109 1110
1110 1111 void PythonQtPrivate::addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb)
1111 1112 {
1112 1113 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1113 1114 info->addPolymorphicHandler(cb);
1114 1115 }
1115 1116
1116 1117 bool PythonQt::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1117 1118 {
1118 1119 return _p->addParentClass(typeName, parentTypeName, upcastingOffset);
1119 1120 }
1120 1121
1121 1122 bool PythonQtPrivate::addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset)
1122 1123 {
1123 1124 PythonQtClassInfo* info = _knownClassInfos.value(typeName);
1124 1125 if (info) {
1125 1126 PythonQtClassInfo* parentInfo = lookupClassInfoAndCreateIfNotPresent(parentTypeName);
1126 1127 info->addParentClass(PythonQtClassInfo::ParentClassInfo(parentInfo, upcastingOffset));
1127 1128 return true;
1128 1129 } else {
1129 1130 return false;
1130 1131 }
1131 1132 }
1132 1133
1133 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module)
1134 void PythonQtPrivate::registerCPPClass(const char* typeName, const char* parentTypeName, const char* package, PythonQtQObjectCreatorFunctionCB* wrapperCreator, PythonQtShellSetInstanceWrapperCB* shell, PyObject* module, int typeSlots)
1134 1135 {
1135 1136 PythonQtClassInfo* info = lookupClassInfoAndCreateIfNotPresent(typeName);
1136 1137 if (!info->pythonQtClassWrapper()) {
1138 info->setTypeSlots(typeSlots);
1137 1139 info->setupCPPObject(typeName);
1138 1140 createPythonQtClassWrapper(info, package, module);
1139 1141 }
1140 1142 if (parentTypeName && strcmp(parentTypeName,"")!=0) {
1141 1143 addParentClass(typeName, parentTypeName, 0);
1142 1144 }
1143 1145 if (wrapperCreator) {
1144 1146 info->setDecoratorProvider(wrapperCreator);
1145 1147 }
1146 1148 if (shell) {
1147 1149 info->setShellSetInstanceWrapperCB(shell);
1148 1150 }
1149 1151 }
1150 1152
1151 1153 PyObject* PythonQtPrivate::packageByName(const char* name)
1152 1154 {
1153 1155 if (name==NULL || name[0]==0) {
1154 1156 name = "private";
1155 1157 }
1156 1158 PyObject* v = _packages.value(name);
1157 1159 if (!v) {
1158 1160 v = PyImport_AddModule((_pythonQtModuleName + "." + name).constData());
1159 1161 _packages.insert(name, v);
1160 1162 // AddObject steals the reference, so increment it!
1161 1163 Py_INCREF(v);
1162 1164 PyModule_AddObject(_pythonQtModule, name, v);
1163 1165 }
1164 1166 return v;
1165 1167 }
1166 1168
1167 1169 void PythonQtPrivate::handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result)
1168 1170 {
1169 1171 QString error = "Return value '" + PythonQtConv::PyObjGetString(result) + "' can not be converted to expected C++ type '" + methodInfo->parameters().at(0).name + "' as return value of virtual method " + signature;
1170 1172 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
1171 1173 PythonQt::self()->handleError();
1172 1174 }
1173 1175
1174 1176 PyObject* PythonQt::helpCalled(PythonQtClassInfo* info)
1175 1177 {
1176 1178 if (_p->_initFlags & ExternalHelp) {
1177 1179 emit pythonHelpRequest(QByteArray(info->className()));
1178 1180 return Py_BuildValue("");
1179 1181 } else {
1180 1182 return PyString_FromString(info->help().toLatin1().data());
1181 1183 }
1182 1184 }
1183 1185
1184 1186 void PythonQtPrivate::removeWrapperPointer(void* obj)
1185 1187 {
1186 1188 _wrappedObjects.remove(obj);
1187 1189 }
1188 1190
1189 1191 void PythonQtPrivate::addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper)
1190 1192 {
1191 1193 _wrappedObjects.insert(obj, wrapper);
1192 1194 }
1193 1195
1194 1196 PythonQtInstanceWrapper* PythonQtPrivate::findWrapperAndRemoveUnused(void* obj)
1195 1197 {
1196 1198 PythonQtInstanceWrapper* wrap = _wrappedObjects.value(obj);
1197 1199 if (wrap && !wrap->_wrappedPtr && wrap->_obj == NULL) {
1198 1200 // this is a wrapper whose QObject was already removed due to destruction
1199 1201 // so the obj pointer has to be a new QObject with the same address...
1200 1202 // we remove the old one and set the copy to NULL
1201 1203 wrap->_objPointerCopy = NULL;
1202 1204 removeWrapperPointer(obj);
1203 1205 wrap = NULL;
1204 1206 }
1205 1207 return wrap;
1206 1208 }
1207 1209
1208 1210 PythonQtObjectPtr PythonQtPrivate::createModule(const QString& name, PyObject* pycode)
1209 1211 {
1210 1212 PythonQtObjectPtr result;
1211 1213 if (pycode) {
1212 1214 result.setNewRef(PyImport_ExecCodeModule((char*)name.toLatin1().data(), pycode));
1213 1215 } else {
1214 1216 PythonQt::self()->handleError();
1215 1217 }
1216 1218 return result;
1217 1219 }
@@ -1,543 +1,579
1 1 #ifndef _PYTHONQT_H
2 2 #define _PYTHONQT_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 //----------------------------------------------------------------------------------
37 37 /*!
38 38 // \file PythonQt.h
39 39 // \author Florian Link
40 40 // \author Last changed by $Author: florian $
41 41 // \date 2006-05
42 42 */
43 43 //----------------------------------------------------------------------------------
44 44
45 45 #include "PythonQtSystem.h"
46 46 #include "PythonQtInstanceWrapper.h"
47 47 #include "PythonQtClassWrapper.h"
48 48 #include "PythonQtSlot.h"
49 49 #include "PythonQtObjectPtr.h"
50 50 #include <QObject>
51 51 #include <QVariant>
52 52 #include <QList>
53 53 #include <QHash>
54 54 #include <QByteArray>
55 55 #include <QStringList>
56 56 #include <QtDebug>
57 57 #include <iostream>
58 58
59 59
60 60 class PythonQtClassInfo;
61 61 class PythonQtPrivate;
62 62 class PythonQtMethodInfo;
63 63 class PythonQtSignalReceiver;
64 64 class PythonQtImportFileInterface;
65 65 class PythonQtCppWrapperFactory;
66 66 class PythonQtQFileImporter;
67 67
68 68 typedef void PythonQtQObjectWrappedCB(QObject* object);
69 69 typedef void PythonQtQObjectNoLongerWrappedCB(QObject* object);
70 70 typedef void* PythonQtPolymorphicHandlerCB(const void *ptr, char **class_name);
71 71
72 72 typedef void PythonQtShellSetInstanceWrapperCB(void* object, PythonQtInstanceWrapper* wrapper);
73 73
74 74 template<class T> void PythonQtSetInstanceWrapperOnShell(void* object, PythonQtInstanceWrapper* wrapper) { ((T*)object)->_wrapper = wrapper; };
75 75
76 76 //! returns the offset that needs to be added to upcast an object of type T1 to T2
77 77 template<class T1, class T2> int PythonQtUpcastingOffset() {
78 78 return (((char*)(static_cast<T2*>(reinterpret_cast<T1*>(0x100)))) - ((char*)reinterpret_cast<T1*>(0x100)));
79 79 }
80 80
81 81 //! callback to create a QObject lazily
82 82 typedef QObject* PythonQtQObjectCreatorFunctionCB();
83 83
84 84 //! helper template to create a derived QObject class
85 85 template<class T> QObject* PythonQtCreateObject() { return new T(); };
86 86
87 87 //! the main interface to the Python Qt binding, realized as a singleton
88 88 class PYTHONQT_EXPORT PythonQt : public QObject {
89 89
90 90 Q_OBJECT
91 91
92 92 public:
93 93 enum InitFlags {
94 94 RedirectStdOut = 1, //!<< sets if the std out/err is redirected to pythonStdOut() and pythonStdErr() signals
95 95 IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
96 96 ExternalHelp = 4 //!<< sets if help() calls on PythonQt modules are forwarded to the pythonHelpRequest() signal
97 97 };
98 98
99 //! flags that tell PythonQt which operators to expect on the registered type
100 enum TypeSlots {
101 Type_Add = 1,
102 Type_Subtract = 1 << 1,
103 Type_Multiply = 1 << 2,
104 Type_Divide = 1 << 3,
105 Type_Mod = 1 << 4,
106 Type_And = 1 << 5,
107 Type_Or = 1 << 6,
108 Type_Xor = 1 << 7,
109 Type_LShift = 1 << 8,
110 Type_RShift = 1 << 9,
111
112 Type_InplaceAdd = 1 << 10,
113 Type_InplaceSubtract = 1 << 11,
114 Type_InplaceMultiply = 1 << 12,
115 Type_InplaceDivide = 1 << 13,
116 Type_InplaceMod = 1 << 14,
117 Type_InplaceAnd = 1 << 15,
118 Type_InplaceOr = 1 << 16,
119 Type_InplaceXor = 1 << 17,
120 Type_InplaceLShift = 1 << 18,
121 Type_InplaceRShift = 1 << 19,
122
123 // Not yet needed/nicely mappable/generated...
124 //Type_Positive = 1 << 29,
125 //Type_Negative = 1 << 29,
126 //Type_Abs = 1 << 29,
127 //Type_Hash = 1 << 29,
128
129 Type_Invert = 1 << 29,
130 Type_RichCompare = 1 << 30,
131 Type_NonZero = 1 << 31,
132
133 };
134
99 135 //! initialize the python qt binding (flags are a or combination of InitFlags), if \c pythonQtModuleName is given
100 136 //! it defines the name of the python module that PythonQt will add, otherwise "PythonQt" is used.
101 137 //! This can be used to e.g. pass in PySide or PyQt4 to make it more compatible.
102 138 static void init(int flags = IgnoreSiteModule | RedirectStdOut, const QByteArray& pythonQtModuleName = QByteArray());
103 139
104 140 //! cleanup
105 141 static void cleanup();
106 142
107 143 //! get the singleton instance
108 144 static PythonQt* self() { return _self; }
109 145
110 146 //-----------------------------------------------------------------------------
111 147 // Public API:
112 148
113 149 //! defines the object types for introspection
114 150 enum ObjectType {
115 151 Class,
116 152 Function,
117 153 Variable,
118 154 Module,
119 155 Anything,
120 156 CallOverloads
121 157 };
122 158
123 159 //! overwrite the python sys path (call this directly after PythonQt::init() if you want to change the std python sys path)
124 160 void overwriteSysPath(const QStringList& paths);
125 161
126 162 //! prepend a path to sys.path to allow importing from it
127 163 void addSysPath(const QString& path);
128 164
129 165 //! sets the __path__ list of a module to the given list (important for local imports)
130 166 void setModuleImportPath(PyObject* module, const QStringList& paths);
131 167
132 168 //! get the __main__ module of python
133 169 PythonQtObjectPtr getMainModule();
134 170
135 171 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
136 172 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
137 173 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
138 174 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
139 175
140 176 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
141 177 //! (ownership of wrapper is passed to PythonQt)
142 178 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
143 179
144 180 This will add a wrapper object that is used to make calls to the given classname \c typeName.
145 181 All slots that take a pointer to typeName as the first argument will be callable from Python on
146 182 a variant object that contains such a type.
147 183 */
148 184 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL);
149 185
150 186 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
151 187 //! and it will register the classes when it first sees a pointer to such a derived class
152 188 void registerQObjectClassNames(const QStringList& names);
153 189
154 190 //! add a parent class relation to the \c given typeName, the upcastingOffset is needed for multiple inheritance
155 191 //! and can be calculated using PythonQtUpcastingOffset<type,parentType>(), which also verifies that
156 192 //! type is really derived from parentType.
157 193 //! Returns false if the typeName was not yet registered.
158 194 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset=0);
159 195
160 196 //! add a handler for polymorphic downcasting
161 197 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
162 198
163 199 //! parses the given file and returns the python code object, this can then be used to call evalCode()
164 200 PythonQtObjectPtr parseFile(const QString& filename);
165 201
166 202 //! evaluates the given code and returns the result value (use Py_Compile etc. to create pycode from string)
167 203 //! If pycode is NULL, a python error is printed.
168 204 QVariant evalCode(PyObject* object, PyObject* pycode);
169 205
170 206 //! evaluates the given script code and returns the result value
171 207 QVariant evalScript(PyObject* object, const QString& script, int start = Py_file_input);
172 208
173 209 //! evaluates the given script code from file
174 210 void evalFile(PyObject* object, const QString& filename);
175 211
176 212 //! creates the new module \c name and evaluates the given file in the context of that module
177 213 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
178 214 //! to a module later on.
179 215 //! The user needs to make sure that the \c name is unique in the python module dictionary.
180 216 PythonQtObjectPtr createModuleFromFile(const QString& name, const QString& filename);
181 217
182 218 //! creates the new module \c name and evaluates the given script in the context of that module.
183 219 //! If the \c script is empty, the module contains no initial code. You can use evalScript/evalCode to add code
184 220 //! to a module later on.
185 221 //! The user needs to make sure that the \c name is unique in the python module dictionary.
186 222 PythonQtObjectPtr createModuleFromScript(const QString& name, const QString& script = QString());
187 223
188 224 //! create a uniquely named module, you can use evalFile or evalScript to populate the module with
189 225 //! script code
190 226 PythonQtObjectPtr createUniqueModule();
191 227
192 228 //@{ Signal handlers
193 229
194 230 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c objectname in module
195 231 bool addSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
196 232
197 233 //! remove a signal handler from the given \c signal of \c obj
198 234 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* module, const QString& objectname);
199 235
200 236 //! add a signal handler to the given \c signal of \c obj and connect it to a callable \c receiver
201 237 bool addSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
202 238
203 239 //! remove a signal handler from the given \c signal of \c obj
204 240 bool removeSignalHandler(QObject* obj, const char* signal, PyObject* receiver);
205 241
206 242 //@}
207 243
208 244 //@{ Variable access
209 245
210 246 //! add the given \c qObject to the python \c object as a variable with \c name (it can be removed via clearVariable)
211 247 void addObject(PyObject* object, const QString& name, QObject* qObject);
212 248
213 249 //! add the given variable to the object
214 250 void addVariable(PyObject* object, const QString& name, const QVariant& v);
215 251
216 252 //! remove the given variable
217 253 void removeVariable(PyObject* module, const QString& name);
218 254
219 255 //! get the variable with the \c name of the \c object, returns an invalid QVariant on error
220 256 QVariant getVariable(PyObject* object, const QString& name);
221 257
222 258 //! read vars etc. in scope of an \c object, optional looking inside of an object \c objectname
223 259 QStringList introspection(PyObject* object, const QString& objectname, ObjectType type);
224 260
225 261 //! returns the found callable object or NULL
226 262 //! @return new reference
227 263 PythonQtObjectPtr lookupCallable(PyObject* object, const QString& name);
228 264
229 265 //@}
230 266
231 267 //@{ Calling of python callables
232 268
233 269 //! call the given python \c callable in the scope of object, returns the result converted to a QVariant
234 270 QVariant call(PyObject* object, const QString& callable, const QVariantList& args = QVariantList());
235 271
236 272 //! call the given python object, returns the result converted to a QVariant
237 273 QVariant call(PyObject* callable, const QVariantList& args = QVariantList());
238 274
239 275 //! call the given python object, returns the result as new PyObject
240 276 PyObject* callAndReturnPyObject(PyObject* callable, const QVariantList& args = QVariantList());
241 277
242 278 //@}
243 279
244 280 //@{ Decorations, constructors, wrappers...
245 281
246 282
247 283 //! add an object whose slots will be used as decorator slots for
248 284 //! other QObjects or CPP classes. The slots need to follow the
249 285 //! convention that the first argument is a pointer to the wrapped object.
250 286 //! (ownership is passed to PythonQt)
251 287 /*!
252 288 Example:
253 289
254 290 A slot with the signature
255 291
256 292 \code
257 293 bool doSomething(QWidget* w, int a)
258 294 \endcode
259 295
260 296 will extend QWidget instances (and derived classes) with a "bool doSomething(int a)" slot
261 297 that will be called with the concrete instance as first argument.
262 298 So in Python you can now e.g. call
263 299
264 300 \code
265 301 someWidget.doSomething(12)
266 302 \endcode
267 303
268 304 without QWidget really having this method. This allows to easily make normal methods
269 305 of Qt classes callable by forwarding them with such decorator slots
270 306 or to make CPP classes (which are not derived from QObject) callable from Python.
271 307 */
272 308 void addInstanceDecorators(QObject* o);
273 309
274 310 //! add an object whose slots will be used as decorator slots for
275 311 //! class objects (ownership is passed to PythonQt)
276 312 /*!
277 313 The slots need to follow the following convention:
278 314 - SomeClass* new_SomeClass(...)
279 315 - QVariant new_SomeClass(...)
280 316 - void delete_SomeClass(SomeClass*)
281 317 - ... static_SomeClass_someName(...)
282 318
283 319 This will add:
284 320 - a constructor
285 321 - a constructor which generates a QVariant
286 322 - a destructor (only useful for CPP objects)
287 323 - a static decorator slot which will be available on the MetaObject (visible in PythonQt module)
288 324
289 325 */
290 326 void addClassDecorators(QObject* o);
291 327
292 328 //! this will add the object both as class and instance decorator (ownership is passed to PythonQt)
293 329 void addDecorators(QObject* o);
294 330
295 331 //! add the given factory to PythonQt (ownership stays with caller)
296 332 void addWrapperFactory(PythonQtCppWrapperFactory* factory);
297 333
298 334 //@}
299 335
300 336 //@{ Custom importer (to replace internal import implementation of python)
301 337
302 338 //! replace the internal import implementation and use the supplied interface to load files (both py and pyc files)
303 339 //! (this method should be called directly after initialization of init() and before calling overwriteSysPath().
304 340 //! On the first call to this method, it will install a generic PythonQt importer in Pythons "path_hooks".
305 341 //! This is not reversible, so even setting setImporter(NULL) afterwards will
306 342 //! keep the custom PythonQt importer with a QFile default import interface.
307 343 //! Subsequent python import calls will make use of the passed importInterface
308 344 //! which forwards all import calls to the given \c importInterface.
309 345 //! Passing NULL will install a default QFile importer.
310 346 //! (\c importInterface ownership stays with caller)
311 347 void setImporter(PythonQtImportFileInterface* importInterface);
312 348
313 349 //! this installs the default QFile importer (which effectively does a setImporter(NULL))
314 350 //! (without calling setImporter or installDefaultImporter at least once, the default python import
315 351 //! mechanism is in place)
316 352 //! the default importer allows to import files from anywhere QFile can read from,
317 353 //! including the Qt resource system using ":". Keep in mind that you need to extend
318 354 //! "sys.path" with ":" to be able to import from the Qt resources.
319 355 void installDefaultImporter() { setImporter(NULL); }
320 356
321 357 //! set paths that the importer should ignore
322 358 void setImporterIgnorePaths(const QStringList& paths);
323 359
324 360 //! get paths that the importer should ignore
325 361 const QStringList& getImporterIgnorePaths();
326 362
327 363 //@}
328 364
329 365 //! get access to internal data (should not be used on the public API, but is used by some C functions)
330 366 static PythonQtPrivate* priv() { return _self->_p; }
331 367
332 368 //! get access to the file importer (if set)
333 369 static PythonQtImportFileInterface* importInterface();
334 370
335 371 //! handle a python error, call this when a python function fails. If no error occurred, it returns false.
336 372 //! The error is currently just output to the python stderr, future version might implement better trace printing
337 373 bool handleError();
338 374
339 375 //! set a callback that is called when a QObject with parent == NULL is wrapped by pythonqt
340 376 void setQObjectWrappedCallback(PythonQtQObjectWrappedCB* cb);
341 377 //! set a callback that is called when a QObject with parent == NULL is no longer wrapped by pythonqt
342 378 void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB* cb);
343 379
344 380 //! call the callback if it is set
345 381 static void qObjectNoLongerWrappedCB(QObject* o);
346 382
347 383 signals:
348 384 //! emitted when python outputs something to stdout (and redirection is turned on)
349 385 void pythonStdOut(const QString& str);
350 386 //! emitted when python outputs something to stderr (and redirection is turned on)
351 387 void pythonStdErr(const QString& str);
352 388
353 389 //! emitted when help() is called on a PythonQt object and \c ExternalHelp is enabled
354 390 void pythonHelpRequest(const QByteArray& cppClassName);
355 391
356 392
357 393 public:
358 394 //! called by internal help methods
359 395 PyObject* helpCalled(PythonQtClassInfo* info);
360 396
361 397 //! returns the found object or NULL
362 398 //! @return new reference
363 399 PythonQtObjectPtr lookupObject(PyObject* module, const QString& name);
364 400
365 401 private:
366 402 void initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName);
367 403
368 404 //! callback for stdout redirection, emits pythonStdOut signal
369 405 static void stdOutRedirectCB(const QString& str);
370 406 //! callback for stderr redirection, emits pythonStdErr signal
371 407 static void stdErrRedirectCB(const QString& str);
372 408
373 409 //! get (and create if not available) the signal receiver of that QObject, signal receiver is made child of the passed \c obj
374 410 PythonQtSignalReceiver* getSignalReceiver(QObject* obj);
375 411
376 412 PythonQt(int flags, const QByteArray& pythonQtModuleName);
377 413 ~PythonQt();
378 414
379 415 static PythonQt* _self;
380 416 static int _uniqueModuleCount;
381 417
382 418 PythonQtPrivate* _p;
383 419
384 420 };
385 421
386 422 //! internal PythonQt details
387 423 class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
388 424
389 425 Q_OBJECT
390 426
391 427 public:
392 428 PythonQtPrivate();
393 429 ~PythonQtPrivate();
394 430
395 431 enum DecoratorTypes {
396 432 StaticDecorator = 1,
397 433 ConstructorDecorator = 2,
398 434 DestructorDecorator = 4,
399 435 InstanceDecorator = 8,
400 436 AllDecorators = 0xffff
401 437 };
402 438
403 439 //! get the suffixes that are used for shared libraries
404 440 const QStringList& sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
405 441
406 442 //! returns if the id is the id for PythonQtObjectPtr
407 443 bool isPythonQtObjectPtrMetaId(int id) { return _PythonQtObjectPtr_metaId == id; }
408 444
409 445 //! add the wrapper pointer (for reuse if the same obj appears while wrapper still exists)
410 446 void addWrapperPointer(void* obj, PythonQtInstanceWrapper* wrapper);
411 447 //! remove the wrapper ptr again
412 448 void removeWrapperPointer(void* obj);
413 449
414 450 //! add parent class relation
415 451 bool addParentClass(const char* typeName, const char* parentTypeName, int upcastingOffset);
416 452
417 453 //! add a handler for polymorphic downcasting
418 454 void addPolymorphicHandler(const char* typeName, PythonQtPolymorphicHandlerCB* cb);
419 455
420 456 //! lookup existing classinfo and return new if not yet present
421 457 PythonQtClassInfo* lookupClassInfoAndCreateIfNotPresent(const char* typeName);
422 458
423 459 //! called when a signal emitting QObject is destroyed to remove the signal handler from the hash map
424 460 void removeSignalEmitter(QObject* obj);
425 461
426 462 //! wrap the given QObject into a Python object (or return existing wrapper!)
427 463 PyObject* wrapQObject(QObject* obj);
428 464
429 465 //! wrap the given ptr into a Python object (or return existing wrapper!) if there is a known QObject of that name or a known wrapper in the factory
430 466 PyObject* wrapPtr(void* ptr, const QByteArray& name);
431 467
432 468 //! registers a QObject derived class to PythonQt (this is implicitly called by addObject as well)
433 469 /* Since Qt4 does not offer a way to detect if a given classname is derived from QObject and thus has a QMetaObject,
434 470 you MUST register all your QObject derived classes here when you want them to be detected in signal and slot calls */
435 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL);
471 void registerClass(const QMetaObject* metaobject, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
436 472
437 473 //! add a wrapper object for the given QMetaType typeName, also does an addClassDecorators() to add constructors for variants
438 474 //! (ownership of wrapper is passed to PythonQt)
439 475 /*! Make sure that you have done a qRegisterMetaType first, if typeName is a user type!
440 476
441 477 This will add a wrapper object that is used to make calls to the given classname \c typeName.
442 478 All slots that take a pointer to typeName as the first argument will be callable from Python on
443 479 a variant object that contains such a type.
444 480 */
445 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL);
481 void registerCPPClass(const char* typeName, const char* parentTypeName = NULL, const char* package = NULL, PythonQtQObjectCreatorFunctionCB* wrapperCreator = NULL, PythonQtShellSetInstanceWrapperCB* shell = NULL, PyObject* module = NULL, int typeSlots = 0);
446 482
447 483 //! as an alternative to registerClass, you can tell PythonQt the names of QObject derived classes
448 484 //! and it will register the classes when it first sees a pointer to such a derived class
449 485 void registerQObjectClassNames(const QStringList& names);
450 486
451 487 //! add a decorator object
452 488 void addDecorators(QObject* o, int decoTypes);
453 489
454 490 //! helper method that creates a PythonQtClassWrapper object (returns a new reference)
455 491 PythonQtClassWrapper* createNewPythonQtClassWrapper(PythonQtClassInfo* info, PyObject* module);
456 492
457 493 //! create a new instance of the given enum type with given value (returns a new reference)
458 494 static PyObject* createEnumValueInstance(PyObject* enumType, unsigned int enumValue);
459 495
460 496 //! helper that creates a new int derived class that represents the enum of the given name (returns a new reference)
461 497 static PyObject* createNewPythonQtEnumWrapper(const char* enumName, PyObject* parentObject);
462 498
463 499 //! helper method that creates a PythonQtInstanceWrapper object and registers it in the object map
464 500 PythonQtInstanceWrapper* createNewPythonQtInstanceWrapper(QObject* obj, PythonQtClassInfo* info, void* wrappedPtr = NULL);
465 501
466 502 //! get the class info for a meta object (if available)
467 503 PythonQtClassInfo* getClassInfo(const QMetaObject* meta) { return _knownClassInfos.value(meta->className()); }
468 504
469 505 //! get the class info for a meta object (if available)
470 506 PythonQtClassInfo* getClassInfo(const QByteArray& className) { return _knownClassInfos.value(className); }
471 507
472 508 //! creates the new module from the given pycode
473 509 PythonQtObjectPtr createModule(const QString& name, PyObject* pycode);
474 510
475 511 //! get the current class info (for the next PythonQtClassWrapper that is created) and reset it to NULL again
476 512 PythonQtClassInfo* currentClassInfoForClassWrapperCreation();
477 513
478 514 //! the dummy tuple (which is empty and may be used to detected that a wrapper is called from internal wrapper creation
479 515 static PyObject* dummyTuple();
480 516
481 517 //! called by virtual overloads when a python return value can not be converted to the required Qt type
482 518 void handleVirtualOverloadReturnError(const char* signature, const PythonQtMethodInfo* methodInfo, PyObject* result);
483 519
484 520 //! get access to the PythonQt module
485 521 PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
486 522
487 523 private:
488 524 //! Setup the shared library suffixes by getting them from the "imp" module.
489 525 void setupSharedLibrarySuffixes();
490 526
491 527 //! create a new pythonqt class wrapper and place it in the pythonqt module
492 528 void createPythonQtClassWrapper(PythonQtClassInfo* info, const char* package, PyObject* module = NULL);
493 529
494 530 //! get/create new package module (the returned object is a borrowed reference)
495 531 PyObject* packageByName(const char* name);
496 532
497 533 //! get the wrapper for a given pointer (and remove a wrapper of an already destroyed qobject)
498 534 PythonQtInstanceWrapper* findWrapperAndRemoveUnused(void* obj);
499 535
500 536 //! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
501 537 QHash<void* , PythonQtInstanceWrapper *> _wrappedObjects;
502 538
503 539 //! stores the meta info of known Qt classes
504 540 QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
505 541
506 542 //! names of qobject derived classes that can be casted to qobject savely
507 543 QHash<QByteArray, bool> _knownQObjectClassNames;
508 544
509 545 //! stores signal receivers for QObjects
510 546 QHash<QObject* , PythonQtSignalReceiver *> _signalReceivers;
511 547
512 548 //! the PythonQt python module
513 549 PythonQtObjectPtr _pythonQtModule;
514 550
515 551 //! the name of the PythonQt python module
516 552 QByteArray _pythonQtModuleName;
517 553
518 554 //! the importer interface (if set)
519 555 PythonQtImportFileInterface* _importInterface;
520 556
521 557 //! the default importer
522 558 PythonQtQFileImporter* _defaultImporter;
523 559
524 560 PythonQtQObjectNoLongerWrappedCB* _noLongerWrappedCB;
525 561 PythonQtQObjectWrappedCB* _wrappedCB;
526 562
527 563 QStringList _importIgnorePaths;
528 564 QStringList _sharedLibrarySuffixes;
529 565
530 566 //! the cpp object wrapper factories
531 567 QList<PythonQtCppWrapperFactory*> _cppWrapperFactories;
532 568
533 569 QHash<QByteArray, PyObject*> _packages;
534 570
535 571 PythonQtClassInfo* _currentClassInfoForClassWrapperCreation;
536 572
537 573 int _initFlags;
538 574 int _PythonQtObjectPtr_metaId;
539 575
540 576 friend class PythonQt;
541 577 };
542 578
543 579 #endif
@@ -1,848 +1,849
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 _typeSlots = 0;
60 61 _isQObject = false;
61 62 _enumsCreated = false;
62 63 }
63 64
64 65 PythonQtClassInfo::~PythonQtClassInfo()
65 66 {
66 67 clearCachedMembers();
67 68
68 69 if (_constructors) {
69 70 _constructors->deleteOverloadsAndThis();
70 71 }
71 72 if (_destructor) {
72 73 _destructor->deleteOverloadsAndThis();
73 74 }
74 75 foreach(PythonQtSlotInfo* info, _decoratorSlots) {
75 76 info->deleteOverloadsAndThis();
76 77 }
77 78 }
78 79
79 80 void PythonQtClassInfo::setupQObject(const QMetaObject* meta)
80 81 {
81 82 // _wrappedClassName is already set earlier in the class setup
82 83 _isQObject = true;
83 84 _meta = meta;
84 85 }
85 86
86 87 void PythonQtClassInfo::setupCPPObject(const QByteArray& classname)
87 88 {
88 89 _isQObject = false;
89 90 _wrappedClassName = classname;
90 91 _metaTypeId = QMetaType::type(classname);
91 92 }
92 93
93 94 void PythonQtClassInfo::clearCachedMembers()
94 95 {
95 96 QHashIterator<QByteArray, PythonQtMemberInfo> i(_cachedMembers);
96 97 while (i.hasNext()) {
97 98 PythonQtMemberInfo member = i.next().value();
98 99 if (member._type== PythonQtMemberInfo::Slot) {
99 100 PythonQtSlotInfo* info = member._slot;
100 101 while (info) {
101 102 PythonQtSlotInfo* next = info->nextInfo();
102 103 delete info;
103 104 info = next;
104 105 }
105 106 }
106 107 }
107 108 }
108 109
109 110 int PythonQtClassInfo::findCharOffset(const char* sigStart, char someChar)
110 111 {
111 112 const char* sigEnd = sigStart;
112 113 char c;
113 114 do {
114 115 c = *sigEnd++;
115 116 } while (c!=someChar && c!=0);
116 117 return sigEnd-sigStart-1;
117 118 }
118 119
119 120 bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName)
120 121 {
121 122 if (!_meta) return false;
122 123
123 124 bool found = false;
124 125 bool nameMapped = false;
125 126 const char* attributeName = memberName;
126 127 // look for properties
127 128 int i = _meta->indexOfProperty(attributeName);
128 129 if (i==-1) {
129 130 // try to map name to objectName
130 131 if (qstrcmp(attributeName, "name")==0) {
131 132 attributeName = "objectName";
132 133 nameMapped = true;
133 134 i = _meta->indexOfProperty(attributeName);
134 135 }
135 136 }
136 137 if (i!=-1) {
137 138 PythonQtMemberInfo newInfo(_meta->property(i));
138 139 _cachedMembers.insert(attributeName, newInfo);
139 140 if (nameMapped) {
140 141 _cachedMembers.insert(memberName, newInfo);
141 142 }
142 143 #ifdef PYTHONQT_DEBUG
143 144 std::cout << "caching property " << memberName << " on " << _meta->className() << std::endl;
144 145 #endif
145 146 found = true;
146 147 }
147 148 return found;
148 149 }
149 150
150 151 PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
151 152 {
152 153 inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset);
153 154 foreach(const ParentClassInfo& info, _parentClasses) {
154 155 inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset);
155 156 }
156 157 return inputInfo;
157 158 }
158 159
159 160 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset) {
160 161 QObject* decoratorProvider = decorator();
161 162 int memberNameLen = strlen(memberName);
162 163 if (decoratorProvider) {
163 164 //qDebug()<< "looking " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
164 165 const QMetaObject* meta = decoratorProvider->metaObject();
165 166 int numMethods = meta->methodCount();
166 167 int startFrom = QObject::staticMetaObject.methodCount();
167 168 for (int i = startFrom; i < numMethods; i++) {
168 169 QMetaMethod m = meta->method(i);
169 170 if ((m.methodType() == QMetaMethod::Method ||
170 171 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
171 172
172 173 const char* sigStart = m.signature();
173 174 bool isClassDeco = false;
174 175 if (qstrncmp(sigStart, "static_", 7)==0) {
175 176 // skip the static_classname_ part of the string
176 177 sigStart += 7 + 1 + strlen(className());
177 178 isClassDeco = true;
178 179 } else if (qstrncmp(sigStart, "new_", 4)==0) {
179 180 isClassDeco = true;
180 181 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
181 182 isClassDeco = true;
182 183 }
183 184 // find the first '('
184 185 int offset = findCharOffset(sigStart, '(');
185 186
186 187 // XXX no checking is currently done if the slots have correct first argument or not...
187 188
188 189 // check if same length and same name
189 190 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
190 191 found = true;
191 192 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i, decoratorProvider, isClassDeco?PythonQtSlotInfo::ClassDecorator:PythonQtSlotInfo::InstanceDecorator);
192 193 info->setUpcastingOffset(upcastingOffset);
193 194 //qDebug()<< "adding " << decoratorProvider->metaObject()->className() << " " << memberName << " " << upcastingOffset;
194 195 if (tail) {
195 196 tail->setNextInfo(info);
196 197 } else {
197 198 PythonQtMemberInfo newInfo(info);
198 199 memberCache.insert(memberName, newInfo);
199 200 }
200 201 tail = info;
201 202 }
202 203 }
203 204 }
204 205 }
205 206
206 207 tail = findDecoratorSlots(memberName, memberNameLen, tail, found, memberCache, upcastingOffset);
207 208
208 209 return tail;
209 210 }
210 211
211 212 bool PythonQtClassInfo::lookForMethodAndCache(const char* memberName)
212 213 {
213 214 bool found = false;
214 215 int memberNameLen = strlen(memberName);
215 216 PythonQtSlotInfo* tail = NULL;
216 217 if (_meta) {
217 218 int numMethods = _meta->methodCount();
218 219 for (int i = 0; i < numMethods; i++) {
219 220 QMetaMethod m = _meta->method(i);
220 221 if (((m.methodType() == QMetaMethod::Method ||
221 222 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
222 223 || m.methodType()==QMetaMethod::Signal) {
223 224
224 225 const char* sigStart = m.signature();
225 226 // find the first '('
226 227 int offset = findCharOffset(sigStart, '(');
227 228
228 229 // check if same length and same name
229 230 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
230 231 found = true;
231 232 PythonQtSlotInfo* info = new PythonQtSlotInfo(this, m, i);
232 233 if (tail) {
233 234 tail->setNextInfo(info);
234 235 } else {
235 236 PythonQtMemberInfo newInfo(info);
236 237 _cachedMembers.insert(memberName, newInfo);
237 238 }
238 239 tail = info;
239 240 }
240 241 }
241 242 }
242 243 }
243 244
244 245 // look for dynamic decorators in this class and in derived classes
245 246 tail = recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, tail, found, _cachedMembers, 0);
246 247
247 248 return found;
248 249 }
249 250
250 251 bool PythonQtClassInfo::lookForEnumAndCache(const QMetaObject* meta, const char* memberName)
251 252 {
252 253 bool found = false;
253 254 // look for enum values
254 255 int enumCount = meta->enumeratorCount();
255 256 for (int i=0;i<enumCount; i++) {
256 257 QMetaEnum e = meta->enumerator(i);
257 258 // we do not want flags, they will cause our values to appear two times
258 259 if (e.isFlag()) continue;
259 260
260 261 for (int j=0; j < e.keyCount(); j++) {
261 262 if (qstrcmp(e.key(j), memberName)==0) {
262 263 PyObject* enumType = findEnumWrapper(e.name());
263 264 if (enumType) {
264 265 PythonQtObjectPtr enumValuePtr;
265 266 enumValuePtr.setNewRef(PythonQtPrivate::createEnumValueInstance(enumType, e.value(j)));
266 267 PythonQtMemberInfo newInfo(enumValuePtr);
267 268 _cachedMembers.insert(memberName, newInfo);
268 269 #ifdef PYTHONQT_DEBUG
269 270 std::cout << "caching enum " << memberName << " on " << meta->className() << std::endl;
270 271 #endif
271 272 found = true;
272 273 break;
273 274 } else {
274 275 std::cout << "enum " << e.name() << " not found on " << className() << std::endl;
275 276 }
276 277 }
277 278 }
278 279 }
279 280 return found;
280 281 }
281 282
282 283 PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName)
283 284 {
284 285 PythonQtMemberInfo info = _cachedMembers.value(memberName);
285 286 if (info._type != PythonQtMemberInfo::Invalid) {
286 287 return info;
287 288 } else {
288 289 bool found = false;
289 290
290 291 found = lookForPropertyAndCache(memberName);
291 292 if (!found) {
292 293 found = lookForMethodAndCache(memberName);
293 294 }
294 295 if (!found) {
295 296 if (_meta) {
296 297 // check enums in our meta object directly
297 298 found = lookForEnumAndCache(_meta, memberName);
298 299 }
299 300 if (!found) {
300 301 // check enums in the class hierachy of CPP classes
301 302 // look for dynamic decorators in this class and in derived classes
302 303 QList<QObject*> decoObjects;
303 304 recursiveCollectDecoratorObjects(decoObjects);
304 305 foreach(QObject* deco, decoObjects) {
305 306 // call on ourself for caching, but with different metaObject():
306 307 found = lookForEnumAndCache(deco->metaObject(), memberName);
307 308 if (found) {
308 309 break;
309 310 }
310 311 }
311 312 }
312 313 }
313 314 if (!found) {
314 315 // maybe it is an enum wrapper?
315 316 PyObject* p = findEnumWrapper(memberName);
316 317 if (p) {
317 318 info._type = PythonQtMemberInfo::EnumWrapper;
318 319 info._enumWrapper = p;
319 320 _cachedMembers.insert(memberName, info);
320 321 found = true;
321 322 }
322 323 }
323 324 if (!found) {
324 325 // since python keywords can not be looked up, we check if the name contains a single trailing _
325 326 // and remove that and look again, so that we e.g. find exec on an exec_ lookup
326 327 QByteArray mbrName(memberName);
327 328 if ((mbrName.length()>2) &&
328 329 (mbrName.at(mbrName.length()-1) == '_') &&
329 330 (mbrName.at(mbrName.length()-2) != '_')) {
330 331 mbrName = mbrName.mid(0,mbrName.length()-1);
331 332 found = lookForMethodAndCache(mbrName.constData());
332 333 if (found) {
333 334 return _cachedMembers.value(mbrName);
334 335 }
335 336 }
336 337 }
337 338 if (!found) {
338 339 // we store a NotFound member, so that we get a quick result for non existing members (e.g. operator_equal lookup)
339 340 info._type = PythonQtMemberInfo::NotFound;
340 341 _cachedMembers.insert(memberName, info);
341 342 }
342 343 }
343 344
344 345 return _cachedMembers.value(memberName);
345 346 }
346 347
347 348 void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects) {
348 349 QObject* deco = decorator();
349 350 if (deco) {
350 351 decoratorObjects.append(deco);
351 352 }
352 353 foreach(const ParentClassInfo& info, _parentClasses) {
353 354 info._parent->recursiveCollectDecoratorObjects(decoratorObjects);
354 355 }
355 356 }
356 357
357 358 void PythonQtClassInfo::recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects) {
358 359 classInfoObjects.append(this);
359 360 foreach(const ParentClassInfo& info, _parentClasses) {
360 361 info._parent->recursiveCollectClassInfos(classInfoObjects);
361 362 }
362 363 }
363 364
364 365 PythonQtSlotInfo* PythonQtClassInfo::findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset)
365 366 {
366 367 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
367 368 while (it.hasNext()) {
368 369
369 370 PythonQtSlotInfo* infoOrig = it.next();
370 371
371 372 const char* sigStart = infoOrig->metaMethod()->signature();
372 373 if (qstrncmp("static_", sigStart, 7)==0) {
373 374 sigStart += 7;
374 375 sigStart += findCharOffset(sigStart, '_')+1;
375 376 }
376 377 int offset = findCharOffset(sigStart, '(');
377 378 if (memberNameLen == offset && qstrncmp(memberName, sigStart, offset)==0) {
378 379 //make a copy, otherwise we will have trouble on overloads!
379 380 PythonQtSlotInfo* info = new PythonQtSlotInfo(*infoOrig);
380 381 info->setUpcastingOffset(upcastingOffset);
381 382 found = true;
382 383 if (tail) {
383 384 tail->setNextInfo(info);
384 385 } else {
385 386 PythonQtMemberInfo newInfo(info);
386 387 memberCache.insert(memberName, newInfo);
387 388 }
388 389 tail = info;
389 390 }
390 391 }
391 392 return tail;
392 393 }
393 394
394 395 void PythonQtClassInfo::listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly) {
395 396 QObject* decoratorProvider = decorator();
396 397 if (decoratorProvider) {
397 398 const QMetaObject* meta = decoratorProvider->metaObject();
398 399 int numMethods = meta->methodCount();
399 400 int startFrom = QObject::staticMetaObject.methodCount();
400 401 for (int i = startFrom; i < numMethods; i++) {
401 402 QMetaMethod m = meta->method(i);
402 403 if ((m.methodType() == QMetaMethod::Method ||
403 404 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
404 405
405 406 const char* sigStart = m.signature();
406 407 bool isClassDeco = false;
407 408 if (qstrncmp(sigStart, "static_", 7)==0) {
408 409 // skip the static_classname_ part of the string
409 410 sigStart += 7 + 1 + strlen(className());
410 411 isClassDeco = true;
411 412 } else if (qstrncmp(sigStart, "new_", 4)==0) {
412 413 continue;
413 414 } else if (qstrncmp(sigStart, "delete_", 7)==0) {
414 415 continue;
415 416 } else if (qstrncmp(sigStart, "py_", 3)==0) {
416 417 // hide everything that starts with py_
417 418 continue;
418 419 }
419 420 // find the first '('
420 421 int offset = findCharOffset(sigStart, '(');
421 422
422 423 // XXX no checking is currently done if the slots have correct first argument or not...
423 424 if (!metaOnly || isClassDeco) {
424 425 list << QString::fromLatin1(sigStart, offset);
425 426 }
426 427 }
427 428 }
428 429 }
429 430
430 431 // look for global decorator slots
431 432 QListIterator<PythonQtSlotInfo*> it(_decoratorSlots);
432 433 while (it.hasNext()) {
433 434 PythonQtSlotInfo* slot = it.next();
434 435 if (metaOnly) {
435 436 if (slot->isClassDecorator()) {
436 437 QByteArray first = slot->slotName();
437 438 if (first.startsWith("static_")) {
438 439 int idx = first.indexOf('_');
439 440 idx = first.indexOf('_', idx+1);
440 441 first = first.mid(idx+1);
441 442 }
442 443 list << first;
443 444 }
444 445 } else {
445 446 list << slot->slotName();
446 447 }
447 448 }
448 449 }
449 450
450 451 QStringList PythonQtClassInfo::propertyList()
451 452 {
452 453 QStringList l;
453 454 if (_isQObject && _meta) {
454 455 int i;
455 456 int numProperties = _meta->propertyCount();
456 457 for (i = 0; i < numProperties; i++) {
457 458 QMetaProperty p = _meta->property(i);
458 459 l << QString(p.name());
459 460 }
460 461 }
461 462 return l;
462 463 }
463 464
464 465 QStringList PythonQtClassInfo::memberList(bool metaOnly)
465 466 {
466 467 decorator();
467 468
468 469 QStringList l;
469 470 QString h;
470 471 if (_isQObject && _meta && !metaOnly) {
471 472 l = propertyList();
472 473 }
473 474
474 475 // normal slots of QObject (or wrapper QObject)
475 476 if (!metaOnly && _meta) {
476 477 int numMethods = _meta->methodCount();
477 478 bool skipQObj = !_isQObject;
478 479 for (int i = skipQObj?QObject::staticMetaObject.methodCount():0; i < numMethods; i++) {
479 480 QMetaMethod m = _meta->method(i);
480 481 if (((m.methodType() == QMetaMethod::Method ||
481 482 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public)
482 483 || m.methodType()==QMetaMethod::Signal) {
483 484 QByteArray signa(m.signature());
484 485 signa = signa.left(signa.indexOf('('));
485 486 l << signa;
486 487 }
487 488 }
488 489 }
489 490
490 491 {
491 492 // look for dynamic decorators in this class and in derived classes
492 493 QList<PythonQtClassInfo*> infos;
493 494 recursiveCollectClassInfos(infos);
494 495 foreach(PythonQtClassInfo* info, infos) {
495 496 info->listDecoratorSlotsFromDecoratorProvider(l, metaOnly);
496 497 }
497 498 }
498 499
499 500 // List enumerator keys...
500 501 QList<const QMetaObject*> enumMetaObjects;
501 502 if (_meta) {
502 503 enumMetaObjects << _meta;
503 504 }
504 505 // check enums in the class hierachy of CPP classes
505 506 QList<QObject*> decoObjects;
506 507 recursiveCollectDecoratorObjects(decoObjects);
507 508 foreach(QObject* deco, decoObjects) {
508 509 enumMetaObjects << deco->metaObject();
509 510 }
510 511
511 512 foreach(const QMetaObject* meta, enumMetaObjects) {
512 513 for (int i = 0; i<meta->enumeratorCount(); i++) {
513 514 QMetaEnum e = meta->enumerator(i);
514 515 l << e.name();
515 516 // we do not want flags, they will cause our values to appear two times
516 517 if (e.isFlag()) continue;
517 518
518 519 for (int j=0; j < e.keyCount(); j++) {
519 520 l << QString(e.key(j));
520 521 }
521 522 }
522 523 }
523 524
524 525 return QSet<QString>::fromList(l).toList();
525 526 }
526 527
527 528 const char* PythonQtClassInfo::className()
528 529 {
529 530 return _wrappedClassName.constData();
530 531 }
531 532
532 533 void* PythonQtClassInfo::castTo(void* ptr, const char* classname)
533 534 {
534 535 if (ptr==NULL) {
535 536 return NULL;
536 537 }
537 538 if (_wrappedClassName == classname) {
538 539 return ptr;
539 540 }
540 541 foreach(const ParentClassInfo& info, _parentClasses) {
541 542 void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname);
542 543 if (result) {
543 544 return result;
544 545 }
545 546 }
546 547 return NULL;
547 548 }
548 549
549 550 bool PythonQtClassInfo::inherits(const char* name)
550 551 {
551 552 if (_wrappedClassName == name) {
552 553 return true;
553 554 }
554 555 foreach(const ParentClassInfo& info, _parentClasses) {
555 556 if (info._parent->inherits(name)) {
556 557 return true;
557 558 }
558 559 }
559 560 return false;
560 561 }
561 562
562 563 bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo)
563 564 {
564 565 if (classInfo == this) {
565 566 return true;
566 567 }
567 568 foreach(const ParentClassInfo& info, _parentClasses) {
568 569 if (info._parent->inherits(classInfo)) {
569 570 return true;
570 571 }
571 572 }
572 573 return false;
573 574 }
574 575
575 576 QString PythonQtClassInfo::help()
576 577 {
577 578 decorator();
578 579 QString h;
579 580 h += QString("--- ") + QString(className()) + QString(" ---\n");
580 581
581 582 if (_isQObject) {
582 583 h += "Properties:\n";
583 584
584 585 int i;
585 586 int numProperties = _meta->propertyCount();
586 587 for (i = 0; i < numProperties; i++) {
587 588 QMetaProperty p = _meta->property(i);
588 589 h += QString(p.name()) + " (" + QString(p.typeName()) + " )\n";
589 590 }
590 591 }
591 592
592 593 if (constructors()) {
593 594 h += "Constructors:\n";
594 595 PythonQtSlotInfo* constr = constructors();
595 596 while (constr) {
596 597 h += constr->fullSignature() + "\n";
597 598 constr = constr->nextInfo();
598 599 }
599 600 }
600 601
601 602 h += "Slots:\n";
602 603 h += "QString help()\n";
603 604 h += "QString className()\n";
604 605
605 606 if (_meta) {
606 607 int numMethods = _meta->methodCount();
607 608 for (int i = 0; i < numMethods; i++) {
608 609 QMetaMethod m = _meta->method(i);
609 610 if ((m.methodType() == QMetaMethod::Method ||
610 611 m.methodType() == QMetaMethod::Slot) && m.access() == QMetaMethod::Public) {
611 612 PythonQtSlotInfo slot(this, m, i);
612 613 h += slot.fullSignature()+ "\n";
613 614 }
614 615 }
615 616 }
616 617
617 618 // TODO xxx : decorators and enums from decorator() are missing...
618 619 // maybe we can reuse memberlist()?
619 620
620 621 if (_meta && _meta->enumeratorCount()) {
621 622 h += "Enums:\n";
622 623 for (int i = 0; i<_meta->enumeratorCount(); i++) {
623 624 QMetaEnum e = _meta->enumerator(i);
624 625 h += QString(e.name()) + " {";
625 626 for (int j=0; j < e.keyCount(); j++) {
626 627 if (j) { h+= ", "; }
627 628 h += e.key(j);
628 629 }
629 630 h += " }\n";
630 631 }
631 632 }
632 633
633 634 if (_isQObject && _meta) {
634 635 int numMethods = _meta->methodCount();
635 636 if (numMethods>0) {
636 637 h += "Signals:\n";
637 638 for (int i = 0; i < numMethods; i++) {
638 639 QMetaMethod m = _meta->method(i);
639 640 if (m.methodType() == QMetaMethod::Signal) {
640 641 h += QString(m.signature()) + "\n";
641 642 }
642 643 }
643 644 }
644 645 }
645 646 return h;
646 647 }
647 648
648 649 PythonQtSlotInfo* PythonQtClassInfo::constructors()
649 650 {
650 651 if (!_constructors) {
651 652 // force creation of lazy decorator, which will register the decorators
652 653 decorator();
653 654 }
654 655 return _constructors;
655 656 }
656 657
657 658 PythonQtSlotInfo* PythonQtClassInfo::destructor()
658 659 {
659 660 if (!_destructor) {
660 661 // force creation of lazy decorator, which will register the decorators
661 662 decorator();
662 663 }
663 664 return _destructor;
664 665 }
665 666
666 667 void PythonQtClassInfo::addConstructor(PythonQtSlotInfo* info)
667 668 {
668 669 PythonQtSlotInfo* prev = constructors();
669 670 if (prev) {
670 671 info->setNextInfo(prev->nextInfo());
671 672 prev->setNextInfo(info);
672 673 } else {
673 674 _constructors = info;
674 675 }
675 676 }
676 677
677 678 void PythonQtClassInfo::addDecoratorSlot(PythonQtSlotInfo* info)
678 679 {
679 680 _decoratorSlots.append(info);
680 681 }
681 682
682 683 void PythonQtClassInfo::setDestructor(PythonQtSlotInfo* info)
683 684 {
684 685 if (_destructor) {
685 686 _destructor->deleteOverloadsAndThis();
686 687 }
687 688 _destructor = info;
688 689 }
689 690
690 691 void PythonQtClassInfo::setMetaObject(const QMetaObject* meta)
691 692 {
692 693 _meta = meta;
693 694 clearCachedMembers();
694 695 }
695 696
696 697 QObject* PythonQtClassInfo::decorator()
697 698 {
698 699 if (!_decoratorProvider && _decoratorProviderCB) {
699 700 _decoratorProvider = (*_decoratorProviderCB)();
700 701 if (_decoratorProvider) {
701 702 _decoratorProvider->setParent(PythonQt::priv());
702 703 // setup enums early, since they might be needed by the constructor decorators:
703 704 if (!_enumsCreated) {
704 705 createEnumWrappers();
705 706 }
706 707 PythonQt::priv()->addDecorators(_decoratorProvider, PythonQtPrivate::ConstructorDecorator | PythonQtPrivate::DestructorDecorator);
707 708 }
708 709 }
709 710 // check if enums need to be created and create them if they are not yet created
710 711 if (!_enumsCreated) {
711 712 createEnumWrappers();
712 713 }
713 714 return _decoratorProvider;
714 715 }
715 716
716 717 bool PythonQtClassInfo::hasOwnerMethodButNoOwner(void* object)
717 718 {
718 719 PythonQtMemberInfo info = member("py_hasOwner");
719 720 if (info._type == PythonQtMemberInfo::Slot) {
720 721 void* obj = object;
721 722 bool result = false;
722 723 void* args[2];
723 724 args[0] = &result;
724 725 args[1] = &obj;
725 726 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
726 727 return !result;
727 728 } else {
728 729 return false;
729 730 }
730 731 }
731 732
732 733 void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, char** resultClassName)
733 734 {
734 735 if (!_polymorphicHandlers.isEmpty()) {
735 736 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
736 737 void* resultPtr = (*cb)(ptr, resultClassName);
737 738 if (resultPtr) {
738 739 return resultPtr;
739 740 }
740 741 }
741 742 }
742 743 foreach(const ParentClassInfo& info, _parentClasses) {
743 744 if (!info._parent->isQObject()) {
744 745 void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName);
745 746 if (resultPtr) {
746 747 return resultPtr;
747 748 }
748 749 }
749 750 }
750 751 return NULL;
751 752 }
752 753
753 754 void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo)
754 755 {
755 756 char* className;
756 757 // this would do downcasting recursively...
757 758 // void* resultPtr = recursiveCastDownIfPossible(ptr, &className);
758 759
759 760 // we only do downcasting on the base object, not on the whole inheritance tree...
760 761 void* resultPtr = NULL;
761 762 if (!_polymorphicHandlers.isEmpty()) {
762 763 foreach(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) {
763 764 resultPtr = (*cb)(ptr, &className);
764 765 if (resultPtr) {
765 766 break;
766 767 }
767 768 }
768 769 }
769 770 if (resultPtr) {
770 771 *resultClassInfo = PythonQt::priv()->getClassInfo(className);
771 772 } else {
772 773 *resultClassInfo = this;
773 774 resultPtr = ptr;
774 775 }
775 776 return resultPtr;
776 777 }
777 778
778 779 PyObject* PythonQtClassInfo::findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum)
779 780 {
780 781 if (isLocalEnum) {
781 782 *isLocalEnum = true;
782 783 }
783 784 int scopePos = name.lastIndexOf("::");
784 785 if (scopePos != -1) {
785 786 if (isLocalEnum) {
786 787 *isLocalEnum = false;
787 788 }
788 789 // split into scope and enum name
789 790 QByteArray enumScope = name.mid(0,scopePos);
790 791 QByteArray enumName = name.mid(scopePos+2);
791 792 PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(enumScope);
792 793 if (info) {
793 794 return info->findEnumWrapper(enumName);
794 795 } else{
795 796 return NULL;
796 797 }
797 798 }
798 799 if (localScope) {
799 800 return localScope->findEnumWrapper(name);
800 801 } else {
801 802 return NULL;
802 803 }
803 804 }
804 805
805 806 void PythonQtClassInfo::createEnumWrappers(const QMetaObject* meta)
806 807 {
807 808 for (int i = meta->enumeratorOffset();i<meta->enumeratorCount();i++) {
808 809 QMetaEnum e = meta->enumerator(i);
809 810 PythonQtObjectPtr p;
810 811 p.setNewRef(PythonQtPrivate::createNewPythonQtEnumWrapper(e.name(), _pythonQtClassWrapper));
811 812 _enumWrappers.append(p);
812 813 }
813 814 }
814 815
815 816 void PythonQtClassInfo::createEnumWrappers()
816 817 {
817 818 if (!_enumsCreated) {
818 819 _enumsCreated = true;
819 820 if (_meta) {
820 821 createEnumWrappers(_meta);
821 822 }
822 823 if (decorator()) {
823 824 createEnumWrappers(decorator()->metaObject());
824 825 }
825 826 foreach(const ParentClassInfo& info, _parentClasses) {
826 827 info._parent->createEnumWrappers();
827 828 }
828 829 }
829 830 }
830 831
831 832 PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) {
832 833 // force enum creation
833 834 if (!_enumsCreated) {
834 835 createEnumWrappers();
835 836 }
836 837 foreach(const PythonQtObjectPtr& p, _enumWrappers) {
837 838 const char* className = ((PyTypeObject*)p.object())->tp_name;
838 839 if (qstrcmp(className, name)==0) {
839 840 return p.object();
840 841 }
841 842 }
842 843 foreach(const ParentClassInfo& info, _parentClasses) {
843 844 PyObject* p = info._parent->findEnumWrapper(name);
844 845 if (p) return p;
845 846 }
846 847 return NULL;
847 848 }
848 849
@@ -1,256 +1,262
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 //! set the type capabilities
108 void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
109 //! get the type capabilities
110 int typeSlots() const { return _typeSlots; }
111
107 112 //! get the Python method definition for a given slot name (without return type and signature)
108 113 PythonQtMemberInfo member(const char* member);
109 114
110 115 //! get access to the constructor slot (which may be overloaded if there are multiple constructors)
111 116 PythonQtSlotInfo* constructors();
112 117
113 118 //! get access to the destructor slot
114 119 PythonQtSlotInfo* destructor();
115 120
116 121 //! add a constructor, ownership is passed to classinfo
117 122 void addConstructor(PythonQtSlotInfo* info);
118 123
119 124 //! set a destructor, ownership is passed to classinfo
120 125 void setDestructor(PythonQtSlotInfo* info);
121 126
122 127 //! add a decorator slot, ownership is passed to classinfo
123 128 void addDecoratorSlot(PythonQtSlotInfo* info);
124 129
125 130 //! get the classname (either of the QObject or of the wrapped CPP object)
126 131 const char* className();
127 132
128 133 //! returns if the QObject
129 134 bool isQObject() { return _isQObject; }
130 135
131 136 //! returns if the class is a CPP wrapper
132 137 bool isCPPWrapper() { return !_isQObject; }
133 138
134 139 //! get the meta object
135 140 const QMetaObject* metaObject() { return _meta; }
136 141
137 142 //! set the meta object, this will reset the caching
138 143 void setMetaObject(const QMetaObject* meta);
139 144
140 145 //! returns if this class inherits from the given classname
141 146 bool inherits(const char* classname);
142 147
143 148 //! returns if this class inherits from the given classinfo
144 149 bool inherits(PythonQtClassInfo* info);
145 150
146 151 //! casts the given \c ptr to an object of type \c classname, returns the new pointer
147 152 //! which might be different to \c ptr due to C++ multiple inheritance
148 153 //! (if the cast is not possible or if ptr is NULL, NULL is returned)
149 154 void* castTo(void* ptr, const char* classname);
150 155
151 156 //! get help string for the metaobject
152 157 QString help();
153 158
154 159 //! get list of all properties (on QObjects only, otherwise the list is empty)
155 160 QStringList propertyList();
156 161
157 162 //! get list of all members
158 163 QStringList memberList(bool metaOnly = false);
159 164
160 165 //! get the meta type id of this class (only valid for isCPPWrapper() == true)
161 166 int metaTypeId() { return _metaTypeId; }
162 167
163 168 //! set an additional decorator provider that offers additional decorator slots for this class
164 169 void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb) { _decoratorProviderCB = cb; _decoratorProvider = NULL; }
165 170
166 171 //! get the decorator qobject instance
167 172 QObject* decorator();
168 173
169 174 //! add the parent class info of a CPP object
170 175 void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
171 176
172 177 //! check if the special method "py_hasOwner" is implemented and if it returns false, which means that the object may be destroyed
173 178 bool hasOwnerMethodButNoOwner(void* object);
174 179
175 180 //! set the associated PythonQtClassWrapper (which handles instance creation of this type)
176 181 void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
177 182
178 183 //! get the associated PythonQtClassWrapper (which handles instance creation of this type)
179 184 PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
180 185
181 186 //! set the shell set instance wrapper cb
182 187 void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
183 188 _shellSetInstanceWrapperCB = cb;
184 189 }
185 190
186 191 //! get the shell set instance wrapper cb
187 192 PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
188 193 return _shellSetInstanceWrapperCB;
189 194 }
190 195
191 196 //! add a handler for polymorphic downcasting
192 197 void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
193 198
194 199 //! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
195 200 void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
196 201
197 202 //! 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 203 static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
199 204
200 205 private:
201 206 void createEnumWrappers();
202 207 void createEnumWrappers(const QMetaObject* meta);
203 208 PyObject* findEnumWrapper(const char* name);
204 209
205 210 //! clear all cached members
206 211 void clearCachedMembers();
207 212
208 213 void* recursiveCastDownIfPossible(void* ptr, char** resultClassName);
209 214
210 215 PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
211 216 void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
212 217 PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
213 218
214 219 void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
215 220 void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
216 221
217 222 bool lookForPropertyAndCache(const char* memberName);
218 223 bool lookForMethodAndCache(const char* memberName);
219 224 bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
220 225
221 226 PythonQtSlotInfo* findDecoratorSlots(const char* memberName, int memberNameLen, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
222 227 int findCharOffset(const char* sigStart, char someChar);
223 228
224 229 QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
225 230
226 231 PythonQtSlotInfo* _constructors;
227 232 PythonQtSlotInfo* _destructor;
228 233 QList<PythonQtSlotInfo*> _decoratorSlots;
229 234
230 235 QList<PythonQtObjectPtr> _enumWrappers;
231 236
232 237 const QMetaObject* _meta;
233 238
234 239 QByteArray _wrappedClassName;
235 240 QList<ParentClassInfo> _parentClasses;
236 241
237 242 QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
238 243
239 244 QObject* _decoratorProvider;
240 245 PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
241 246
242 247 PyObject* _pythonQtClassWrapper;
243 248
244 249 PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
245 250
246 251 int _metaTypeId;
252 int _typeSlots;
247 253
248 254 bool _isQObject;
249 255 bool _enumsCreated;
250 256
251 257 };
252 258
253 259 //---------------------------------------------------------------
254 260
255 261
256 262 #endif
@@ -1,290 +1,452
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 PythonQtClassWrapper.cpp
36 36 // \author Florian Link
37 37 // \author Last changed by $Author: florian $
38 38 // \date 2006-05
39 39 */
40 40 //----------------------------------------------------------------------------------
41 41
42 42 #include "PythonQtClassWrapper.h"
43 43 #include <QObject>
44 44
45 45 #include "PythonQt.h"
46 46 #include "PythonQtSlot.h"
47 47 #include "PythonQtClassInfo.h"
48 48 #include "PythonQtConversion.h"
49 49 #include "PythonQtInstanceWrapper.h"
50 50
51 static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
52 {
53 PyObject* result = NULL;
54 static QByteArray memberName = "__invert__";
55 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
56 if (opSlot._type == PythonQtMemberInfo::Slot) {
57 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
58 }
59 return result;
60 }
61
62 static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
63 {
64 int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
65 if (result) {
66 static QByteArray memberName = "__nonzero__";
67 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
68 if (opSlot._type == PythonQtMemberInfo::Slot) {
69 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
70 if (resultObj == Py_False) {
71 result = 0;
72 }
73 Py_XDECREF(resultObj);
74 }
75 }
76 return result;
77 }
78
79
80 static PyObject* PythonQtInstanceWrapper_binaryfunc(PythonQtInstanceWrapper* wrapper, PyObject* other, const QByteArray& opName, const QByteArray& fallbackOpName = QByteArray())
81 {
82 PyObject* result = NULL;
83 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(opName);
84 if (opSlot._type == PythonQtMemberInfo::Slot) {
85 // TODO get rid of tuple
86 PyObject* args = PyTuple_New(1);
87 Py_INCREF(other);
88 PyTuple_SET_ITEM(args, 0, other);
89 result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
90 Py_DECREF(args);
91 if (!result && !fallbackOpName.isEmpty()) {
92 // try fallback if we did not get a result
93 result = PythonQtInstanceWrapper_binaryfunc(wrapper, other, fallbackOpName);
94 }
95 }
96 return result;
97 }
98
99 #define BINARY_OP(NAME) \
100 static PyObject* PythonQtInstanceWrapper_ ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
101 { \
102 static const QByteArray opName("__" #NAME "__"); \
103 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName); \
104 }
105
106 #define BINARY_OP_INPLACE(NAME) \
107 static PyObject* PythonQtInstanceWrapper_i ## NAME(PythonQtInstanceWrapper* wrapper, PyObject* other) \
108 { \
109 static const QByteArray opName("__i" #NAME "__"); \
110 static const QByteArray fallbackName("__" #NAME "__"); \
111 return PythonQtInstanceWrapper_binaryfunc(wrapper, other, opName, fallbackName); \
112 }
113
114 BINARY_OP(add)
115 BINARY_OP(sub)
116 BINARY_OP(mul)
117 BINARY_OP(div)
118 BINARY_OP(and)
119 BINARY_OP(or)
120 BINARY_OP(xor)
121 BINARY_OP(mod)
122 BINARY_OP(lshift)
123 BINARY_OP(rshift)
124
125 BINARY_OP_INPLACE(add)
126 BINARY_OP_INPLACE(sub)
127 BINARY_OP_INPLACE(mul)
128 BINARY_OP_INPLACE(div)
129 BINARY_OP_INPLACE(and)
130 BINARY_OP_INPLACE(or)
131 BINARY_OP_INPLACE(xor)
132 BINARY_OP_INPLACE(mod)
133 BINARY_OP_INPLACE(lshift)
134 BINARY_OP_INPLACE(rshift)
135
136 static void initializeSlots(PythonQtClassWrapper* wrap)
137 {
138 int typeSlots = wrap->classInfo()->typeSlots();
139 if (typeSlots) {
140 if (typeSlots & PythonQt::Type_Add) {
141 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_add;
142 }
143 if (typeSlots & PythonQt::Type_Subtract) {
144 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_sub;
145 }
146 if (typeSlots & PythonQt::Type_Multiply) {
147 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul;
148 }
149 if (typeSlots & PythonQt::Type_Divide) {
150 wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div;
151 wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div;
152 }
153 if (typeSlots & PythonQt::Type_And) {
154 wrap->_base.as_number.nb_and = (binaryfunc)PythonQtInstanceWrapper_and;
155 }
156 if (typeSlots & PythonQt::Type_Or) {
157 wrap->_base.as_number.nb_or = (binaryfunc)PythonQtInstanceWrapper_or;
158 }
159 if (typeSlots & PythonQt::Type_Xor) {
160 wrap->_base.as_number.nb_xor = (binaryfunc)PythonQtInstanceWrapper_xor;
161 }
162 if (typeSlots & PythonQt::Type_Mod) {
163 wrap->_base.as_number.nb_remainder = (binaryfunc)PythonQtInstanceWrapper_mod;
164 }
165 if (typeSlots & PythonQt::Type_LShift) {
166 wrap->_base.as_number.nb_lshift = (binaryfunc)PythonQtInstanceWrapper_lshift;
167 }
168 if (typeSlots & PythonQt::Type_RShift) {
169 wrap->_base.as_number.nb_rshift = (binaryfunc)PythonQtInstanceWrapper_rshift;
170 }
171
172 if (typeSlots & PythonQt::Type_InplaceAdd) {
173 wrap->_base.as_number.nb_add = (binaryfunc)PythonQtInstanceWrapper_iadd;
174 }
175 if (typeSlots & PythonQt::Type_InplaceSubtract) {
176 wrap->_base.as_number.nb_subtract = (binaryfunc)PythonQtInstanceWrapper_isub;
177 }
178 if (typeSlots & PythonQt::Type_InplaceMultiply) {
179 wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_imul;
180 }
181 if (typeSlots & PythonQt::Type_InplaceDivide) {
182 wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
183 wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv;
184 }
185 if (typeSlots & PythonQt::Type_InplaceAnd) {
186 wrap->_base.as_number.nb_inplace_and = (binaryfunc)PythonQtInstanceWrapper_iand;
187 }
188 if (typeSlots & PythonQt::Type_InplaceOr) {
189 wrap->_base.as_number.nb_inplace_or = (binaryfunc)PythonQtInstanceWrapper_ior;
190 }
191 if (typeSlots & PythonQt::Type_InplaceXor) {
192 wrap->_base.as_number.nb_inplace_xor = (binaryfunc)PythonQtInstanceWrapper_ixor;
193 }
194 if (typeSlots & PythonQt::Type_InplaceMod) {
195 wrap->_base.as_number.nb_inplace_remainder = (binaryfunc)PythonQtInstanceWrapper_imod;
196 }
197 if (typeSlots & PythonQt::Type_InplaceLShift) {
198 wrap->_base.as_number.nb_inplace_lshift = (binaryfunc)PythonQtInstanceWrapper_ilshift;
199 }
200 if (typeSlots & PythonQt::Type_InplaceRShift) {
201 wrap->_base.as_number.nb_inplace_rshift = (binaryfunc)PythonQtInstanceWrapper_irshift;
202 }
203 if (typeSlots & PythonQt::Type_Invert) {
204 wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert;
205 }
206 if (typeSlots & PythonQt::Type_NonZero) {
207 wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero;
208 }
209 }
210 }
211
51 212 static PyObject* PythonQtClassWrapper_alloc(PyTypeObject *self, Py_ssize_t nitems)
52 213 {
53 214 // call the default type alloc
54 215 PyObject* obj = PyType_Type.tp_alloc(self, nitems);
55 216
56 217 // take current class type, if we are called via newPythonQtClassWrapper()
57 218 PythonQtClassWrapper* wrap = (PythonQtClassWrapper*)obj;
58 219 wrap->_classInfo = PythonQt::priv()->currentClassInfoForClassWrapperCreation();
220 initializeSlots(wrap);
59 221
60 222 return obj;
61 223 }
62 224
63 225
64 226 static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
65 227 {
66 228 // call the default type init
67 229 if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
68 230 return -1;
69 231 }
70 232
71 233 // if we have no CPP class information, try our base class
72 234 if (!self->classInfo()) {
73 235 PyTypeObject* superType = ((PyTypeObject *)self)->tp_base;
74 236
75 237 if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
76 238 PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
77 239 return -1;
78 240 }
79 241
80 242 // take the class info from the superType
81 243 self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
82 244 }
83 245
84 246 return 0;
85 247 }
86 248
87 249 static PyObject *PythonQtClassWrapper_classname(PythonQtClassWrapper* type)
88 250 {
89 251 return PyString_FromString((QString("Class_") + type->classInfo()->className()).toLatin1().data());
90 252 }
91 253
92 254 static PyObject *PythonQtClassWrapper_help(PythonQtClassWrapper* type)
93 255 {
94 256 return PythonQt::self()->helpCalled(type->classInfo());
95 257 }
96 258
97 259 PyObject *PythonQtClassWrapper__init__(PythonQtClassWrapper *type, PyObject *args)
98 260 {
99 261 Py_ssize_t argc = PyTuple_Size(args);
100 262 if (argc>0) {
101 263 // we need to call __init__ of the instance
102 264 PyObject* self = PyTuple_GET_ITEM(args, 0);
103 265 if (PyObject_TypeCheck(self, (PyTypeObject*)type->classInfo()->pythonQtClassWrapper())) {
104 266 PyObject* newargs = PyTuple_New(argc-1);
105 267 for (int i = 0;i<argc-1; i++) {
106 268 PyTuple_SET_ITEM(newargs, i,PyTuple_GET_ITEM(args, i+1));
107 269 }
108 270 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)self;
109 271 int result = PythonQtInstanceWrapper_init(wrapper, newargs, NULL);
110 272 Py_DECREF(newargs);
111 273 if (result==0) {
112 274 Py_INCREF(Py_None);
113 275 return Py_None;
114 276 } else {
115 277 // init failed!
116 278 }
117 279 } else {
118 280 // self not of correct type!
119 281 }
120 282 } else {
121 283 // wrong number of args
122 284 }
123 285 return NULL;
124 286 }
125 287
126 288 static PyMethodDef PythonQtClassWrapper_methods[] = {
127 289 {"__init__", (PyCFunction)PythonQtClassWrapper__init__, METH_VARARGS,
128 290 "Return the classname of the object"
129 291 },
130 292 {"className", (PyCFunction)PythonQtClassWrapper_classname, METH_NOARGS,
131 293 "Return the classname of the object"
132 294 },
133 295 {"help", (PyCFunction)PythonQtClassWrapper_help, METH_NOARGS,
134 296 "Shows the help of available methods for this class"
135 297 },
136 298 {NULL, NULL, 0 , NULL} /* Sentinel */
137 299 };
138 300
139 301
140 302 static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name)
141 303 {
142 304 const char *attributeName;
143 305 PythonQtClassWrapper *wrapper = (PythonQtClassWrapper *)obj;
144 306
145 307 if ((attributeName = PyString_AsString(name)) == NULL) {
146 308 return NULL;
147 309 }
148 310 if (obj == (PyObject*)&PythonQtInstanceWrapper_Type) {
149 311 return NULL;
150 312 }
151 313
152 314 if (qstrcmp(attributeName, "__dict__")==0) {
153 315 PyObject* dict = ((PyTypeObject *)wrapper)->tp_dict;
154 316 if (!wrapper->classInfo()) {
155 317 Py_INCREF(dict);
156 318 return dict;
157 319 }
158 320 dict = PyDict_Copy(dict);
159 321
160 322 QStringList l = wrapper->classInfo()->memberList(false);
161 323 foreach (QString name, l) {
162 324 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
163 325 if (o) {
164 326 PyDict_SetItemString(dict, name.toLatin1().data(), o);
165 327 Py_DECREF(o);
166 328 } else {
167 329 // it must have been a property or child, which we do not know as a class object...
168 330 }
169 331 }
170 332 if (wrapper->classInfo()->constructors()) {
171 333 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[0], obj);
172 334 PyDict_SetItemString(dict, "__init__", func);
173 335 Py_DECREF(func);
174 336 }
175 337 for (int i = 1;i<3;i++) {
176 338 PyObject* func = PyCFunction_New(&PythonQtClassWrapper_methods[i], obj);
177 339 PyDict_SetItemString(dict, PythonQtClassWrapper_methods[i].ml_name, func);
178 340 Py_DECREF(func);
179 341 }
180 342 return dict;
181 343 }
182 344
183 345 if (wrapper->classInfo()) {
184 346 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
185 347 if (member._type == PythonQtMemberInfo::EnumValue) {
186 348 PyObject* enumValue = member._enumValue;
187 349 Py_INCREF(enumValue);
188 350 return enumValue;
189 351 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
190 352 PyObject* enumWrapper = member._enumWrapper;
191 353 Py_INCREF(enumWrapper);
192 354 return enumWrapper;
193 355 } else if (member._type == PythonQtMemberInfo::Slot) {
194 356 // we return all slots, even the instance slots, since they are callable as unbound slots with self argument
195 357 return PythonQtSlotFunction_New(member._slot, obj, NULL);
196 358 }
197 359 }
198 360
199 361 // look for the interal methods (className(), help())
200 362 PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName);
201 363 if (internalMethod) {
202 364 return internalMethod;
203 365 }
204 366 PyErr_Clear();
205 367
206 368 // look in super
207 369 PyObject* superAttr = PyType_Type.tp_getattro(obj, name);
208 370 if (superAttr) {
209 371 return superAttr;
210 372 }
211 373
212 374 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
213 375 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
214 376 return NULL;
215 377 }
216 378
217 379 static int PythonQtClassWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
218 380 {
219 381 return PyType_Type.tp_setattro(obj,name,value);
220 382 }
221 383
222 384 /*
223 385 static PyObject * PythonQtClassWrapper_repr(PyObject * obj)
224 386 {
225 387 PythonQtClassWrapper* wrapper = (PythonQtClassWrapper*)obj;
226 388 if (wrapper->classInfo()->isCPPWrapper()) {
227 389 const QMetaObject* meta = wrapper->classInfo()->metaObject();
228 390 if (!meta) {
229 391 QObject* decorator = wrapper->classInfo()->decorator();
230 392 if (decorator) {
231 393 meta = decorator->metaObject();
232 394 }
233 395 }
234 396 if (meta) {
235 397 return PyString_FromFormat("%s Class (C++ wrapped by %s)", wrapper->classInfo()->className(), meta->className());
236 398 } else {
237 399 return PyString_FromFormat("%s Class (C++ unwrapped)", wrapper->classInfo()->className());
238 400 }
239 401 } else {
240 402 return PyString_FromFormat("%s Class", wrapper->classInfo()->className());
241 403 }
242 404 }
243 405
244 406 */
245 407
246 408 PyTypeObject PythonQtClassWrapper_Type = {
247 409 PyObject_HEAD_INIT(NULL)
248 410 0, /*ob_size*/
249 411 "PythonQt.PythonQtClassWrapper", /*tp_name*/
250 412 sizeof(PythonQtClassWrapper), /*tp_basicsize*/
251 413 0, /*tp_itemsize*/
252 414 0, /*tp_dealloc*/
253 415 0, /*tp_print*/
254 416 0, /*tp_getattr*/
255 417 0, /*tp_setattr*/
256 418 0, /*tp_compare*/
257 419 0, //PythonQtClassWrapper_repr, /*tp_repr*/
258 420 0, /*tp_as_number*/
259 421 0, /*tp_as_sequence*/
260 422 0, /*tp_as_mapping*/
261 423 0, /*tp_hash */
262 424 0, /*tp_call*/
263 425 0, /*tp_str*/
264 426 PythonQtClassWrapper_getattro, /*tp_getattro*/
265 427 PythonQtClassWrapper_setattro, /*tp_setattro*/
266 428 0, /*tp_as_buffer*/
267 429 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
268 430 0, /* tp_doc */
269 431 0, /* tp_traverse */
270 432 0, /* tp_clear */
271 433 0, /* tp_richcompare */
272 434 0, /* tp_weaklistoffset */
273 435 0, /* tp_iter */
274 436 0, /* tp_iternext */
275 437 0, /* tp_methods */
276 438 0, /* tp_members */
277 439 0, /* tp_getset */
278 440 0, /* tp_base */
279 441 0, /* tp_dict */
280 442 0, /* tp_descr_get */
281 443 0, /* tp_descr_set */
282 444 0, /* tp_dictoffset */
283 445 (initproc)PythonQtClassWrapper_init, /* tp_init */
284 446 PythonQtClassWrapper_alloc, /* tp_alloc */
285 447 0, /* tp_new */
286 448 0, /* tp_free */
287 449 };
288 450
289 451 //-------------------------------------------------------
290 452
@@ -1,671 +1,715
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 static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
187 {
188 bool validPtrs = false;
189 bool areSamePtrs = false;
190 if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
191 if (PyObject_TypeCheck(other, &PythonQtInstanceWrapper_Type)) {
192 validPtrs = true;
193 PythonQtInstanceWrapper* w1 = wrapper;
194 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)other;
195 // check pointers directly
196 if (w1->_wrappedPtr != NULL) {
197 if (w1->_wrappedPtr == w2->_wrappedPtr) {
198 areSamePtrs = true;
199 }
200 } else if (w1->_obj == w2->_obj) {
201 areSamePtrs = true;
202 }
203 } else if (other == Py_None) {
204 validPtrs = true;
205 if (wrapper->_obj || wrapper->_wrappedPtr) {
206 areSamePtrs = false;
207 } else {
208 areSamePtrs = true;
209 }
210 }
211 }
212
213 if ((wrapper->classInfo()->typeSlots() & PythonQt::Type_RichCompare) == 0) {
214 // shortcut if richcompare is not supported:
215 if (validPtrs && code == Py_EQ) {
216 return PythonQtConv::GetPyBool(areSamePtrs);
217 } else if (validPtrs && code == Py_NE) {
218 return PythonQtConv::GetPyBool(!areSamePtrs);
219 }
220 Py_INCREF(Py_NotImplemented);
221 return Py_NotImplemented;
222 }
223
224 QByteArray memberName;
225 switch (code) {
226 case Py_LT:
227 {
228 static QByteArray name = "__lt__";
229 memberName = name;
230 }
231 break;
232
233 case Py_LE:
234 {
235 static QByteArray name = "__le__";
236 memberName = name;
237 }
238 break;
239
240 case Py_EQ:
241 {
242 static QByteArray name = "__eq__";
243 memberName = name;
244 }
245 break;
246
247 case Py_NE:
248 {
249 static QByteArray name = "__ne__";
250 memberName = name;
251 }
252 break;
253
254 case Py_GT:
255 {
256 static QByteArray name = "__gt__";
257 memberName = name;
258 }
259 break;
260
261 case Py_GE:
262 {
263 static QByteArray name = "__ge__";
264 memberName = name;
265 }
266 break;
267 }
268
269 PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
270 if (opSlot._type == PythonQtMemberInfo::Slot) {
271 // TODO get rid of tuple
272 PyObject* args = PyTuple_New(1);
273 Py_INCREF(other);
274 PyTuple_SET_ITEM(args, 0, other);
275 PyObject* result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, args, NULL, wrapper->_wrappedPtr);
276 Py_DECREF(args);
277 return result;
278 } else {
279 // not implemented, let python try something else!
280 Py_INCREF(Py_NotImplemented);
281 return Py_NotImplemented;
282 }
283 }
284
285
186 286 static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
187 287 {
188 288 return PyString_FromString(obj->ob_type->tp_name);
189 289 }
190 290
191 291 static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
192 292 {
193 293 return PythonQt::self()->helpCalled(obj->classInfo());
194 294 }
195 295
196 296 static PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
197 297 {
198 298 PythonQtInstanceWrapper_deleteObject(self, true);
199 299 Py_INCREF(Py_None);
200 300 return Py_None;
201 301 }
202 302
203 303
204 304 static PyMethodDef PythonQtInstanceWrapper_methods[] = {
205 305 {"className", (PyCFunction)PythonQtInstanceWrapper_classname, METH_NOARGS,
206 306 "Return the classname of the object"
207 307 },
208 308 {"help", (PyCFunction)PythonQtInstanceWrapper_help, METH_NOARGS,
209 309 "Shows the help of available methods for this class"
210 310 },
211 311 {"delete", (PyCFunction)PythonQtInstanceWrapper_delete, METH_NOARGS,
212 312 "Deletes the C++ object (at your own risk, my friend!)"
213 313 },
214 314 {NULL, NULL, 0, NULL} /* Sentinel */
215 315 };
216 316
217 317
218 318 static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
219 319 {
220 320 const char *attributeName;
221 321 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
222 322
223 323 if ((attributeName = PyString_AsString(name)) == NULL) {
224 324 return NULL;
225 325 }
226 326
227 327 if (qstrcmp(attributeName, "__dict__")==0) {
228 328 PyObject* dict = PyBaseObject_Type.tp_getattro(obj, name);
229 329 dict = PyDict_Copy(dict);
230 330
231 331 if (wrapper->_obj) {
232 332 // only the properties are missing, the rest is already available from
233 333 // PythonQtClassWrapper...
234 334 QStringList l = wrapper->classInfo()->propertyList();
235 335 foreach (QString name, l) {
236 336 PyObject* o = PyObject_GetAttrString(obj, name.toLatin1().data());
237 337 if (o) {
238 338 PyDict_SetItemString(dict, name.toLatin1().data(), o);
239 339 Py_DECREF(o);
240 340 } else {
241 341 std::cerr << "PythonQtInstanceWrapper: something is wrong, could not get attribute " << name.toLatin1().data();
242 342 }
243 343 }
244 344
245 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
345 QList<QByteArray> dynamicProps = wrapper->_obj->dynamicPropertyNames();
246 346 foreach (QByteArray name, dynamicProps) {
247 347 PyObject* o = PyObject_GetAttrString(obj, name.data());
248 348 if (o) {
249 349 PyDict_SetItemString(dict, name.data(), o);
250 350 Py_DECREF(o);
251 351 } else {
252 352 std::cerr << "PythonQtInstanceWrapper: dynamic property could not be read " << name.data();
253 353 }
254 354 }
255 355 }
256 356 // Note: we do not put children into the dict, is would look confusing?!
257 357 return dict;
258 358 }
259 359
260 360 // first look in super, to return derived methods from base object first
261 361 PyObject* superAttr = PyBaseObject_Type.tp_getattro(obj, name);
262 362 if (superAttr) {
263 363 return superAttr;
264 364 }
265 365 PyErr_Clear();
266 366
267 367 // mlabDebugConst("Python","get " << attributeName);
268 368
269 369 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
270 370 switch (member._type) {
271 371 case PythonQtMemberInfo::Property:
272 372 if (wrapper->_obj) {
273 373 if (member._property.userType() != QVariant::Invalid) {
274 374 return PythonQtConv::QVariantToPyObject(member._property.read(wrapper->_obj));
275 375 } else {
276 376 Py_INCREF(Py_None);
277 377 return Py_None;
278 378 }
279 379 } else {
280 380 QString error = QString("Trying to read property '") + attributeName + "' from a destroyed " + wrapper->classInfo()->className() + " object";
281 381 PyErr_SetString(PyExc_ValueError, error.toLatin1().data());
282 382 return NULL;
283 383 }
284 384 break;
285 385 case PythonQtMemberInfo::Slot:
286 386 return PythonQtSlotFunction_New(member._slot, obj, NULL);
287 387 break;
288 388 case PythonQtMemberInfo::EnumValue:
289 389 {
290 390 PyObject* enumValue = member._enumValue;
291 391 Py_INCREF(enumValue);
292 392 return enumValue;
293 393 }
294 394 break;
295 395 case PythonQtMemberInfo::EnumWrapper:
296 396 {
297 397 PyObject* enumWrapper = member._enumWrapper;
298 398 Py_INCREF(enumWrapper);
299 399 return enumWrapper;
300 400 }
301 401 break;
302 402 case PythonQtMemberInfo::NotFound:
303 403 {
304 404 static const QByteArray getterString("py_get_");
305 405 // check for a getter slot
306 406 PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
307 407 if (member._type == PythonQtMemberInfo::Slot) {
308 408 return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
309 409 }
310 410
311 411 // handle dynamic properties
312 412 if (wrapper->_obj) {
313 413 QVariant v = wrapper->_obj->property(attributeName);
314 414 if (v.isValid()) {
315 415 return PythonQtConv::QVariantToPyObject(v);
316 416 }
317 417 }
318 418 }
319 419 break;
320 420 default:
321 421 // is an invalid type, go on
322 422 break;
323 423 }
324 424
325 425 // look for the internal methods (className(), help())
326 426 PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName);
327 427 if (internalMethod) {
328 428 return internalMethod;
329 429 }
330 430 PyErr_Clear();
331 431
332 432 if (wrapper->_obj) {
333 433 // look for a child
334 434 QObjectList children = wrapper->_obj->children();
335 435 for (int i = 0; i < children.count(); i++) {
336 436 QObject *child = children.at(i);
337 437 if (child->objectName() == attributeName) {
338 438 return PythonQt::priv()->wrapQObject(child);
339 439 }
340 440 }
341 441 }
342 442
343 443 QString error = QString(wrapper->classInfo()->className()) + " has no attribute named '" + QString(attributeName) + "'";
344 444 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
345 445 return NULL;
346 446 }
347 447
348 448 static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
349 449 {
350 450 QString error;
351 451 const char *attributeName;
352 452 PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
353 453
354 454 if ((attributeName = PyString_AsString(name)) == NULL)
355 455 return -1;
356 456
357 457 PythonQtMemberInfo member = wrapper->classInfo()->member(attributeName);
358 458 if (member._type == PythonQtMemberInfo::Property) {
359 459
360 460 if (!wrapper->_obj) {
361 461 error = QString("Trying to set property '") + attributeName + "' on a destroyed " + wrapper->classInfo()->className() + " object";
362 462 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
363 463 return -1;
364 464 }
365
465
366 466 QMetaProperty prop = member._property;
367 467 if (prop.isWritable()) {
368 468 QVariant v;
369 469 if (prop.isEnumType()) {
370 470 // this will give us either a string or an int, everything else will probably be an error
371 471 v = PythonQtConv::PyObjToQVariant(value);
372 472 } else {
373 473 int t = prop.userType();
374 474 v = PythonQtConv::PyObjToQVariant(value, t);
375 475 }
376 476 bool success = false;
377 477 if (v.isValid()) {
378 478 success = prop.write(wrapper->_obj, v);
379 479 }
380 480 if (success) {
381 481 return 0;
382 482 } else {
383 483 error = QString("Property '") + attributeName + "' of type '" +
384 484 prop.typeName() + "' does not accept an object of type "
385 485 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
386 486 }
387 487 } else {
388 488 error = QString("Property '") + attributeName + "' of " + obj->ob_type->tp_name + " object is not writable";
389 489 }
390 490 } else if (member._type == PythonQtMemberInfo::Slot) {
391 491 error = QString("Slot '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
392 492 } else if (member._type == PythonQtMemberInfo::EnumValue) {
393 493 error = QString("EnumValue '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
394 494 } else if (member._type == PythonQtMemberInfo::EnumWrapper) {
395 495 error = QString("Enum '") + attributeName + "' can not be overwritten on " + obj->ob_type->tp_name + " object";
396 496 } else if (member._type == PythonQtMemberInfo::NotFound) {
397 497 // check for a setter slot
398 static const QByteArray setterString("py_set_");
498 static const QByteArray setterString("py_set_");
399 499 PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
400 500 if (setter._type == PythonQtMemberInfo::Slot) {
401 501 // call the setter and ignore the result value
402 502 void* result;
403 503 PyObject* args = PyTuple_New(1);
404 504 Py_INCREF(value);
405 505 PyTuple_SET_ITEM(args, 0, value);
406 506 PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, setter._slot, args, NULL, wrapper->_wrappedPtr, &result);
407 507 Py_DECREF(args);
408 508 return 0;
409 509 }
410 510
411 511 // handle dynamic properties
412 512 if (wrapper->_obj) {
413 513 QVariant prop = wrapper->_obj->property(attributeName);
414 514 if (prop.isValid()) {
415 515 QVariant v = PythonQtConv::PyObjToQVariant(value);
416 516 if (v.isValid()) {
417 517 wrapper->_obj->setProperty(attributeName, v);
418 518 return 0;
419 519 } else {
420 520 error = QString("Dynamic property '") + attributeName + "' does not accept an object of type "
421 521 + QString(value->ob_type->tp_name) + " (" + PythonQtConv::PyObjGetRepresentation(value) + ")";
422 522 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
423 523 return -1;
424 524 }
425 525 }
426 526 }
427
527
428 528 // if we are a derived python class, we allow setting attributes.
429 529 // if we are a direct CPP wrapper, we do NOT allow it, since
430 530 // it would be confusing to allow it because a wrapper will go away when it is not seen by python anymore
431 531 // and when it is recreated from a CPP pointer the attributes are gone...
432 532 if (obj->ob_type->tp_base != &PythonQtInstanceWrapper_Type) {
433 533 return PyBaseObject_Type.tp_setattro(obj,name,value);
434 534 } else {
435 535 error = QString("'") + attributeName + "' does not exist on " + obj->ob_type->tp_name + " and creating new attributes on C++ objects is not allowed";
436 536 }
437 537 }
438 538
439 539 PyErr_SetString(PyExc_AttributeError, error.toLatin1().data());
440 540 return -1;
441 541 }
442 542
443 543 static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
444 544 QString result;
445 545 if (wrapper->_wrappedPtr) {
446 546 // first try some manually string conversions for some variants
447 547 int metaid = wrapper->classInfo()->metaTypeId();
448 548 result = PythonQtConv::CPPObjectToString(metaid, wrapper->_wrappedPtr);
449 549 if (!result.isEmpty()) {
450 550 return result;
451 551 }
452 552 }
453 553 // next, try to call py_toString
454 554 PythonQtMemberInfo info = wrapper->classInfo()->member("py_toString");
455 555 if (info._type == PythonQtMemberInfo::Slot) {
456 556 PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, info._slot, NULL, NULL, wrapper->_wrappedPtr);
457 557 if (resultObj) {
458 558 // TODO this is one conversion too much, would be nicer to call the slot directly...
459 559 result = PythonQtConv::PyObjGetString(resultObj);
460 560 Py_DECREF(resultObj);
461 561 }
462 562 }
463 563 return result;
464 564 }
465 565
466 566 static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
467 567 {
468 568 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
469 569 const char* typeName = obj->ob_type->tp_name;
470 570 QObject *qobj = wrapper->_obj;
471 571 QString str = getStringFromObject(wrapper);
472 572 if (!str.isEmpty()) {
473 573 return PyString_FromFormat("%s", str.toLatin1().constData());
474 574 }
475 575 if (wrapper->_wrappedPtr) {
476 576 if (wrapper->_obj) {
477 577 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
478 578 } else {
479 579 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
480 580 }
481 581 } else {
482 582 return PyString_FromFormat("%s (QObject %p)", typeName, qobj);
483 583 }
484 584 }
485 585
486 586 static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
487 587 {
488 588 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
489 589 const char* typeName = obj->ob_type->tp_name;
490
590
491 591 QObject *qobj = wrapper->_obj;
492 592 QString str = getStringFromObject(wrapper);
493 593 if (!str.isEmpty()) {
494 594 if (str.startsWith(typeName)) {
495 595 return PyString_FromFormat("%s", str.toLatin1().constData());
496 596 } else {
497 597 return PyString_FromFormat("%s(%s, %p)", typeName, str.toLatin1().constData(), wrapper->_wrappedPtr);
498 598 }
499 599 }
500 600 if (wrapper->_wrappedPtr) {
501 601 if (wrapper->_obj) {
502 602 return PyString_FromFormat("%s (C++ Object %p wrapped by %s %p))", typeName, wrapper->_wrappedPtr, wrapper->_obj->metaObject()->className(), qobj);
503 603 } else {
504 604 return PyString_FromFormat("%s (C++ Object %p)", typeName, wrapper->_wrappedPtr);
505 605 }
506 606 } else {
507 607 return PyString_FromFormat("%s (%s %p)", typeName, wrapper->classInfo()->className(), qobj);
508 608 }
509 609 }
510 610
511 static int PythonQtInstanceWrapper_compare(PyObject * obj1, PyObject * obj2)
512 {
513 if (PyObject_TypeCheck(obj1, &PythonQtInstanceWrapper_Type) &&
514 PyObject_TypeCheck(obj2, &PythonQtInstanceWrapper_Type)) {
515
516 PythonQtInstanceWrapper* w1 = (PythonQtInstanceWrapper*)obj1;
517 PythonQtInstanceWrapper* w2 = (PythonQtInstanceWrapper*)obj2;
518 // check pointers directly first:
519 if (w1->_wrappedPtr != NULL) {
520 if (w1->_wrappedPtr == w2->_wrappedPtr) {
521 return 0;
522 }
523 } else if (w1->_obj == w2->_obj) {
524 return 0;
525 }
526 const char* class1 = w1->classInfo()->className();
527 const char* class2 = w2->classInfo()->className();
528 if (strcmp(class1, class2) == 0) {
529 // same class names, so we can try the operator_equal
530 PythonQtMemberInfo info = w1->classInfo()->member("operator_equal");
531 if (info._type == PythonQtMemberInfo::Slot) {
532 bool result = false;
533 void* obj1 = w1->_wrappedPtr;
534 if (!obj1) {
535 obj1 = w1->_obj;
536 }
537 if (!obj1) { return -1; }
538 void* obj2 = w2->_wrappedPtr;
539 if (!obj2) {
540 obj2 = w2->_obj;
541 }
542 if (!obj2) { return -1; }
543 if (info._slot->isInstanceDecorator()) {
544 // call on decorator QObject
545 void* args[3];
546 args[0] = &result;
547 args[1] = &obj1; // this is a pointer, so it needs a pointer to a pointer
548 args[2] = obj2; // this is a reference, so it needs the direct pointer
549 info._slot->decorator()->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
550 return result?0:-1;
551 } else {
552 // call directly on QObject
553 if (w1->_obj && w2->_obj) {
554 void* args[2];
555 args[0] = &result;
556 args[1] = obj2; // this is a reference, so it needs the direct pointer
557 w1->_obj->qt_metacall(QMetaObject::InvokeMetaMethod, info._slot->slotIndex(), args);
558 return result?0:-1;
559 }
560 }
561 }
562 }
563 }
564 return -1;
565 }
566
567 static int PythonQtInstanceWrapper_nonzero(PyObject *obj)
611 static int PythonQtInstanceWrapper_builtin_nonzero(PyObject *obj)
568 612 {
569 613 PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
570 614 return (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
571 615 }
572 616
573 617
574 618 static long PythonQtInstanceWrapper_hash(PythonQtInstanceWrapper *obj)
575 619 {
576 620 if (obj->_wrappedPtr != NULL) {
577 621 return reinterpret_cast<long>(obj->_wrappedPtr);
578 622 } else {
579 623 QObject* qobj = obj->_obj; // get pointer from QPointer wrapper
580 624 return reinterpret_cast<long>(qobj);
581 625 }
582 626 }
583 627
584 628
585 629
586 630 // we override nb_nonzero, so that one can do 'if' expressions to test for a NULL ptr
587 631 static PyNumberMethods PythonQtInstanceWrapper_as_number = {
588 632 0, /* nb_add */
589 633 0, /* nb_subtract */
590 634 0, /* nb_multiply */
591 635 0, /* nb_divide */
592 636 0, /* nb_remainder */
593 637 0, /* nb_divmod */
594 638 0, /* nb_power */
595 639 0, /* nb_negative */
596 640 0, /* nb_positive */
597 641 0, /* nb_absolute */
598 PythonQtInstanceWrapper_nonzero, /* nb_nonzero */
642 PythonQtInstanceWrapper_builtin_nonzero, /* nb_nonzero */
599 643 0, /* nb_invert */
600 644 0, /* nb_lshift */
601 645 0, /* nb_rshift */
602 646 0, /* nb_and */
603 647 0, /* nb_xor */
604 648 0, /* nb_or */
605 649 0, /* nb_coerce */
606 650 0, /* nb_int */
607 651 0, /* nb_long */
608 652 0, /* nb_float */
609 653 0, /* nb_oct */
610 654 0, /* nb_hex */
611 655 0, /* nb_inplace_add */
612 656 0, /* nb_inplace_subtract */
613 657 0, /* nb_inplace_multiply */
614 658 0, /* nb_inplace_divide */
615 659 0, /* nb_inplace_remainder */
616 660 0, /* nb_inplace_power */
617 661 0, /* nb_inplace_lshift */
618 662 0, /* nb_inplace_rshift */
619 663 0, /* nb_inplace_and */
620 664 0, /* nb_inplace_xor */
621 665 0, /* nb_inplace_or */
622 666 0, /* nb_floor_divide */
623 667 0, /* nb_true_divide */
624 668 0, /* nb_inplace_floor_divide */
625 669 0, /* nb_inplace_true_divide */
626 670 };
627 671
628 672 PyTypeObject PythonQtInstanceWrapper_Type = {
629 673 PyObject_HEAD_INIT(&PythonQtClassWrapper_Type)
630 674 0, /*ob_size*/
631 675 "PythonQt.PythonQtInstanceWrapper", /*tp_name*/
632 676 sizeof(PythonQtInstanceWrapper), /*tp_basicsize*/
633 677 0, /*tp_itemsize*/
634 678 (destructor)PythonQtInstanceWrapper_dealloc, /*tp_dealloc*/
635 679 0, /*tp_print*/
636 680 0, /*tp_getattr*/
637 681 0, /*tp_setattr*/
638 PythonQtInstanceWrapper_compare, /*tp_compare*/
682 0, /*tp_compare*/
639 683 PythonQtInstanceWrapper_repr, /*tp_repr*/
640 684 &PythonQtInstanceWrapper_as_number, /*tp_as_number*/
641 685 0, /*tp_as_sequence*/
642 686 0, /*tp_as_mapping*/
643 687 (hashfunc)PythonQtInstanceWrapper_hash, /*tp_hash */
644 688 0, /*tp_call*/
645 689 PythonQtInstanceWrapper_str, /*tp_str*/
646 690 PythonQtInstanceWrapper_getattro, /*tp_getattro*/
647 691 PythonQtInstanceWrapper_setattro, /*tp_setattro*/
648 692 0, /*tp_as_buffer*/
649 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
693 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
650 694 "PythonQtInstanceWrapper object", /* tp_doc */
651 695 0, /* tp_traverse */
652 696 0, /* tp_clear */
653 0, /* tp_richcompare */
697 (richcmpfunc)PythonQtInstanceWrapper_richcompare, /* tp_richcompare */
654 698 0, /* tp_weaklistoffset */
655 699 0, /* tp_iter */
656 700 0, /* tp_iternext */
657 701 0, /* tp_methods */
658 702 0, /* tp_members */
659 703 0, /* tp_getset */
660 704 0, /* tp_base */
661 705 0, /* tp_dict */
662 706 0, /* tp_descr_get */
663 707 0, /* tp_descr_set */
664 708 0, /* tp_dictoffset */
665 709 (initproc)PythonQtInstanceWrapper_init, /* tp_init */
666 710 0, /* tp_alloc */
667 711 PythonQtInstanceWrapper_new, /* tp_new */
668 712 };
669 713
670 714 //-------------------------------------------------------
671 715
General Comments 0
You need to be logged in to leave comments. Login now