##// END OF EJS Templates
added experimental compacting to avoid generation of hundreds of files that all include the same stuff...
florianlink -
r92:f97ec94c87a9
parent child
Show More
@@ -1,1872 +1,1842
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 "classgenerator.h"
43 43 #include "fileout.h"
44 44
45 45 #include <QtCore/QDir>
46 46 #include <QtCore/QMetaType>
47 47
48 48 #include <qdebug.h>
49 49
50 50 #define GENERATOR_NO_PROTECTED_FUNCTIONS
51 51
52 52 ClassGenerator::ClassGenerator(PriGenerator *pri, SetupGenerator *setup) :
53 53 priGenerator(pri),
54 54 setupGenerator(setup)
55 55 {}
56 56
57 57 QString ClassGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
58 58 {
59 59 return QString("qtscript_%1.cpp").arg(meta_class->name());
60 60 }
61 61
62 62 bool ClassGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
63 63 {
64 64 return false; // DISABLED!
65 65 uint cg = meta_class->typeEntry()->codeGeneration();
66 66 return (cg & TypeEntry::GenerateCode) != 0;
67 67 }
68 68
69 69 static QString normalizedType(const AbstractMetaType *type)
70 70 {
71 71 QString str = QString::fromLatin1(QMetaObject::normalizedType(type->cppSignature().toLatin1()));
72 72 if (str.endsWith(QLatin1Char('&')))
73 73 str.chop(1);
74 74 else if (str.startsWith("const ")) {
75 75 if (str.endsWith('*') || type->hasInstantiations() || type->typeEntry()->isValue())
76 76 str.remove(0, 6);
77 77 }
78 78 if (str == QLatin1String("QBool")) // ### hack
79 79 str = QLatin1String("bool");
80 80 return str;
81 81 }
82 82
83 83 /*!
84 84 Returns true if the class \a meta_class inherits from QObject,
85 85 otherwise returns false.
86 86 */
87 87 static bool isQObjectBased(const AbstractMetaClass *meta_class)
88 88 {
89 89 while (meta_class) {
90 90 if (meta_class->name() == QLatin1String("QObject"))
91 91 return true;
92 92 meta_class = meta_class->baseClass();
93 93 }
94 94 return false;
95 95 }
96 96
97 97 /*!
98 98 Returns true if any of the given \a enums has been declared with
99 99 Q_ENUMS.
100 100 */
101 101 static bool hasQEnums(const AbstractMetaEnumList &enums)
102 102 {
103 103 for (int i = 0; i < enums.size(); ++i) {
104 104 if (enums.at(i)->hasQEnumsDeclaration())
105 105 return true;
106 106 }
107 107 return false;
108 108 }
109 109
110 110 /*!
111 111 Returns true if any of the given \a enums has a QFlags class
112 112 associated with it.
113 113 */
114 114 static bool hasFlags(const AbstractMetaEnumList &enums)
115 115 {
116 116 for (int i = 0; i < enums.size(); ++i) {
117 117 FlagsTypeEntry *flags = enums.at(i)->typeEntry()->flags();
118 118 if (flags)
119 119 return true;
120 120 }
121 121 return false;
122 122 }
123 123
124 124 static bool isSequenceType(const AbstractMetaType *tp)
125 125 {
126 126 return tp->isContainer() && (tp->instantiations().size() == 1);
127 127 }
128 128
129 129 static AbstractMetaFunction *findDefaultConstructor(const AbstractMetaFunctionList &ctors)
130 130 {
131 131 for (int i = 0; i < ctors.size(); ++i) {
132 132 if (ctors.at(i)->actualMinimumArgumentCount() == 0)
133 133 return ctors.at(i);
134 134 }
135 135 return 0;
136 136 }
137 137
138 138 static AbstractMetaFunctionList findConstructors(const AbstractMetaClass *meta_class)
139 139 {
140 140 return meta_class->queryFunctions(AbstractMetaClass::Constructors
141 141 | AbstractMetaClass::WasPublic
142 142 | AbstractMetaClass::NotRemovedFromTargetLang);
143 143 }
144 144
145 145 /*!
146 146 Returns true if \a meta_class has a default constructor, false
147 147 otherwise.
148 148 */
149 149 bool hasDefaultConstructor(const AbstractMetaClass *meta_class)
150 150 {
151 151 return findDefaultConstructor(findConstructors(meta_class)) != 0;
152 152 }
153 153
154 154 /*!
155 155 Given the list of \a functions, creates a mapping from # of
156 156 arguments to list of functions.
157 157 */
158 158 static QMap<int, AbstractMetaFunctionList> createArgcToFunctionsMap(
159 159 const AbstractMetaFunctionList &functions)
160 160 {
161 161 QMap<int, AbstractMetaFunctionList> result;
162 162 for (int i = 0; i < functions.size(); ++i) {
163 163 AbstractMetaFunction *func = functions.at(i);
164 164 int argc = func->arguments().size();
165 165 for (int k = argc; k > 0; --k) {
166 166 if (func->argumentRemoved(k))
167 167 --argc;
168 168 }
169 169 for (int j = func->actualMinimumArgumentCount(); j <= argc; ++j)
170 170 result[j].append(func);
171 171 }
172 172 return result;
173 173 }
174 174
175 175 /*!
176 176 Returns the name of the QScriptValue function to use to test if
177 177 a value is of the given \a typeName, or an empty string if there
178 178 is no such function.
179 179 */
180 180 static QString builtinTypeTesterFunction(const QString &typeName)
181 181 {
182 182 if (typeName == QLatin1String("QString"))
183 183 return QLatin1String("isString");
184 184 else if (typeName == QLatin1String("double"))
185 185 return QLatin1String("isNumber");
186 186 else if (typeName == QLatin1String("float"))
187 187 return QLatin1String("isNumber");
188 188 else if (typeName == QLatin1String("int"))
189 189 return QLatin1String("isNumber");
190 190 else if (typeName == QLatin1String("uint"))
191 191 return QLatin1String("isNumber");
192 192 else if (typeName == QLatin1String("short"))
193 193 return QLatin1String("isNumber");
194 194 else if (typeName == QLatin1String("unsigned short"))
195 195 return QLatin1String("isNumber");
196 196 else if (typeName == QLatin1String("bool"))
197 197 return QLatin1String("isBoolean");
198 198 else if (typeName == QLatin1String("QVariant"))
199 199 return QLatin1String("isVariant");
200 200 // else if (typeName == QLatin1String("QDateTime"))
201 201 // return QLatin1String("isDate");
202 202 else if (typeName == QLatin1String("QRegExp"))
203 203 return QLatin1String("isRegExp");
204 204 else if (typeName == QLatin1String("QObject*"))
205 205 return QLatin1String("isQObject");
206 206 return QString();
207 207 }
208 208
209 209 /*!
210 210 Writes the code injections for the class \a meta_class that should
211 211 be injected at position \a pos.
212 212 */
213 213 static void writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class,
214 214 CodeSnip::Position pos)
215 215 {
216 216 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
217 217 foreach (const CodeSnip &cs, code_snips) {
218 218 if ((cs.language == TypeSystem::NativeCode) && (cs.position == pos)) {
219 219 s << cs.code() << endl;
220 220 }
221 221 }
222 222 }
223 223
224 224 /*!
225 225 Writes the code injections for the function \a fun of the class \a
226 226 meta_class that should be injected at position \a pos.
227 227 */
228 228 static void writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class,
229 229 const AbstractMetaFunction *fun, CodeSnip::Position pos)
230 230 {
231 231 FunctionModificationList mods = fun->modifications(meta_class);
232 232 foreach (const FunctionModification &mod, mods) {
233 233 if (!mod.isCodeInjection())
234 234 continue;
235 235 foreach (const CodeSnip &cs, mod.snips) {
236 236 if ((cs.language == TypeSystem::NativeCode) && (cs.position == pos)) {
237 237 s << cs.code() << endl;
238 238 }
239 239 }
240 240 }
241 241 }
242 242
243 243 /*!
244 244 Writes a boolean expression that checks if the actual arguments are
245 245 compatible with what the function expects. This is used to resolve
246 246 ambiguous calls.
247 247 */
248 248 static void writeArgumentTypeTests(QTextStream &stream, const AbstractMetaFunction *fun,
249 249 const AbstractMetaArgumentList &arguments, int argc, int indent)
250 250 {
251 251 QString indentStr(indent, QLatin1Char(' '));
252 252 int j = 0;
253 253 for (int i = 0; i < argc; ++j) {
254 254 if (fun->argumentRemoved(j+1))
255 255 continue;
256 256 if (i > 0)
257 257 stream << endl << indentStr << "&& ";
258 258 const AbstractMetaType *argType = 0;
259 259 QString typeName = fun->typeReplaced(j+1);
260 260 if (typeName.isEmpty()) {
261 261 AbstractMetaArgument *arg = arguments.at(j);
262 262 argType = arg->type();
263 263 typeName = normalizedType(argType);
264 264 }
265 265 QString scriptArg = QString::fromLatin1("context->argument(%0)").arg(i);
266 266 if (argType && isSequenceType(argType)) {
267 267 stream << scriptArg << ".isArray()";
268 268 } else if (typeName == "QVariant") {
269 269 stream << "true";
270 270 } else {
271 271 QString tester = builtinTypeTesterFunction(typeName);
272 272 if (!tester.isEmpty()) {
273 273 stream << scriptArg << "." << tester << "()";
274 274 } else if (typeName.endsWith('*')) {
275 275 stream << "qscriptvalue_cast<" << typeName << ">(" << scriptArg << ")";
276 276 } else {
277 277 // typeid-based test
278 278 stream << "(qMetaTypeId<" << typeName;
279 279 if (typeName.endsWith(QLatin1Char('>')))
280 280 stream << " ";
281 281 stream << ">() == " << scriptArg << ".toVariant().userType())";
282 282 }
283 283 }
284 284 ++i;
285 285 }
286 286 }
287 287
288 288 /*!
289 289 Returns the name of the QScriptValue function to use to convert a
290 290 value is of the given \a typeName, or an empty string if there is no
291 291 such function.
292 292 */
293 293 static QString builtinConversionFunction(const QString &typeName)
294 294 {
295 295 if (typeName == QLatin1String("QString"))
296 296 return QLatin1String("toString");
297 297 else if (typeName == QLatin1String("double"))
298 298 return QLatin1String("toNumber");
299 299 else if (typeName == QLatin1String("int"))
300 300 return QLatin1String("toInt32");
301 301 else if (typeName == QLatin1String("uint"))
302 302 return QLatin1String("toUInt32");
303 303 else if (typeName == QLatin1String("bool"))
304 304 return QLatin1String("toBoolean");
305 305 else if (typeName == QLatin1String("QVariant"))
306 306 return QLatin1String("toVariant");
307 307 else if (typeName == QLatin1String("QDateTime"))
308 308 return QLatin1String("toDateTime");
309 309 else if (typeName == QLatin1String("QRegExp"))
310 310 return QLatin1String("toRegExp");
311 311 else if (typeName == QLatin1String("QObject*"))
312 312 return QLatin1String("toQObject");
313 313 return QString();
314 314 }
315 315
316 316 /*!
317 317 Generates script arguments --> C++ types conversion, in preparation
318 318 for calling the native function we are binding.
319 319 */
320 320 static int writePrepareArguments(QTextStream &stream, const AbstractMetaFunction *fun,
321 321 const AbstractMetaArgumentList &arguments,
322 322 int scriptArgc, int indent)
323 323 {
324 324 if (arguments.size() == 0) {
325 325 Q_ASSERT(scriptArgc == 0);
326 326 return 0; // nothing to do
327 327 }
328 328 QString indentStr(indent, QLatin1Char(' '));
329 329 int j = 0;
330 330 for (int scriptArgIndex = 0; j < arguments.size(); ++j) {
331 331 const AbstractMetaArgument *arg = arguments.at(j);
332 332 bool isOptional = !arg->defaultValueExpression().isEmpty();
333 333 if (isOptional && (scriptArgIndex == scriptArgc))
334 334 break;
335 335 QString conv = fun->conversionRule(TypeSystem::NativeCode, j+1);
336 336 QString actualIn = QString::fromLatin1("context->argument(%0)").arg(scriptArgIndex);
337 337 QString actualOut = QString::fromLatin1("_q_arg%0").arg(j);
338 338 if (!conv.isEmpty()) {
339 339 // custom conversion
340 340 conv.replace(QString::fromLatin1("%in%"), actualIn);
341 341 conv.replace(QString::fromLatin1("%out%"), actualOut);
342 342 conv.replace(QString::fromLatin1("%this%"), QString::fromLatin1("_q_self"));
343 343 stream << conv;
344 344 } else {
345 345 const AbstractMetaType *argType = 0;
346 346 QString typeName = fun->typeReplaced(j+1);
347 347 if (typeName.isEmpty()) {
348 348 argType = arg->type();
349 349 typeName = normalizedType(argType);
350 350 }
351 351 stream << indentStr << typeName << " " << actualOut;
352 352 QString converter;
353 353 // ### generalize the QSet check (we should check if the type has push_back())
354 354 bool useToSequence = argType && isSequenceType(argType) && !argType->name().startsWith("Set");
355 355 if (useToSequence) {
356 356 stream << ";" << endl;
357 357 stream << indentStr << "qScriptValueToSequence(";
358 358 } else {
359 359 stream << " = ";
360 360 converter = builtinConversionFunction(typeName);
361 361 if (converter.isEmpty()) {
362 362 // generic conversion
363 363 stream << "qscriptvalue_cast<" << typeName;
364 364 if (typeName.endsWith(QLatin1Char('>')))
365 365 stream << " ";
366 366 stream << ">(";
367 367 }
368 368 }
369 369 stream << actualIn;
370 370 if (useToSequence) {
371 371 stream << ", " << actualOut << ")";
372 372 } else {
373 373 if (converter.isEmpty()) {
374 374 stream << ")"; // close qscriptvalue_cast
375 375 } else {
376 376 stream << "." << converter << "()";
377 377 }
378 378 }
379 379 stream << ";" << endl;
380 380 }
381 381 if (!fun->argumentRemoved(j+1))
382 382 ++scriptArgIndex;
383 383 }
384 384 return j;
385 385 }
386 386
387 387 /*!
388 388 Writes the arguments that are passed to the native function we are
389 389 binding. Those arguments must have been prepared already in variables
390 390 _q_arg0, _q_arg1, .. in the generated code.
391 391 */
392 392 static void writeArguments(QTextStream &stream, int count)
393 393 {
394 394 for (int i = 0; i < count; ++i) {
395 395 if (i > 0)
396 396 stream << ", ";
397 397 stream << "_q_arg" << i;
398 398 }
399 399 }
400 400
401 401 /*!
402 402 Writes a constructor call.
403 403 */
404 404 static void writeConstructorCallAndReturn(QTextStream &stream, const AbstractMetaFunction *fun,
405 405 int scriptArgc, const AbstractMetaClass *meta_class,
406 406 int indent)
407 407 {
408 408 QString indentStr(indent, QLatin1Char(' '));
409 409
410 410 writeInjectedCode(stream, meta_class, fun, CodeSnip::Beginning);
411 411
412 412 AbstractMetaArgumentList arguments = fun->arguments();
413 413 Q_ASSERT(arguments.size() >= scriptArgc);
414 414 int nativeArgc = writePrepareArguments(stream, fun, arguments, scriptArgc, indent);
415 415 stream << indentStr;
416 416 if (meta_class->generateShellClass()) {
417 417 stream << "QtScriptShell_" << meta_class->name();
418 418 } else {
419 419 stream << meta_class->qualifiedCppName();
420 420 }
421 421 bool useNew = meta_class->typeEntry()->isObject() || !hasDefaultConstructor(meta_class);
422 422 if (useNew)
423 423 stream << "*";
424 424 stream << " _q_cpp_result";
425 425 if (useNew) {
426 426 stream << " = new ";
427 427 if (meta_class->generateShellClass())
428 428 stream << "QtScriptShell_" << meta_class->name();
429 429 else
430 430 stream << meta_class->qualifiedCppName();
431 431 }
432 432 if (useNew || (nativeArgc != 0)) {
433 433 stream << "(";
434 434 writeArguments(stream, nativeArgc);
435 435 stream << ")";
436 436 }
437 437 stream << ";" << endl;
438 438
439 439 stream << indentStr << "QScriptValue _q_result = context->engine()->new";
440 440 if (isQObjectBased(meta_class))
441 441 stream << "QObject";
442 442 else
443 443 stream << "Variant";
444 444 stream << "(context->thisObject(), ";
445 445 if (!isQObjectBased(meta_class))
446 446 stream << "qVariantFromValue(";
447 447 if (meta_class->generateShellClass()) {
448 448 stream << "(" << meta_class->qualifiedCppName();
449 449 if (useNew)
450 450 stream << "*";
451 451 stream << ")";
452 452 }
453 453 stream << "_q_cpp_result";
454 454 if (isQObjectBased(meta_class))
455 455 stream << ", QScriptEngine::AutoOwnership";
456 456 else
457 457 stream << ")";
458 458 stream << ");" << endl;
459 459 if (meta_class->generateShellClass()) {
460 460 stream << indentStr << "_q_cpp_result";
461 461 if (useNew)
462 462 stream << "->";
463 463 else
464 464 stream << ".";
465 465 stream << "__qtscript_self = _q_result;" << endl;
466 466 }
467 467
468 468 writeInjectedCode(stream, meta_class, fun, CodeSnip::End);
469 469
470 470 stream << indentStr << "return _q_result;" << endl;
471 471 }
472 472
473 473 /*!
474 474 Returns true if the given \a typeName has a QScriptValue constructor
475 475 we can use, false otherwise.
476 476 */
477 477 static bool hasScriptValueConstructor(const QString &typeName)
478 478 {
479 479 return (typeName == QLatin1String("bool"))
480 480 || (typeName == QLatin1String("int"))
481 481 || (typeName == QLatin1String("uint"))
482 482 || (typeName == QLatin1String("double"))
483 483 || (typeName == QLatin1String("QString"));
484 484 }
485 485
486 486 /*!
487 487 Writes a function call.
488 488 */
489 489 static void writeFunctionCallAndReturn(QTextStream &stream, const AbstractMetaFunction *fun,
490 490 int scriptArgc, const AbstractMetaClass *meta_class,
491 491 int indent)
492 492 {
493 493 QString indentStr(indent, QLatin1Char(' '));
494 494 AbstractMetaArgumentList arguments = fun->arguments();
495 495 Q_ASSERT(arguments.size() >= scriptArgc);
496 496
497 497 writeInjectedCode(stream, meta_class, fun, CodeSnip::Beginning);
498 498
499 499 int nativeArgc = writePrepareArguments(stream, fun, arguments, scriptArgc, indent);
500 500 bool returnThisObject = fun->shouldReturnThisObject();
501 501 bool ignoreReturnValue = returnThisObject || fun->shouldIgnoreReturnValue();
502 502 stream << indentStr;
503 503 AbstractMetaType *retType = fun->type();
504 504 bool constCastResult = false;
505 505 if (retType && !ignoreReturnValue) {
506 506 QString rsig = retType->cppSignature();
507 507 QString typeName = normalizedType(retType);
508 508 stream << typeName << " _q_result = ";
509 509 constCastResult = rsig.endsWith('*') && rsig.startsWith("const ");
510 510 if (constCastResult)
511 511 stream << "const_cast<" << typeName << ">(";
512 512 }
513 513
514 514 if (!fun->isStatic()) {
515 515 // ### the friendly check should be enough...
516 516 if (fun->isFriendly()
517 517 || ((fun->name() == QLatin1String("operator_equal"))
518 518 && ((meta_class->name() == QLatin1String("QPoint"))
519 519 || (meta_class->name() == QLatin1String("QPointF"))
520 520 || (meta_class->name() == QLatin1String("QRect"))
521 521 || (meta_class->name() == QLatin1String("QRectF"))
522 522 || (meta_class->name() == QLatin1String("QSize"))
523 523 || (meta_class->name() == QLatin1String("QSizeF"))))) {
524 524 stream << fun->originalName() << "(";
525 525 stream << "*_q_self, ";
526 526 } else {
527 527 stream << "_q_self->";
528 528 stream << fun->originalName() << "(";
529 529 }
530 530 } else {
531 531 stream << meta_class->qualifiedCppName() << "::";
532 532 stream << fun->originalName() << "(";
533 533 }
534 534 writeArguments(stream, nativeArgc);
535 535 if (constCastResult)
536 536 stream << ")";
537 537 stream << ");" << endl;
538 538
539 539 writeInjectedCode(stream, meta_class, fun, CodeSnip::End);
540 540
541 541 // write return statement
542 542 stream << indentStr;
543 543 if (returnThisObject) {
544 544 stream << "return context->thisObject();";
545 545 } else {
546 546 QString conv = fun->conversionRule(TypeSystem::NativeCode, 0);
547 547 if (!conv.isEmpty()) {
548 548 // custom conversion
549 549 conv.replace(QString::fromLatin1("%in%"), "_q_result");
550 550 conv.replace(QString::fromLatin1("%out%"), "_q_convertedResult");
551 551 stream << conv;
552 552 stream << "return qScriptValueFromValue(context->engine(), _q_convertedResult);";
553 553 } else {
554 554 stream << "return ";
555 555 if (retType) {
556 556 if (isSequenceType(retType))
557 557 stream << "qScriptValueFromSequence";
558 558 else if (hasScriptValueConstructor(normalizedType(retType)))
559 559 stream << "QScriptValue";
560 560 else
561 561 stream << "qScriptValueFromValue";
562 562 stream << "(context->engine(), _q_result);";
563 563 } else {
564 564 stream << "context->engine()->undefinedValue();";
565 565 }
566 566 }
567 567 }
568 568 stream << endl;
569 569 }
570 570
571 571 /*!
572 572 Returns true if the given function \a fun is operator>>() or
573 573 operator<<() that streams from/to a Q{Data,Text}Stream, false
574 574 otherwise.
575 575 */
576 576 bool ClassGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun)
577 577 {
578 578 return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction)
579 579 && (fun->arguments().size() == 1)
580 580 && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom"))
581 581 || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo"))));
582 582 }
583 583
584 584 /*!
585 585 Generates code that uses Q{Data,Text}Stream operator>>() or
586 586 operator<<() to read/write an instance of meta_class.
587 587 */
588 588 static void writeStreamingOperatorCall(QTextStream &stream, const AbstractMetaFunction *fun,
589 589 const AbstractMetaClass * /*meta_class*/, int indent)
590 590 {
591 591 QString indentStr(indent, QLatin1Char(' '));
592 592 QString streamClassName = fun->arguments().at(0)->type()->name();
593 593 stream << indentStr << streamClassName << "* _q_arg0 = qscriptvalue_cast<"
594 594 << streamClassName << "*>(context->argument(0));" << endl;
595 595 stream << indentStr << "operator";
596 596 if (fun->modifiedName() == "readFrom")
597 597 stream << ">>";
598 598 else
599 599 stream << "<<";
600 600 stream << "(*_q_arg0, *_q_self);" << endl;
601 601 stream << indentStr << "return context->engine()->undefinedValue();" << endl;
602 602 }
603 603
604 604 /*!
605 605 Writes the constructor forwarding for \a meta_class.
606 606 */
607 607 static void writeConstructorForwarding(QTextStream &stream,
608 608 const AbstractMetaFunctionList &functions,
609 609 const AbstractMetaClass *meta_class)
610 610 {
611 611 #if 0
612 612 stream << "/** signatures:" << endl;
613 613 foreach (const AbstractMetaFunction *fun, functions) {
614 614 stream << " * " << fun->signature() << endl;
615 615 }
616 616 stream << " */" << endl;
617 617 #endif
618 618
619 619 if (/*meta_class->isAbstract() ||*/ (functions.size() == 0)) {
620 620 stream << " return context->throwError(QScriptContext::TypeError," << endl
621 621 << " QString::fromLatin1(\"" << meta_class->name()
622 622 << " cannot be constructed\"));" << endl;
623 623
624 624 } else {
625 625 stream << " if (context->thisObject().strictlyEquals(context->engine()->globalObject())) {" << endl
626 626 << " return context->throwError(QString::fromLatin1(\""
627 627 << meta_class->name() << "(): Did you forget to construct with 'new'?\"));" << endl
628 628 << " }" << endl;
629 629
630 630 writeInjectedCode(stream, meta_class, CodeSnip::Constructor);
631 631
632 632 QMap<int, AbstractMetaFunctionList> argcToFunctions;
633 633 argcToFunctions = createArgcToFunctionsMap(functions);
634 634
635 635 int argcMin = argcToFunctions.keys().first();
636 636 int argcMax = argcToFunctions.keys().last();
637 637 bool needElse = false;
638 638 for (int i = argcMin; i <= argcMax; ++i) {
639 639 AbstractMetaFunctionList funcs = argcToFunctions.value(i);
640 640 if (funcs.isEmpty())
641 641 continue;
642 642 if (needElse)
643 643 stream << " else ";
644 644 else
645 645 stream << " ";
646 646 needElse = true;
647 647 stream << "if (context->argumentCount() == " << i << ") {" << endl;
648 648 if ((funcs.size() == 1) || (i == 0)) {
649 649 AbstractMetaFunction *fun = funcs.at(0);
650 650 const int indent = 8;
651 651 writeConstructorCallAndReturn(stream, fun, i, meta_class, indent);
652 652 } else {
653 653 // handle overloads
654 654 for (int j = 0; j < funcs.size(); ++j) {
655 655 AbstractMetaFunction *fun = funcs.at(j);
656 656 stream << " ";
657 657 if (j > 0)
658 658 stream << "} else ";
659 659 stream << "if (";
660 660 AbstractMetaArgumentList arguments = fun->arguments();
661 661 const int indent = 12;
662 662 writeArgumentTypeTests(stream, fun, arguments, i, indent);
663 663 stream << ") {" << endl;
664 664 writeConstructorCallAndReturn(stream, fun, i, meta_class, indent);
665 665 }
666 666 stream << " }" << endl;
667 667 }
668 668 stream << " }";
669 669 }
670 670 stream << endl;
671 671 // writeThrowAmbiguityError(stream, meta_class, 0, signatures.toList());
672 672 }
673 673 }
674 674
675 675 /*!
676 676 Returns a list of enum \a values that are actually unique.
677 677 */
678 678 QList<int> uniqueEnumValueIndexes(const AbstractMetaEnumValueList &values)
679 679 {
680 680 QMap<int, int> map;
681 681 for (int i = 0; i < values.count(); ++i) {
682 682 AbstractMetaEnumValue *val = values.at(i);
683 683 if (!map.contains(val->value()))
684 684 map.insert(val->value(), i);
685 685 }
686 686 return map.values();
687 687 }
688 688
689 689 /*!
690 690 */
691 691 static bool isContiguousEnum(const QList<int> &indexes, const AbstractMetaEnumValueList &values)
692 692 {
693 693 if (indexes.isEmpty())
694 694 return false;
695 695 int prev = values.at(indexes.at(0))->value();
696 696 for (int i = 1; i < indexes.size(); ++i) {
697 697 int curr = values.at(indexes.at(i))->value();
698 698 if (curr != prev + 1)
699 699 return false;
700 700 prev = curr;
701 701 }
702 702 return true;
703 703 }
704 704
705 705 static void writeCreateEnumClassHelper(QTextStream &stream)
706 706 {
707 707 stream << "static QScriptValue qtscript_create_enum_class_helper(" << endl
708 708 << " QScriptEngine *engine," << endl
709 709 << " QScriptEngine::FunctionSignature construct," << endl
710 710 << " QScriptEngine::FunctionSignature valueOf," << endl
711 711 << " QScriptEngine::FunctionSignature toString)" << endl
712 712 << "{" << endl
713 713 << " QScriptValue proto = engine->newObject();" << endl
714 714 << " proto.setProperty(QString::fromLatin1(\"valueOf\")," << endl
715 715 << " engine->newFunction(valueOf), QScriptValue::SkipInEnumeration);" << endl
716 716 << " proto.setProperty(QString::fromLatin1(\"toString\")," << endl
717 717 << " engine->newFunction(toString), QScriptValue::SkipInEnumeration);" << endl
718 718 << " return engine->newFunction(construct, proto, 1);" << endl
719 719 << "}" << endl << endl;
720 720 }
721 721
722 722 static void writeCreateFlagsClassHelper(QTextStream &stream)
723 723 {
724 724 stream << "static QScriptValue qtscript_create_flags_class_helper(" << endl
725 725 << " QScriptEngine *engine," << endl
726 726 << " QScriptEngine::FunctionSignature construct," << endl
727 727 << " QScriptEngine::FunctionSignature valueOf," << endl
728 728 << " QScriptEngine::FunctionSignature toString," << endl
729 729 << " QScriptEngine::FunctionSignature equals)" << endl
730 730 << "{" << endl
731 731 << " QScriptValue proto = engine->newObject();" << endl
732 732 << " proto.setProperty(QString::fromLatin1(\"valueOf\")," << endl
733 733 << " engine->newFunction(valueOf), QScriptValue::SkipInEnumeration);" << endl
734 734 << " proto.setProperty(QString::fromLatin1(\"toString\")," << endl
735 735 << " engine->newFunction(toString), QScriptValue::SkipInEnumeration);" << endl
736 736 << " proto.setProperty(QString::fromLatin1(\"equals\")," << endl
737 737 << " engine->newFunction(equals), QScriptValue::SkipInEnumeration);" << endl
738 738 << " return engine->newFunction(construct, proto);" << endl
739 739 << "}" << endl << endl;
740 740 }
741 741
742 742 /*!
743 743 Writes the enum \a enom belonging to the class \a meta_class to the
744 744 given \a stream.
745 745 */
746 746 static void writeEnumClass(QTextStream &stream, const AbstractMetaClass *meta_class,
747 747 const AbstractMetaEnum *enom)
748 748 {
749 749 QString qualifiedCppNameColons;
750 750 if (meta_class->name() != "Global")
751 751 qualifiedCppNameColons = meta_class->qualifiedCppName() + "::";
752 752 QString qualifiedEnumName = qualifiedCppNameColons + enom->name();
753 753 QString qtScriptEnumName = meta_class->name() + "_" + enom->name();
754 754
755 755 stream << "//" << endl;
756 756 stream << "// " << qualifiedEnumName << endl;
757 757 stream << "//" << endl << endl;
758 758
759 759 // determine unique values (aliases will cause switch statement to not compile)
760 760 AbstractMetaEnumValueList values = enom->values();
761 761 QList<int> uniqueIndexes = uniqueEnumValueIndexes(values);
762 762
763 763 bool contiguous = isContiguousEnum(uniqueIndexes, values);
764 764
765 765 // write arrays of values and keys
766 766 stream << "static const " << qualifiedEnumName
767 767 << " qtscript_" << qtScriptEnumName << "_values[] = {" << endl;
768 768 for (int i = 0; i < uniqueIndexes.size(); ++i) {
769 769 stream << " ";
770 770 if (i > 0)
771 771 stream << ", ";
772 772 stream << qualifiedCppNameColons << values.at(uniqueIndexes.at(i))->name() << endl;
773 773 }
774 774 stream << "};" << endl << endl;
775 775 stream << "static const char * const qtscript_" << qtScriptEnumName << "_keys[] = {" << endl;
776 776 for (int i = 0; i < uniqueIndexes.size(); ++i) {
777 777 stream << " ";
778 778 if (i > 0)
779 779 stream << ", ";
780 780 stream << "\"" << values.at(uniqueIndexes.at(i))->name() << "\"" << endl;
781 781 }
782 782 stream << "};" << endl << endl;
783 783
784 784 // write toString helper
785 785 stream << "static QString qtscript_"
786 786 << qtScriptEnumName << "_toStringHelper"
787 787 << "(" << qualifiedEnumName << " value)" << endl;
788 788 stream << "{" << endl;
789 789 if (enom->hasQEnumsDeclaration() && (meta_class->qualifiedCppName() != "QTransform")) {
790 790 stream << " const QMetaObject *meta = qtscript_" << meta_class->name() << "_metaObject();" << endl;
791 791 stream << " int idx = meta->indexOfEnumerator(\"" << enom->name() << "\");" << endl;
792 792 stream << " Q_ASSERT(idx != -1);" << endl;
793 793 stream << " QMetaEnum menum = meta->enumerator(idx);" << endl;
794 794 stream << " return QString::fromLatin1(menum.valueToKey(value));" << endl;
795 795 } else {
796 796 if (contiguous) {
797 797 stream << " if ((value >= " << qualifiedCppNameColons
798 798 << values.at(uniqueIndexes.first())->name() << ")"
799 799 << " && (value <= " << qualifiedCppNameColons
800 800 << values.at(uniqueIndexes.last())->name() << "))" << endl
801 801 << " return qtscript_" << qtScriptEnumName
802 802 << "_keys[static_cast<int>(value)-static_cast<int>("
803 803 << qualifiedCppNameColons
804 804 << values.at(uniqueIndexes.first())->name() << ")];" << endl;
805 805 } else {
806 806 stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl
807 807 << " if (qtscript_" << qtScriptEnumName << "_values[i] == value)" << endl
808 808 << " return QString::fromLatin1(qtscript_" << qtScriptEnumName << "_keys[i]);" << endl
809 809 << " }" << endl;
810 810 }
811 811 stream << " return QString();" << endl;
812 812 }
813 813 stream << "}" << endl << endl;
814 814
815 815 // write QScriptValue <--> C++ conversion functions
816 816 stream << "static QScriptValue qtscript_"
817 817 << qtScriptEnumName << "_toScriptValue("
818 818 << "QScriptEngine *engine, const " << qualifiedEnumName << " &value)" << endl
819 819 << "{" << endl
820 820 << " QScriptValue clazz = engine->globalObject().property(QString::fromLatin1(\""
821 821 << meta_class->name() << "\"));" << endl
822 822 // << " QScriptValue enumClazz = clazz.property(QString::fromLatin1(\""
823 823 // << enom->name() << "\"));" << endl
824 824 << " return clazz.property(qtscript_" << qtScriptEnumName << "_toStringHelper(value));" << endl
825 825 << "}" << endl << endl;
826 826 stream << "static void qtscript_"
827 827 << qtScriptEnumName << "_fromScriptValue("
828 828 << "const QScriptValue &value, " << qualifiedEnumName << " &out)" << endl
829 829 << "{" << endl
830 830 << " out = qvariant_cast<" << qualifiedEnumName << ">(value.toVariant());" << endl
831 831 << "}" << endl << endl;
832 832
833 833 // write constructor
834 834 stream << "static QScriptValue qtscript_construct_"
835 835 << qtScriptEnumName
836 836 << "(QScriptContext *context, QScriptEngine *engine)" << endl;
837 837 stream << "{" << endl;
838 838 stream << " int arg = context->argument(0).toInt32();" << endl;
839 839 if (enom->hasQEnumsDeclaration() && (meta_class->qualifiedCppName() != "QTransform")) {
840 840 stream << " const QMetaObject *meta = qtscript_" << meta_class->name() << "_metaObject();" << endl;
841 841 stream << " int idx = meta->indexOfEnumerator(\"" << enom->name() << "\");" << endl;
842 842 stream << " Q_ASSERT(idx != -1);" << endl;
843 843 stream << " QMetaEnum menum = meta->enumerator(idx);" << endl;
844 844 stream << " if (menum.valueToKey(arg) != 0)" << endl;
845 845 stream << " return qScriptValueFromValue(engine, static_cast<"
846 846 << qualifiedEnumName << ">(arg));" << endl;
847 847 } else {
848 848 if (contiguous) {
849 849 stream << " if ((arg >= " << qualifiedCppNameColons
850 850 << values.at(uniqueIndexes.first())->name() << ")"
851 851 << " && (arg <= " << qualifiedCppNameColons
852 852 << values.at(uniqueIndexes.last())->name() << "))" << endl;
853 853 stream << " return qScriptValueFromValue(engine, static_cast<"
854 854 << qualifiedEnumName << ">(arg));" << endl;
855 855 } else {
856 856 stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl
857 857 << " if (qtscript_" << qtScriptEnumName << "_values[i] == arg)" << endl;
858 858 stream << " return qScriptValueFromValue(engine, static_cast<"
859 859 << qualifiedEnumName << ">(arg));" << endl;
860 860 stream << " }" << endl;
861 861 }
862 862 }
863 863 stream << " return context->throwError(QString::fromLatin1(\""
864 864 << enom->name() << "(): invalid enum value (%0)\").arg(arg));" << endl;
865 865 stream << "}" << endl;
866 866 stream << endl;
867 867
868 868 // write prototype.valueOf()
869 869 stream << "static QScriptValue qtscript_" << qtScriptEnumName
870 870 << "_valueOf(QScriptContext *context, QScriptEngine *engine)" << endl;
871 871 stream << "{" << endl;
872 872 stream << " " << qualifiedEnumName << " value = "
873 873 << "qscriptvalue_cast<" << qualifiedEnumName
874 874 << ">(context->thisObject());" << endl;
875 875 stream << " return QScriptValue(engine, static_cast<int>(value));" << endl;
876 876 stream << "}" << endl;
877 877 stream << endl;
878 878
879 879 // write prototype.toString()
880 880 stream << "static QScriptValue qtscript_" << qtScriptEnumName
881 881 << "_toString(QScriptContext *context, QScriptEngine *engine)" << endl;
882 882 stream << "{" << endl;
883 883 stream << " " << qualifiedEnumName << " value = "
884 884 << "qscriptvalue_cast<" << qualifiedEnumName
885 885 << ">(context->thisObject());" << endl;
886 886 stream << " return QScriptValue(engine, qtscript_" << qtScriptEnumName << "_toStringHelper(value));" << endl;
887 887 stream << "}" << endl;
888 888 stream << endl;
889 889
890 890 // write class creation function
891 891 stream << "static QScriptValue qtscript_create_"
892 892 << qtScriptEnumName
893 893 << "_class(QScriptEngine *engine, QScriptValue &clazz)" << endl;
894 894 stream << "{" << endl;
895 895
896 896 stream << " QScriptValue ctor = qtscript_create_enum_class_helper(" << endl
897 897 << " engine, qtscript_construct_" << qtScriptEnumName << "," << endl
898 898 << " qtscript_" << qtScriptEnumName << "_valueOf, qtscript_"
899 899 << qtScriptEnumName << "_toString);" << endl;
900 900
901 901 stream << " qScriptRegisterMetaType<" << qualifiedEnumName << ">(engine, "
902 902 << "qtscript_" << qtScriptEnumName << "_toScriptValue," << endl
903 903 << " qtscript_" << qtScriptEnumName << "_fromScriptValue,"
904 904 << " ctor.property(QString::fromLatin1(\"prototype\")));" << endl;
905 905
906 906 // enum values are properties of the constructor
907 907 stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl
908 908 << " clazz.setProperty(QString::fromLatin1(qtscript_"
909 909 << qtScriptEnumName << "_keys[i])," << endl
910 910 << " engine->newVariant(qVariantFromValue(qtscript_"
911 911 << qtScriptEnumName << "_values[i]))," << endl
912 912 << " QScriptValue::ReadOnly | QScriptValue::Undeletable);" << endl
913 913 << " }" << endl;
914 914
915 915 stream << " return ctor;" << endl;
916 916 stream << "}" << endl;
917 917 stream << endl;
918 918
919 919 // write flags class too, if any
920 920 FlagsTypeEntry *flags = enom->typeEntry()->flags();
921 921 if (!flags)
922 922 return;
923 923
924 924 QString qualifiedFlagsName = qualifiedCppNameColons + flags->targetLangName();
925 925 QString qtScriptFlagsName = meta_class->name() + "_" + flags->targetLangName();
926 926
927 927 stream << "//" << endl;
928 928 stream << "// " << qualifiedFlagsName << endl;
929 929 stream << "//" << endl << endl;
930 930
931 931 // write QScriptValue <--> C++ conversion functions
932 932 stream << "static QScriptValue qtscript_"
933 933 << qtScriptFlagsName << "_toScriptValue("
934 934 << "QScriptEngine *engine, const " << qualifiedFlagsName << " &value)" << endl
935 935 << "{" << endl
936 936 << " return engine->newVariant(qVariantFromValue(value));" << endl
937 937 << "}" << endl << endl;
938 938 stream << "static void qtscript_"
939 939 << qtScriptFlagsName << "_fromScriptValue("
940 940 << "const QScriptValue &value, " << qualifiedFlagsName << " &out)" << endl
941 941 << "{" << endl
942 942 << " QVariant var = value.toVariant();" << endl
943 943 << " if (var.userType() == qMetaTypeId<" << qualifiedFlagsName << ">())" << endl
944 944 << " out = qvariant_cast<" << qualifiedFlagsName << ">(var);" << endl
945 945 << " else if (var.userType() == qMetaTypeId<" << qualifiedEnumName << ">())" << endl
946 946 << " out = qvariant_cast<" << qualifiedEnumName << ">(var);" << endl
947 947 << " else" << endl
948 948 << " out = 0;" << endl
949 949 << "}" << endl << endl;
950 950
951 951 // write constructor
952 952 stream << "static QScriptValue qtscript_construct_"
953 953 << qtScriptFlagsName
954 954 << "(QScriptContext *context, QScriptEngine *engine)" << endl;
955 955 stream << "{" << endl;
956 956 stream << " " << qualifiedFlagsName << " result = 0;" << endl;
957 957 stream << " if ((context->argumentCount() == 1) && context->argument(0).isNumber()) {" << endl;
958 958 stream << " result = static_cast<" << qualifiedFlagsName << ">(context->argument(0).toInt32());" << endl;
959 959 stream << " } else {" << endl;
960 960 stream << " for (int i = 0; i < context->argumentCount(); ++i) {" << endl;
961 961 stream << " QVariant v = context->argument(i).toVariant();" << endl;
962 962 stream << " if (v.userType() != qMetaTypeId<" << qualifiedEnumName << ">()) {" << endl;
963 963 stream << " return context->throwError(QScriptContext::TypeError," << endl
964 964 << " QString::fromLatin1(\"" << flags->targetLangName()
965 965 << "(): argument %0 is not of type " << enom->name() << "\").arg(i));" << endl;
966 966 stream << " }" << endl;
967 967 stream << " result |= qvariant_cast<" << qualifiedEnumName
968 968 << ">(v);" << endl;
969 969 stream << " }" << endl;
970 970 stream << " }" << endl;
971 971 stream << " return engine->newVariant(qVariantFromValue(result));" << endl;
972 972 stream << "}" << endl;
973 973 stream << endl;
974 974
975 975 // write prototype.valueOf()
976 976 stream << "static QScriptValue qtscript_" << qtScriptFlagsName
977 977 << "_valueOf(QScriptContext *context, QScriptEngine *engine)" << endl;
978 978 stream << "{" << endl;
979 979 stream << " " << qualifiedFlagsName << " value = "
980 980 << "qscriptvalue_cast<" << qualifiedFlagsName
981 981 << ">(context->thisObject());" << endl;
982 982 stream << " return QScriptValue(engine, static_cast<int>(value));" << endl;
983 983 stream << "}" << endl;
984 984 stream << endl;
985 985
986 986 // write prototype.toString()
987 987 stream << "static QScriptValue qtscript_" << qtScriptFlagsName
988 988 << "_toString(QScriptContext *context, QScriptEngine *engine)" << endl;
989 989 stream << "{" << endl;
990 990 stream << " " << qualifiedFlagsName << " value = "
991 991 << "qscriptvalue_cast<" << qualifiedFlagsName
992 992 << ">(context->thisObject());" << endl;
993 993 stream << " QString result;" << endl;
994 994 stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl
995 995 << " if ((value & qtscript_" << qtScriptEnumName << "_values[i])"
996 996 << " == qtscript_" << qtScriptEnumName << "_values[i]) {" << endl
997 997 << " if (!result.isEmpty())" << endl
998 998 << " result.append(QString::fromLatin1(\",\"));" << endl
999 999 << " result.append(QString::fromLatin1(qtscript_" << qtScriptEnumName << "_keys[i]));" << endl
1000 1000 << " }" << endl
1001 1001 << " }" << endl
1002 1002 << " return QScriptValue(engine, result);" << endl
1003 1003 << "}" << endl
1004 1004 << endl;
1005 1005
1006 1006 // write prototype.equals()
1007 1007 stream << "static QScriptValue qtscript_" << qtScriptFlagsName
1008 1008 << "_equals(QScriptContext *context, QScriptEngine *engine)" << endl
1009 1009 << "{" << endl
1010 1010 << " QVariant thisObj = context->thisObject().toVariant();" << endl
1011 1011 << " QVariant otherObj = context->argument(0).toVariant();" << endl
1012 1012
1013 1013 << " return QScriptValue(engine, ((thisObj.userType() == otherObj.userType()) &&" << endl
1014 1014 << " (thisObj.value<" << qualifiedFlagsName << ">() == otherObj.value<" << qualifiedFlagsName << ">())));" << endl
1015 1015 << "}" << endl << endl;
1016 1016
1017 1017 // write class creation function
1018 1018 stream << "static QScriptValue qtscript_create_" << qtScriptFlagsName << "_class(QScriptEngine *engine)" << endl;
1019 1019 stream << "{" << endl;
1020 1020 stream << " QScriptValue ctor = qtscript_create_flags_class_helper(" << endl
1021 1021 << " engine, qtscript_construct_" << qtScriptFlagsName
1022 1022 << ", qtscript_" << qtScriptFlagsName << "_valueOf," << endl
1023 1023 << " qtscript_" << qtScriptFlagsName << "_toString, qtscript_"
1024 1024 << qtScriptFlagsName << "_equals);" << endl;
1025 1025
1026 1026 stream << " qScriptRegisterMetaType<" << qualifiedFlagsName << ">(engine, "
1027 1027 << "qtscript_" << qtScriptFlagsName << "_toScriptValue," << endl
1028 1028 << " qtscript_" << qtScriptFlagsName << "_fromScriptValue,"
1029 1029 << " ctor.property(QString::fromLatin1(\"prototype\")));" << endl;
1030 1030
1031 1031 stream << " return ctor;" << endl;
1032 1032 stream << "}" << endl;
1033 1033 stream << endl;
1034 1034 }
1035 1035
1036 1036 /*!
1037 1037 Declares the given \a typeName if it hasn't been declared already,
1038 1038 and adds it to the set of registered type names.
1039 1039 */
1040 1040 void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
1041 1041 QSet<QString> &registeredTypeNames)
1042 1042 {
1043 1043 QString name = typeName;
1044 1044 if (name.endsWith(QLatin1Char('&')))
1045 1045 name.chop(1);
1046 1046 if (registeredTypeNames.contains(name) || (QMetaType::type(typeName.toLatin1()) != 0))
1047 1047 return;
1048 1048 if (name.contains(QLatin1Char(','))) {
1049 1049 // need to expand the Q_DECLARE_METATYPE macro manually,
1050 1050 // otherwise the compiler will choke
1051 1051 stream << "template <> \\" << endl
1052 1052 << "struct QMetaTypeId< " << name << " > \\" << endl
1053 1053 << "{ \\" << endl
1054 1054 << " enum { Defined = 1 }; \\" << endl
1055 1055 << " static int qt_metatype_id() \\" << endl
1056 1056 << " { \\" << endl
1057 1057 << " static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \\" << endl
1058 1058 << " if (!metatype_id) \\" << endl
1059 1059 << " metatype_id = qRegisterMetaType< " << name << " >(\"" << name << "\"); \\" << endl
1060 1060 << " return metatype_id; \\" << endl
1061 1061 << " } \\" << endl
1062 1062 << "};" << endl;
1063 1063 } else {
1064 1064 stream << "Q_DECLARE_METATYPE(" << name << ")" << endl;
1065 1065 }
1066 1066 registeredTypeNames << name;
1067 1067 }
1068 1068
1069 1069 /*!
1070 1070 Declares the given \a type recursively (i.e. subtypes of a composite
1071 1071 type are also declared).
1072 1072 */
1073 1073 static void declareTypeRecursive(QTextStream &stream, const AbstractMetaType *type,
1074 1074 QSet<QString> &registeredTypeNames)
1075 1075 {
1076 1076 if (!type)
1077 1077 return;
1078 1078 QList<AbstractMetaType *> subTypes = type->instantiations();
1079 1079 for (int i = 0; i < subTypes.size(); ++i)
1080 1080 declareTypeRecursive(stream, subTypes.at(i), registeredTypeNames);
1081 1081 QString typeName = normalizedType(type);
1082 1082 if (typeName == QLatin1String("QStringList<QString>"))
1083 1083 return; // ### wtf...
1084 1084 maybeDeclareMetaType(stream, typeName, registeredTypeNames);
1085 1085 }
1086 1086
1087 1087 /*!
1088 1088 Declares the types associated with the given \a functions.
1089 1089 */
1090 1090 void declareFunctionMetaTypes(QTextStream &stream, const AbstractMetaFunctionList &functions,
1091 1091 QSet<QString> &registeredTypeNames)
1092 1092 {
1093 1093 for (int i = 0; i < functions.size(); ++i) {
1094 1094 AbstractMetaFunction *fun = functions.at(i);
1095 1095 if (ClassGenerator::isSpecialStreamingOperator(fun)) {
1096 1096 maybeDeclareMetaType(stream, fun->arguments().at(0)->type()->name() + "*",
1097 1097 registeredTypeNames);
1098 1098 continue;
1099 1099 }
1100 1100 AbstractMetaArgumentList arguments = fun->arguments();
1101 1101 for (int j = 0; j < arguments.size(); ++j) {
1102 1102 if (fun->argumentRemoved(j+1))
1103 1103 continue;
1104 1104 QString repl = fun->typeReplaced(j+1);
1105 1105 if (!repl.isEmpty()) {
1106 1106 maybeDeclareMetaType(stream, repl, registeredTypeNames);
1107 1107 } else {
1108 1108 const AbstractMetaArgument *arg = arguments.at(j);
1109 1109 declareTypeRecursive(stream, arg->type(), registeredTypeNames);
1110 1110 }
1111 1111 }
1112 1112 QString retRepl = fun->typeReplaced(0);
1113 1113 if (!retRepl.isEmpty())
1114 1114 maybeDeclareMetaType(stream, retRepl, registeredTypeNames);
1115 1115 else
1116 1116 declareTypeRecursive(stream, fun->type(), registeredTypeNames);
1117 1117 }
1118 1118 }
1119 1119
1120 1120 /*!
1121 1121 Returns true if we don't care about the given enum \a enom,
1122 1122 false otherwise.
1123 1123 */
1124 1124 static bool shouldIgnoreEnum(const AbstractMetaEnum *enom)
1125 1125 {
1126 1126 return !enom->wasPublic() || (enom->name() == "enum_1");
1127 1127 }
1128 1128
1129 1129 /*!
1130 1130 Declares the types associated with the enums of the given \a
1131 1131 meta_class.
1132 1132 */
1133 1133 void declareEnumMetaTypes(QTextStream &stream, const AbstractMetaClass *meta_class,
1134 1134 QSet<QString> &registeredTypeNames)
1135 1135 {
1136 1136 AbstractMetaEnumList enums = meta_class->enums();
1137 1137 for (int i = 0; i < enums.size(); ++i) {
1138 1138 const AbstractMetaEnum *enom = enums.at(i);
1139 1139 if (shouldIgnoreEnum(enom))
1140 1140 continue;
1141 1141 if (meta_class->name() == "Global")
1142 1142 maybeDeclareMetaType(stream, enom->name(), registeredTypeNames);
1143 1143 else
1144 1144 maybeDeclareMetaType(stream, QString::fromLatin1("%0::%1")
1145 1145 .arg(meta_class->qualifiedCppName()).arg(enom->name()),
1146 1146 registeredTypeNames);
1147 1147 FlagsTypeEntry *flags = enom->typeEntry()->flags();
1148 1148 if (flags) {
1149 1149 maybeDeclareMetaType(stream, QString::fromLatin1("QFlags<%0::%1>")
1150 1150 .arg(meta_class->qualifiedCppName()).arg(enom->name()),
1151 1151 registeredTypeNames);
1152 1152 }
1153 1153 }
1154 1154 }
1155 1155
1156 1156 /*!
1157 1157 Returns the maximum function length among \a functions.
1158 1158 */
1159 1159 static int maxFunctionLength(const AbstractMetaFunctionList &functions)
1160 1160 {
1161 1161 int result = 0;
1162 1162 for (int i = 0; i < functions.size(); ++i)
1163 1163 result = qMax(result, functions.at(i)->arguments().size());
1164 1164 return result;
1165 1165 }
1166 1166
1167 1167 /*!
1168 1168 Writes a prototype/static function.
1169 1169 */
1170 1170 static void writeFunctionForwarding(QTextStream &stream, const AbstractMetaClass *meta_class,
1171 1171 const AbstractMetaFunctionList &functions)
1172 1172 {
1173 1173 #if 0
1174 1174 stream << "/** signatures:" << endl;
1175 1175 foreach (const AbstractMetaFunction *fun, functions) {
1176 1176 stream << " * " << fun->signature() << endl;
1177 1177 }
1178 1178 stream << " */" << endl;
1179 1179 #endif
1180 1180 QMap<int, AbstractMetaFunctionList> argcToFunctions;
1181 1181 argcToFunctions = createArgcToFunctionsMap(functions);
1182 1182 QSet<QString> signatures;
1183 1183 int argcMin = argcToFunctions.keys().first();
1184 1184 int argcMax = argcToFunctions.keys().last();
1185 1185 for (int i = argcMin; i <= argcMax; ++i) {
1186 1186 AbstractMetaFunctionList funcs = argcToFunctions.value(i);
1187 1187 if (funcs.isEmpty())
1188 1188 continue;
1189 1189 stream << " if (context->argumentCount() == " << i << ") {" << endl;
1190 1190 if (funcs.size() == 1) {
1191 1191 AbstractMetaFunction *fun = funcs.at(0);
1192 1192 const int indent = 8;
1193 1193 // special case for Q{Data,Text}Stream streaming operators
1194 1194 if (ClassGenerator::isSpecialStreamingOperator(fun))
1195 1195 writeStreamingOperatorCall(stream, fun, meta_class, indent);
1196 1196 else
1197 1197 writeFunctionCallAndReturn(stream, fun, i, meta_class, indent);
1198 1198 signatures.insert(fun->targetLangSignature());
1199 1199 } else {
1200 1200 // handle overloads
1201 1201 QStringList sigs;
1202 1202 for (int j = 0; j < funcs.size(); ++j) {
1203 1203 AbstractMetaFunction *fun = funcs.at(j);
1204 1204 sigs.append(fun->signature());
1205 1205 stream << " ";
1206 1206 if (j > 0)
1207 1207 stream << "} else ";
1208 1208 stream << "if (";
1209 1209 AbstractMetaArgumentList arguments = fun->arguments();
1210 1210 const int indent = 12;
1211 1211 writeArgumentTypeTests(stream, fun, arguments, i, indent);
1212 1212 stream << ") {" << endl;
1213 1213 writeFunctionCallAndReturn(stream, fun, i, meta_class, indent);
1214 1214 signatures.insert(fun->targetLangSignature());
1215 1215 }
1216 1216 stream << " }" << endl;
1217 1217 }
1218 1218 stream << " }" << endl;
1219 1219 }
1220 1220 }
1221 1221
1222 1222 static void writePrototypeCall(QTextStream &s, const AbstractMetaClass *meta_class,
1223 1223 const QMap<QString, AbstractMetaFunctionList> &nameToFunctions,
1224 1224 int prototypeFunctionsOffset)
1225 1225 {
1226 1226 s << "static QScriptValue qtscript_" << meta_class->name()
1227 1227 << "_prototype_call(QScriptContext *context, QScriptEngine *)" << endl
1228 1228 << "{" << endl;
1229 1229
1230 1230 s << "#if QT_VERSION > 0x040400" << endl;
1231 1231
1232 1232 s << " Q_ASSERT(context->callee().isFunction());" << endl
1233 1233 << " uint _id = context->callee().data().toUInt32();" << endl;
1234 1234
1235 1235 s << "#else" << endl
1236 1236 << " uint _id;" << endl
1237 1237 << " if (context->callee().isFunction())" << endl
1238 1238 << " _id = context->callee().data().toUInt32();" << endl
1239 1239 << " else" << endl
1240 1240 << " _id = 0xBABE0000 + " << nameToFunctions.size() << ";" << endl;
1241 1241
1242 1242 s << "#endif" << endl;
1243 1243
1244 1244 s << " Q_ASSERT((_id & 0xFFFF0000) == 0xBABE0000);" << endl
1245 1245 << " _id &= 0x0000FFFF;" << endl;
1246 1246
1247 1247 // cast the thisObject to C++ type
1248 1248 s << " ";
1249 1249 #ifndef GENERATOR_NO_PROTECTED_FUNCTIONS
1250 1250 if (meta_class->hasProtectedFunctions())
1251 1251 s << "qtscript_";
1252 1252 #endif
1253 1253 s << meta_class->qualifiedCppName() << "* _q_self = ";
1254 1254 #ifndef GENERATOR_NO_PROTECTED_FUNCTIONS
1255 1255 if (meta_class->hasProtectedFunctions())
1256 1256 s << "reinterpret_cast<qtscript_" << meta_class->name() << "*>(";
1257 1257 #endif
1258 1258 s << "qscriptvalue_cast<" << meta_class->qualifiedCppName()
1259 1259 << "*>(context->thisObject())";
1260 1260 #ifndef GENERATOR_NO_PROTECTED_FUNCTIONS
1261 1261 if (meta_class->hasProtectedFunctions())
1262 1262 s << ")";
1263 1263 #endif
1264 1264 s << ";" << endl
1265 1265 << " if (!_q_self) {" << endl
1266 1266 << " return context->throwError(QScriptContext::TypeError," << endl
1267 1267 << " QString::fromLatin1(\"" << meta_class->name()
1268 1268 << ".%0(): this object is not a " << meta_class->name() << "\")" << endl
1269 1269 << " .arg(qtscript_" << meta_class->name()
1270 1270 << "_function_names[_id+" << prototypeFunctionsOffset <<"]));" << endl
1271 1271 << " }" << endl << endl;
1272 1272
1273 1273 s << " switch (_id) {" << endl;
1274 1274
1275 1275 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1276 1276 int index = 0;
1277 1277 for (it = nameToFunctions.constBegin(); it != nameToFunctions.constEnd(); ++it) {
1278 1278 s << " case " << index << ":" << endl;
1279 1279 writeFunctionForwarding(s, meta_class, it.value());
1280 1280 s << " break;" << endl << endl;
1281 1281 ++index;
1282 1282 }
1283 1283
1284 1284 if (!meta_class->hasDefaultToStringFunction()) {
1285 1285 s << " case " << index << ": {" << endl;
1286 1286 s << " QString result";
1287 1287 FunctionModelItem fun = meta_class->hasToStringCapability();
1288 1288 if (fun) {
1289 1289 int indirections = fun->arguments().at(1)->type().indirections();
1290 1290 QString deref = QLatin1String(indirections == 0 ? "*" : "");
1291 1291 s << ";" << endl
1292 1292 << " QDebug d(&result);" << endl
1293 1293 << " d << " << deref << "_q_self;" << endl;
1294 1294 } else {
1295 1295 // ### FIXME: can cause compile error
1296 1296 // s << "=QString(\"" << meta_class->name() << "(0x%1)\").arg((int)_q_self, 0, 16);" << endl;
1297 1297 s << " = QString::fromLatin1(\"" << meta_class->name() << "\");" << endl;
1298 1298 }
1299 1299 s << " return QScriptValue(context->engine(), result);" << endl
1300 1300 << " }" << endl << endl;
1301 1301 }
1302 1302
1303 1303 s << " default:" << endl
1304 1304 << " Q_ASSERT(false);" << endl
1305 1305 << " }" << endl;
1306 1306
1307 1307 s << " return qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(context," << endl
1308 1308 << " qtscript_" << meta_class->name()
1309 1309 << "_function_names[_id+" << prototypeFunctionsOffset << "]," << endl
1310 1310 << " qtscript_" << meta_class->name()
1311 1311 << "_function_signatures[_id+" << prototypeFunctionsOffset << "]);" << endl;
1312 1312
1313 1313 s << "}" << endl << endl;
1314 1314 }
1315 1315
1316 1316 static void writeStaticCall(QTextStream &s, const AbstractMetaClass *meta_class,
1317 1317 const AbstractMetaFunctionList &constructors,
1318 1318 const QMap<QString, AbstractMetaFunctionList> &nameToFunctions)
1319 1319 {
1320 1320 s << "static QScriptValue qtscript_" << meta_class->name()
1321 1321 << "_static_call(QScriptContext *context, QScriptEngine *)" << endl
1322 1322 << "{" << endl;
1323 1323
1324 1324 s << " uint _id = context->callee().data().toUInt32();" << endl
1325 1325 << " Q_ASSERT((_id & 0xFFFF0000) == 0xBABE0000);" << endl
1326 1326 << " _id &= 0x0000FFFF;" << endl;
1327 1327
1328 1328 s << " switch (_id) {" << endl;
1329 1329
1330 1330 s << " case 0:" << endl;
1331 1331 writeConstructorForwarding(s, constructors, meta_class);
1332 1332 s << " break;" << endl << endl;
1333 1333
1334 1334 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1335 1335 int index = 1;
1336 1336 for (it = nameToFunctions.constBegin(); it != nameToFunctions.constEnd(); ++it) {
1337 1337 s << " case " << index << ":" << endl;
1338 1338 writeFunctionForwarding(s, meta_class, it.value());
1339 1339 s << " break;" << endl << endl;
1340 1340 ++index;
1341 1341 }
1342 1342
1343 1343 s << " default:" << endl
1344 1344 << " Q_ASSERT(false);" << endl
1345 1345 << " }" << endl;
1346 1346
1347 1347 s << " return qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(context," << endl
1348 1348 << " qtscript_" << meta_class->name() << "_function_names[_id]," << endl
1349 1349 << " qtscript_" << meta_class->name() << "_function_signatures[_id]);" << endl;
1350 1350
1351 1351 s << "}" << endl << endl;
1352 1352 }
1353 1353
1354 1354 /*!
1355 1355 Writes the include defined by \a inc to \a stream.
1356 1356 */
1357 1357 void ClassGenerator::writeInclude(QTextStream &stream, const Include &inc)
1358 1358 {
1359 1359 if (inc.name.isEmpty())
1360 1360 return;
1361 1361 if (inc.type == Include::TargetLangImport)
1362 1362 return;
1363 1363 stream << "#include ";
1364 1364 if (inc.type == Include::IncludePath)
1365 1365 stream << "<";
1366 1366 else
1367 1367 stream << "\"";
1368 1368 stream << inc.name;
1369 1369 if (inc.type == Include::IncludePath)
1370 1370 stream << ">";
1371 1371 else
1372 1372 stream << "\"";
1373 1373 stream << endl;
1374 1374 }
1375 1375
1376 1376 static void writeHelperFunctions(QTextStream &stream, const AbstractMetaClass *meta_class)
1377 1377 {
1378 1378 stream << "static QScriptValue qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(" << endl
1379 1379 << " QScriptContext *context, const char *functionName, const char *signatures)" << endl
1380 1380 << "{" << endl
1381 1381 << " QStringList lines = QString::fromLatin1(signatures).split(QLatin1Char('\\n'));" << endl
1382 1382 << " QStringList fullSignatures;" << endl
1383 1383 << " for (int i = 0; i < lines.size(); ++i)" << endl
1384 1384 << " fullSignatures.append(QString::fromLatin1(\"%0(%1)\").arg(functionName).arg(lines.at(i)));" << endl
1385 1385 << " return context->throwError(QString::fromLatin1(\"" << meta_class->name()
1386 1386 << "::%0(): could not find a function match; candidates are:\\n%1\")" << endl
1387 1387 << " .arg(functionName).arg(fullSignatures.join(QLatin1String(\"\\n\"))));" << endl
1388 1388 << "}" << endl << endl;
1389 1389 }
1390 1390
1391 void writeQtScriptQtBindingsLicense(QTextStream &stream)
1392 {
1393 stream
1394 << "/****************************************************************************" << endl
1395 << "**" << endl
1396 << "** Copyright (C) 2008 Trolltech ASA. All rights reserved." << endl
1397 << "**" << endl
1398 << "** This file is part of the Qt Script Qt Bindings project on Trolltech Labs." << endl
1399 << "**" << endl
1400 << "** This file may be used under the terms of the GNU General Public" << endl
1401 << "** License version 2.0 as published by the Free Software Foundation" << endl
1402 << "** and appearing in the file LICENSE.GPL included in the packaging of" << endl
1403 << "** this file. Please review the following information to ensure GNU" << endl
1404 << "** General Public Licensing requirements will be met:" << endl
1405 << "** http://www.trolltech.com/products/qt/opensource.html" << endl
1406 << "**" << endl
1407 << "** If you are unsure which license is appropriate for your use, please" << endl
1408 << "** review the following information:" << endl
1409 << "** http://www.trolltech.com/products/qt/licensing.html or contact the" << endl
1410 << "** sales department at sales@trolltech.com." << endl
1411 << "**" << endl
1412 << "** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE" << endl
1413 << "** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE." << endl
1414 << "**" << endl
1415 << "****************************************************************************/" << endl
1416 << endl;
1417 }
1418 1391
1419 1392 /*!
1420 1393 Finds the functions in \a meta_class that we actually want to
1421 1394 generate bindings for.
1422 1395 */
1423 1396 void findPrototypeAndStaticFunctions(
1424 1397 const AbstractMetaClass *meta_class,
1425 1398 QMap<QString, AbstractMetaFunctionList> &nameToPrototypeFunctions,
1426 1399 QMap<QString, AbstractMetaFunctionList> &nameToStaticFunctions)
1427 1400 {
1428 1401 AbstractMetaFunctionList functions = meta_class->functionsInTargetLang();
1429 1402 for (int i = 0; i < functions.size(); ++i) {
1430 1403 AbstractMetaFunction* func = functions.at(i);
1431 1404 if (!func->isNormal())
1432 1405 continue;
1433 1406 #ifdef GENERATOR_NO_PROTECTED_FUNCTIONS
1434 1407 if (func->wasProtected())
1435 1408 continue;
1436 1409 #endif
1437 1410 if (func->declaringClass() != meta_class)
1438 1411 continue; // function inherited through prototype
1439 1412 if (func->isPropertyReader() || func->isPropertyWriter())
1440 1413 continue; // no point in including property accessors
1441 1414 if (func->isSlot() || func->isSignal() || func->isInvokable())
1442 1415 continue; // no point in including signals and slots
1443 1416 QMap<QString, AbstractMetaFunctionList> &map =
1444 1417 func->isStatic() ? nameToStaticFunctions : nameToPrototypeFunctions;
1445 1418 map[func->modifiedName()].append(func);
1446 1419 }
1447 1420 }
1448 1421
1449 1422 static void writeFunctionSignaturesString(QTextStream &s, const AbstractMetaFunctionList &functions)
1450 1423 {
1451 1424 s << "\"";
1452 1425 for (int i = 0; i < functions.size(); ++i) {
1453 1426 if (i > 0)
1454 1427 s << "\\n";
1455 1428 QString sig = functions.at(i)->targetLangSignature();
1456 1429 sig = sig.mid(sig.indexOf('(') + 1);
1457 1430 sig.chop(1);
1458 1431 s << sig;
1459 1432 }
1460 1433 s << "\"";
1461 1434 }
1462 1435
1463 1436 /*!
1464 1437 Writes the whole native binding for the class \a meta_class.
1465 1438 */
1466 1439 void ClassGenerator::write(QTextStream &stream, const AbstractMetaClass *meta_class)
1467 1440 {
1468 if (FileOut::license)
1469 writeQtScriptQtBindingsLicense(stream);
1470
1471 1441 // write common includes
1472 1442 stream << "#include <QtScript/QScriptEngine>" << endl;
1473 1443 stream << "#include <QtScript/QScriptContext>" << endl;
1474 1444 stream << "#include <QtScript/QScriptValue>" << endl;
1475 1445 stream << "#include <QtCore/QStringList>" << endl;
1476 1446 stream << "#include <QtCore/QDebug>" << endl;
1477 1447 stream << "#include <qmetaobject.h>" << endl;
1478 1448 stream << endl;
1479 1449
1480 1450 // write class-specific includes
1481 1451 {
1482 1452 Include inc = meta_class->typeEntry()->include();
1483 1453 writeInclude(stream, inc);
1484 1454 }
1485 1455 {
1486 1456 IncludeList includes = meta_class->typeEntry()->extraIncludes();
1487 1457 qSort(includes.begin(), includes.end());
1488 1458
1489 1459 foreach (const Include &i, includes) {
1490 1460 writeInclude(stream, i);
1491 1461 }
1492 1462 }
1493 1463 stream << endl;
1494 1464
1495 1465 if (meta_class->generateShellClass()) {
1496 1466 stream << "#include \"qtscriptshell_" << meta_class->name() << ".h\"" << endl;
1497 1467 stream << endl;
1498 1468 }
1499 1469
1500 1470 AbstractMetaEnumList enums = meta_class->enums();
1501 1471 {
1502 1472 // kill the enums we don't care about
1503 1473 AbstractMetaEnumList::iterator it;
1504 1474 for (it = enums.begin(); it != enums.end(); ) {
1505 1475 if (shouldIgnoreEnum(*it))
1506 1476 it = enums.erase(it);
1507 1477 else
1508 1478 ++it;
1509 1479 }
1510 1480 }
1511 1481
1512 1482 if (meta_class->isNamespace() || meta_class->name() == "Global") {
1513 1483 QMap<QString, Include> includes;
1514 1484 foreach (AbstractMetaEnum *enom, enums) {
1515 1485 Include include = enom->typeEntry()->include();
1516 1486 includes.insert(include.toString(), include);
1517 1487 }
1518 1488
1519 1489 foreach (const Include &i, includes) {
1520 1490 writeInclude(stream, i);
1521 1491 }
1522 1492
1523 1493 stream << endl;
1524 1494 }
1525 1495
1526 1496 if (meta_class->name() == "Global") {
1527 1497 stream << "class Global {};" << endl;
1528 1498 stream << endl;
1529 1499 }
1530 1500
1531 1501 // find constructors
1532 1502 AbstractMetaFunctionList ctors = findConstructors(meta_class);
1533 1503 bool hasDefaultCtor = findDefaultConstructor(ctors) != 0;
1534 1504
1535 1505 // find interesting functions
1536 1506 QMap<QString, AbstractMetaFunctionList> nameToPrototypeFunctions;
1537 1507 QMap<QString, AbstractMetaFunctionList> nameToStaticFunctions;
1538 1508 findPrototypeAndStaticFunctions(meta_class, nameToPrototypeFunctions, nameToStaticFunctions);
1539 1509
1540 1510 int staticFunctionsOffset = 1;
1541 1511 int prototypeFunctionsOffset = staticFunctionsOffset + nameToStaticFunctions.size();
1542 1512
1543 1513 // write table of function names
1544 1514 stream << "static const char * const qtscript_"
1545 1515 << meta_class->name() << "_function_names[] = {" << endl;
1546 1516 stream << " \"" << meta_class->name() << "\"" << endl;
1547 1517 {
1548 1518 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1549 1519 stream << " // static" << endl;
1550 1520 for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) {
1551 1521 stream << " , ";
1552 1522 stream << "\"" << it.key() << "\"" << endl;
1553 1523 }
1554 1524 stream << " // prototype" << endl;
1555 1525 for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) {
1556 1526 QString functionName = it.key();
1557 1527 QString scriptName = functionName;
1558 1528 if (functionName == QLatin1String("operator_equal"))
1559 1529 scriptName = QLatin1String("equals");
1560 1530 stream << " , ";
1561 1531 stream << "\"" << scriptName << "\"" << endl;
1562 1532 }
1563 1533 if (!meta_class->hasDefaultToStringFunction())
1564 1534 stream << " , \"toString\"" << endl;
1565 1535 }
1566 1536 stream << "};" << endl << endl;
1567 1537
1568 1538 // write table of function signatures
1569 1539 stream << "static const char * const qtscript_"
1570 1540 << meta_class->name() << "_function_signatures[] = {" << endl;
1571 1541 stream << " ";
1572 1542 writeFunctionSignaturesString(stream, ctors);
1573 1543 stream << endl;
1574 1544 {
1575 1545 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1576 1546 stream << " // static" << endl;
1577 1547 for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) {
1578 1548 stream << " , ";
1579 1549 writeFunctionSignaturesString(stream, it.value());
1580 1550 stream << endl;
1581 1551 }
1582 1552 stream << " // prototype" << endl;
1583 1553 for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) {
1584 1554 stream << " , ";
1585 1555 writeFunctionSignaturesString(stream, it.value());
1586 1556 stream << endl;
1587 1557 }
1588 1558 if (!meta_class->hasDefaultToStringFunction())
1589 1559 stream << "\"\"" << endl;
1590 1560 }
1591 1561 stream << "};" << endl << endl;
1592 1562
1593 1563 // write table of function lengths
1594 1564 stream << "static const int qtscript_" << meta_class->name() << "_function_lengths[] = {" << endl;
1595 1565 stream << " " << maxFunctionLength(ctors) << endl;
1596 1566 {
1597 1567 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1598 1568 stream << " // static" << endl;
1599 1569 for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) {
1600 1570 stream << " , " << maxFunctionLength(it.value()) << endl;
1601 1571 }
1602 1572 stream << " // prototype" << endl;
1603 1573 for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) {
1604 1574 stream << " , " << maxFunctionLength(it.value()) << endl;
1605 1575 }
1606 1576 if (!meta_class->hasDefaultToStringFunction())
1607 1577 stream << " , 0" << endl;
1608 1578 }
1609 1579 stream << "};" << endl << endl;
1610 1580
1611 1581 #ifndef GENERATOR_NO_PROTECTED_FUNCTIONS
1612 1582 if (meta_class->hasProtectedFunctions()) {
1613 1583 // write a friendly class
1614 1584 stream << "class qtscript_" << meta_class->name()
1615 1585 << " : public " << meta_class->qualifiedCppName() << endl;
1616 1586 stream << "{" << endl;
1617 1587 for (int x = 0; x < 2; ++x) {
1618 1588 QMap<QString, AbstractMetaFunctionList> &map =
1619 1589 x ? nameToStaticFunctions : nameToPrototypeFunctions;
1620 1590 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1621 1591 for (it = map.constBegin(); it != map.constEnd(); ++it) {
1622 1592 AbstractMetaFunctionList functions = it.value();
1623 1593 for (int i = 0; i < functions.size(); ++i) {
1624 1594 if (functions.at(i)->isProtected()) {
1625 1595 stream << " friend QScriptValue qtscript_" << meta_class->name()
1626 1596 << "_" << it.key();
1627 1597 if (functions.at(i)->isStatic())
1628 1598 stream << "_static";
1629 1599 stream << "(QScriptContext *, QScriptEngine *);" << endl;
1630 1600 break;
1631 1601 }
1632 1602 }
1633 1603 }
1634 1604 }
1635 1605 stream << "};" << endl;
1636 1606 stream << endl;
1637 1607 }
1638 1608 #endif
1639 1609
1640 1610 writeHelperFunctions(stream, meta_class);
1641 1611
1642 1612 // write metaobject getter if we need it
1643 1613 if (hasQEnums(enums) && (meta_class->qualifiedCppName() != "QTransform")) {
1644 1614 if (meta_class->qualifiedCppName() == "Qt") {
1645 1615 stream << "struct qtscript_Qt_metaObject_helper : private QObject" << endl
1646 1616 << "{" << endl
1647 1617 << " static const QMetaObject *get()" << endl
1648 1618 << " { return &static_cast<qtscript_Qt_metaObject_helper*>(0)->staticQtMetaObject; }" << endl
1649 1619 << "};" << endl << endl;
1650 1620 }
1651 1621 stream << "static const QMetaObject *qtscript_" << meta_class->name() << "_metaObject()" << endl
1652 1622 << "{" << endl
1653 1623 << " return ";
1654 1624 if (meta_class->qualifiedCppName() == "Qt")
1655 1625 stream << "qtscript_Qt_metaObject_helper::get()";
1656 1626 else
1657 1627 stream << "&" << meta_class->qualifiedCppName() << "::staticMetaObject";
1658 1628 stream << ";" << endl
1659 1629 << "}" << endl << endl;
1660 1630 }
1661 1631
1662 1632 // write metatype declarations
1663 1633 {
1664 1634 QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
1665 1635
1666 1636 if (!meta_class->isNamespace()) {
1667 1637 if (meta_class->typeEntry()->isValue() && hasDefaultCtor)
1668 1638 maybeDeclareMetaType(stream, meta_class->qualifiedCppName(), registeredTypeNames);
1669 1639 else
1670 1640 registeredTypeNames << meta_class->qualifiedCppName();
1671 1641 maybeDeclareMetaType(stream, meta_class->qualifiedCppName() + "*", registeredTypeNames);
1672 1642 }
1673 1643 if (meta_class->generateShellClass()) {
1674 1644 if (meta_class->typeEntry()->isValue()) {
1675 1645 maybeDeclareMetaType(stream, "QtScriptShell_" + meta_class->name(),
1676 1646 registeredTypeNames);
1677 1647 }
1678 1648 maybeDeclareMetaType(stream, "QtScriptShell_" + meta_class->name() + "*",
1679 1649 registeredTypeNames);
1680 1650 }
1681 1651
1682 1652 declareEnumMetaTypes(stream, meta_class, registeredTypeNames);
1683 1653
1684 1654 for (int x = 0; x < 2; ++x) {
1685 1655 QMap<QString, AbstractMetaFunctionList> &map =
1686 1656 x ? nameToStaticFunctions : nameToPrototypeFunctions;
1687 1657 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1688 1658 for (it = map.constBegin(); it != map.constEnd(); ++it) {
1689 1659 declareFunctionMetaTypes(stream, it.value(), registeredTypeNames);
1690 1660 }
1691 1661 }
1692 1662
1693 1663 declareFunctionMetaTypes(stream, ctors, registeredTypeNames);
1694 1664
1695 1665 if (meta_class->baseClass() != 0) {
1696 1666 maybeDeclareMetaType(stream, meta_class->baseClass()->qualifiedCppName()
1697 1667 + QLatin1String("*"), registeredTypeNames);
1698 1668 }
1699 1669 foreach (AbstractMetaClass *iface, meta_class->interfaces()) {
1700 1670 AbstractMetaClass *impl = iface->primaryInterfaceImplementor();
1701 1671 maybeDeclareMetaType(stream, impl->qualifiedCppName() + QLatin1String("*"),
1702 1672 registeredTypeNames);
1703 1673 }
1704 1674
1705 1675 // ### hackety hack
1706 1676 if (meta_class->name().endsWith("Gradient"))
1707 1677 maybeDeclareMetaType(stream, "QGradient", registeredTypeNames);
1708 1678
1709 1679 stream << endl;
1710 1680 }
1711 1681
1712 1682 writeInjectedCode(stream, meta_class, CodeSnip::Beginning);
1713 1683
1714 1684 // write enum classes
1715 1685 if (!enums.isEmpty()) {
1716 1686 writeCreateEnumClassHelper(stream);
1717 1687 if (hasFlags(enums))
1718 1688 writeCreateFlagsClassHelper(stream);
1719 1689
1720 1690 for (int i = 0; i < enums.size(); ++i) {
1721 1691 const AbstractMetaEnum *enom = enums.at(i);
1722 1692 writeEnumClass(stream, meta_class, enom);
1723 1693 }
1724 1694 }
1725 1695
1726 1696 stream << "//" << endl;
1727 1697 stream << "// " << meta_class->name() << endl;
1728 1698 stream << "//" << endl << endl;
1729 1699
1730 1700 if (!meta_class->isNamespace()) {
1731 1701 if (!nameToPrototypeFunctions.isEmpty() || !meta_class->hasDefaultToStringFunction())
1732 1702 writePrototypeCall(stream, meta_class, nameToPrototypeFunctions, prototypeFunctionsOffset);
1733 1703 }
1734 1704
1735 1705 writeStaticCall(stream, meta_class, ctors, nameToStaticFunctions);
1736 1706
1737 1707 if (isQObjectBased(meta_class)) {
1738 1708 // write C++ <--> script conversion functions
1739 1709 stream << "static QScriptValue qtscript_" << meta_class->name() << "_toScriptValue(QScriptEngine *engine, "
1740 1710 << meta_class->qualifiedCppName() << "* const &in)" << endl
1741 1711 << "{" << endl
1742 1712 << " return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject);" << endl
1743 1713 << "}" << endl << endl;
1744 1714 stream << "static void qtscript_" << meta_class->name() << "_fromScriptValue(const QScriptValue &value, "
1745 1715 << meta_class->qualifiedCppName() << "* &out)" << endl
1746 1716 << "{" << endl
1747 1717 << " out = qobject_cast<" << meta_class->qualifiedCppName() << "*>(value.toQObject());" << endl
1748 1718 << "}" << endl << endl;
1749 1719 }
1750 1720
1751 1721 //
1752 1722 // write exported function that creates the QtScript class
1753 1723 //
1754 1724 stream << "QScriptValue qtscript_create_" << meta_class->name()
1755 1725 << "_class(QScriptEngine *engine)" << endl;
1756 1726 stream << "{" << endl;
1757 1727
1758 1728 // setup prototype
1759 1729 if (!meta_class->isNamespace()) {
1760 1730 stream << " engine->setDefaultPrototype(qMetaTypeId<"
1761 1731 << meta_class->qualifiedCppName() << "*>(), QScriptValue());" << endl;
1762 1732 stream << " QScriptValue proto = engine->newVariant(qVariantFromValue(("
1763 1733 << meta_class->qualifiedCppName() << "*)0));" << endl;
1764 1734 bool havePrototypePrototype = false;
1765 1735 if (meta_class->baseClass() != 0) {
1766 1736 stream << " proto.setPrototype(engine->defaultPrototype(qMetaTypeId<"
1767 1737 << meta_class->baseClass()->qualifiedCppName() << "*>()));" << endl;
1768 1738 havePrototypePrototype = true;
1769 1739 }
1770 1740 foreach (AbstractMetaClass *iface, meta_class->interfaces()) {
1771 1741 AbstractMetaClass *impl = iface->primaryInterfaceImplementor();
1772 1742 if (impl == meta_class)
1773 1743 continue;
1774 1744 if (!havePrototypePrototype) {
1775 1745 stream << " proto.setPrototype(engine->defaultPrototype(qMetaTypeId<"
1776 1746 << impl->qualifiedCppName() << "*>()));" << endl;
1777 1747 havePrototypePrototype = true;
1778 1748 } else {
1779 1749 // alternative would be to copy the properties from the secondary
1780 1750 // prototype to the primary prototype.
1781 1751 stream << " proto.setProperty(QString::fromLatin1(\"__"
1782 1752 << impl->name() << "__\")," << endl
1783 1753 << " engine->defaultPrototype(qMetaTypeId<"
1784 1754 << impl->qualifiedCppName() << "*>())," << endl
1785 1755 << " QScriptValue::SkipInEnumeration);" << endl;
1786 1756 }
1787 1757 }
1788 1758 if (!nameToPrototypeFunctions.isEmpty()) {
1789 1759 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1790 1760 int count = nameToPrototypeFunctions.size();
1791 1761 if (!meta_class->hasDefaultToStringFunction())
1792 1762 ++count;
1793 1763 stream << " for (int i = 0; i < " << count << "; ++i) {" << endl
1794 1764 << " QScriptValue fun = engine->newFunction(qtscript_"
1795 1765 << meta_class->name() << "_prototype_call, qtscript_"
1796 1766 << meta_class->name() << "_function_lengths[i+"
1797 1767 << prototypeFunctionsOffset << "]);" << endl
1798 1768 << " fun.setData(QScriptValue(engine, uint(0xBABE0000 + i)));" << endl
1799 1769 << " proto.setProperty(QString::fromLatin1(qtscript_"
1800 1770 << meta_class->name() << "_function_names[i+" << prototypeFunctionsOffset << "])," << endl
1801 1771 << " fun, QScriptValue::SkipInEnumeration);" << endl
1802 1772 << " }" << endl;
1803 1773 }
1804 1774 writeInjectedCode(stream, meta_class, CodeSnip::PrototypeInitialization);
1805 1775 stream << endl;
1806 1776
1807 1777 // register the prototype
1808 1778 // stream << " qDebug() << \"registering " << meta_class->name() << " prototype\";" << endl;
1809 1779 if (meta_class->typeEntry()->isValue() && hasDefaultCtor) {
1810 1780 stream << " engine->setDefaultPrototype(qMetaTypeId<"
1811 1781 << meta_class->qualifiedCppName() << ">(), proto);" << endl;
1812 1782 }
1813 1783 if (isQObjectBased(meta_class)) {
1814 1784 stream << " qScriptRegisterMetaType<" << meta_class->qualifiedCppName() << "*>(engine, qtscript_"
1815 1785 << meta_class->name() << "_toScriptValue, " << endl << " qtscript_"
1816 1786 << meta_class->name() << "_fromScriptValue, proto);" << endl;
1817 1787 } else {
1818 1788 stream << " engine->setDefaultPrototype(qMetaTypeId<"
1819 1789 << meta_class->qualifiedCppName() << "*>(), proto);" << endl;
1820 1790 }
1821 1791 stream << endl;
1822 1792 } else {
1823 1793 stream << " QScriptValue proto = QScriptValue();" << endl;
1824 1794 }
1825 1795
1826 1796 // setup constructor
1827 1797 stream << " QScriptValue ctor = engine->newFunction(qtscript_" << meta_class->name()
1828 1798 << "_static_call, proto, qtscript_" << meta_class->name() << "_function_lengths[0]);" << endl;
1829 1799 stream << " ctor.setData(QScriptValue(engine, uint(0xBABE0000 + 0)));" << endl;
1830 1800 if (!nameToStaticFunctions.isEmpty()) {
1831 1801 // static functions
1832 1802 QMap<QString, AbstractMetaFunctionList>::const_iterator it;
1833 1803 stream << " for (int i = 0; i < " << nameToStaticFunctions.size() << "; ++i) {" << endl
1834 1804 << " QScriptValue fun = engine->newFunction(qtscript_" << meta_class->name()
1835 1805 << "_static_call," << endl
1836 1806 << " qtscript_" << meta_class->name() << "_function_lengths[i+" << staticFunctionsOffset << "]);" << endl
1837 1807 << " fun.setData(QScriptValue(engine, uint(0xBABE0000 + i+1)));" << endl
1838 1808 << " ctor.setProperty(QString::fromLatin1(qtscript_"
1839 1809 << meta_class->name() << "_function_names[i+" << staticFunctionsOffset << "])," << endl
1840 1810 << " fun, QScriptValue::SkipInEnumeration);" << endl
1841 1811 << " }" << endl;
1842 1812 }
1843 1813 stream << endl;
1844 1814 // enums and flags classes
1845 1815 {
1846 1816 for (int i = 0; i < enums.size(); ++i) {
1847 1817 const AbstractMetaEnum *enom = enums.at(i);
1848 1818 stream << " ctor.setProperty(QString::fromLatin1(\""
1849 1819 << enom->name() << "\")," << endl
1850 1820 << " qtscript_create_" << meta_class->name()
1851 1821 << "_" << enom->name() << "_class(engine, ctor));" << endl;
1852 1822 FlagsTypeEntry *flags = enom->typeEntry()->flags();
1853 1823 if (flags) {
1854 1824 stream << " ctor.setProperty(QString::fromLatin1(\""
1855 1825 << flags->targetLangName() << "\")," << endl
1856 1826 << " qtscript_create_" << meta_class->name()
1857 1827 << "_" << flags->targetLangName() << "_class(engine));" << endl;
1858 1828 }
1859 1829 }
1860 1830 }
1861 1831
1862 1832 writeInjectedCode(stream, meta_class, CodeSnip::ConstructorInitialization);
1863 1833
1864 1834 stream << " return ctor;" << endl;
1865 1835 stream << "}" << endl;
1866 1836
1867 1837 writeInjectedCode(stream, meta_class, CodeSnip::End);
1868 1838
1869 1839 QString packName = meta_class->package().replace(".", "_");
1870 1840 priGenerator->addSource(packName, fileNameForClass(meta_class));
1871 1841 setupGenerator->addClass(meta_class);
1872 1842 }
@@ -1,86 +1,157
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 "prigenerator.h"
43 #include "shellgenerator.h"
43 44 #include "reporthandler.h"
44 45 #include "fileout.h"
45 46
46 47 void PriGenerator::addHeader(const QString &folder, const QString &header)
47 48 {
48 49 priHash[folder].headers << header;
49 50 }
50 51
51 52 void PriGenerator::addSource(const QString &folder, const QString &source)
52 53 {
53 54 priHash[folder].sources << source;
54 55 }
55 56
57 static void collectAndRemoveFile(QTextStream& stream, const QString& file) {
58 QFile f(file);
59 if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
60 QString s = QString::fromLatin1(f.readAll());
61 if (file.endsWith(".cpp")) {
62 // remove first line include
63 s = s.mid(s.indexOf('\n')+1);
64 }
65 stream << s;
66 f.close();
67 QFile::remove(file);
68 }
69 }
70
71 static QString combineIncludes(const QString& text) {
72 QStringList lines = text.split('\n');
73 QSet<QString> includes;
74 QString result;
75 foreach(QString line, lines) {
76 if (line.startsWith("#include")) {
77 includes.insert(line);
78 } else if (line.startsWith("#")) {
79 // skip preprocessor stuff
80 } else {
81 result += line + "\n";
82 }
83 }
84 QStringList includeList = includes.toList();
85 qSort(includeList);
86 result = includeList.join("\n") + result;
87 return result;
88 }
89
90 static QStringList compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix) {
91 QStringList outList;
92 int count = list.count();
93 int fileNum = 0;
94 while (count>0) {
95 QString outFileName = prefix + QString::number(fileNum) + ext;
96 FileOut file(dir + "/" + outFileName);
97 if (ext == ".cpp") {
98 file.stream << "#include \"" + prefix + QString::number(fileNum) + ".h\"\n";
99 }
100 outList << outFileName;
101 QString allText;
102 QTextStream ts(&allText);
103 for (int i = 0; i<MAX_CLASSES_PER_FILE && count>0; i++) {
104 collectAndRemoveFile(ts, dir + "/" + list.at(list.length()-count));
105 count--;
106 }
107 allText = combineIncludes(allText);
108 file.stream << allText;
109 fileNum++;
110 }
111 return outList;
112 }
113
56 114 void PriGenerator::generate()
57 115 {
58 116 QHashIterator<QString, Pri> pri(priHash);
59 117 while (pri.hasNext()) {
60 118 pri.next();
61 119 QStringList list = pri.value().headers;
62 120 if (list.isEmpty())
63 121 continue;
64 122
65 123 QString folder = pri.key();
66 FileOut file(m_out_dir + "/generated_cpp/" + folder + "/" + folder + ".pri");
67 file.stream << "HEADERS += \\\n";
124 folder.replace('\\','/');
125 folder = folder.left(folder.indexOf('/'));
126
68 127 qSort(list.begin(), list.end());
128 FileOut file(m_out_dir + "/generated_cpp/" + pri.key());
129
130 // strange idea to do the file compacting so late, but it is the most effective way without patching the generator a lot
131 bool compact = true;
132 if (compact) {
133 list = compactFiles(list, ".h", m_out_dir + "/generated_cpp/" + folder, folder);
134 }
135
136 file.stream << "HEADERS += \\\n";
69 137 foreach (const QString &entry, list) {
70 file.stream << " $$PWD/" << entry << " \\\n";
138 file.stream << " $$PWD/" << entry << " \\\n";
71 139 }
72 140
73 141 file.stream << "\n";
74 142 file.stream << "SOURCES += \\\n";
75 143 list = pri.value().sources;
76 144 qSort(list.begin(), list.end());
145 if (compact) {
146 list = compactFiles(list, ".cpp", m_out_dir + "/generated_cpp/" + folder, folder);
147 }
77 148 foreach (const QString &entry, list) {
78 149 file.stream << " $$PWD/" << entry << " \\\n";
79 150 }
80 151 file.stream << " $$PWD/" << folder << "_init.cpp\n";
81 152
82 153 if (file.done())
83 154 ++m_num_generated_written;
84 155 ++m_num_generated;
85 156 }
86 157 }
@@ -1,233 +1,228
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 AbstractMetaClass *cls)
50 50 {
51 51 packHash[cls->package()].append(cls);
52 52 }
53 53
54 void writeQtScriptQtBindingsLicense(QTextStream &stream);
55
56 54 void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
57 55 QSet<QString> &registeredTypeNames);
58 56 bool hasDefaultConstructor(const AbstractMetaClass *meta_class);
59 57
60 58 void SetupGenerator::generate()
61 59 {
62 60 AbstractMetaClassList classes_with_polymorphic_id;
63 61 {
64 62 QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
65 63 while (pack.hasNext()) {
66 64 pack.next();
67 65 QList<const AbstractMetaClass*> list = pack.value();
68 66 foreach (const AbstractMetaClass *cls, list) {
69 67 if (cls->typeEntry()->isPolymorphicBase()) {
70 68 classes_with_polymorphic_id.append((AbstractMetaClass*)cls);
71 69 }
72 70 }
73 71 }
74 72 }
75 73
76 74 QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
77 75 while (pack.hasNext()) {
78 76 pack.next();
79 77 QList<const AbstractMetaClass*> list = pack.value();
80 78 if (list.isEmpty())
81 79 continue;
82 80
83 81 QString packKey = pack.key();
84 82 QString packName = pack.key();
85 83 QStringList components = packName.split(".");
86 84 if ((components.size() > 2) && (components.at(0) == "com")
87 85 && (components.at(1) == "trolltech")) {
88 86 // kill com.trolltech in key
89 87 components.removeAt(0);
90 88 components.removeAt(0);
91 89 }
92 90 packName.replace(".", "_");
93 91 packKey.replace(".", "_");
94 92
95 93 QString shortPackName;
96 94 foreach (QString comp, components) {
97 95 comp[0] = comp[0].toUpper();
98 96 shortPackName += comp;
99 97 }
100 98 // add missing camel case (workaround..)
101 99 if (shortPackName == "QtWebkit") {
102 100 shortPackName = "QtWebKit";
103 101 } else if (shortPackName == "QtXmlpatterns") {
104 102 shortPackName = "QtXmlPatterns";
105 103 } else if (shortPackName == "QtOpengl") {
106 104 shortPackName = "QtOpenGL";
107 105 } else if (shortPackName == "QtUitools") {
108 106 shortPackName = "QtUiTools";
109 107 }
110 108
111 109
112 110 {
113 111 FileOut initFile(m_out_dir + "/generated_cpp/" + packName + "/" + packKey + "_init.cpp");
114 112 QTextStream &s = initFile.stream;
115 113
116 if (FileOut::license)
117 writeQtScriptQtBindingsLicense(s);
118
119 114 s << "#include <PythonQt.h>" << endl;
120 115
121 foreach (const AbstractMetaClass *cls, list) {
122 s << "#include \"" << ShellGenerator::wrapperClassName(cls) << ".h\"" << endl;
116 for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) {
117 s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl;
123 118 }
124 119 s << endl;
125 120
126 121 QStringList polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id);
127 122 s << endl;
128 123
129 124 // declare individual class creation functions
130 125 s << "void PythonQt_init_" << shortPackName << "() {" << endl;
131 126 QStringList cppClassNames;
132 127 foreach (const AbstractMetaClass *cls, list) {
133 128 if (ShellGenerator::isBuiltIn(cls->name())) { continue; }
134 129
135 130 QString shellCreator;
136 131 if (cls->generateShellClass()) {
137 132 shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">";
138 133 }
139 134 if (cls->isQObject()) {
140 135 s << "PythonQt::self()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ");" << endl;
141 136 } else {
142 137 QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
143 138 s << "PythonQt::self()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ");" << endl;
144 139 }
145 140 foreach(AbstractMetaClass* interface, cls->interfaces()) {
146 141 // the interface might be our own class... (e.g. QPaintDevice)
147 142 if (interface->qualifiedCppName() != cls->qualifiedCppName()) {
148 143 s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<<interface->qualifiedCppName()<<">());" << endl;
149 144 }
150 145 }
151 146 }
152 147 s << endl;
153 148 foreach (QString handler, polymorphicHandlers) {
154 149 s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl;
155 150 }
156 151
157 152 s << "}";
158 153 s << endl;
159 154 }
160 155 }
161 156 }
162 157
163 158 QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package,
164 159 const AbstractMetaClassList &classes)
165 160 {
166 161 QStringList handlers;
167 162 foreach (AbstractMetaClass *cls, classes) {
168 163 const ComplexTypeEntry *centry = cls->typeEntry();
169 164 if (!centry->isPolymorphicBase())
170 165 continue;
171 166 bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem");
172 167
173 168 AbstractMetaClassList classList = this->classes();
174 169 bool first = true;
175 170 foreach (AbstractMetaClass *clazz, classList) {
176 171 bool inherits = false;
177 172 if (isGraphicsItem) {
178 173 foreach(AbstractMetaClass* interfaze, clazz->interfaces()) {
179 174 if (interfaze->qualifiedCppName()=="QGraphicsItem") {
180 175 inherits = true;
181 176 break;
182 177 }
183 178 }
184 179 } else {
185 180 inherits = clazz->inheritsFrom(cls);
186 181 }
187 182 if (clazz->package() == package && inherits) {
188 183 if (!clazz->typeEntry()->polymorphicIdValue().isEmpty() || isGraphicsItem) {
189 184 // On first find, open the function
190 185 if (first) {
191 186 first = false;
192 187
193 188 QString handler = cls->name();
194 189 handlers.append(handler);
195 190
196 191 s << "static void* polymorphichandler_" << handler
197 192 << "(const void *ptr, char **class_name)" << endl
198 193 << "{" << endl
199 194 << " Q_ASSERT(ptr != 0);" << endl
200 195 << " " << cls->qualifiedCppName() << " *object = ("
201 196 << cls->qualifiedCppName() << " *)ptr;" << endl;
202 197 }
203 198
204 199 // For each, add case label
205 200 QString polyId = clazz->typeEntry()->polymorphicIdValue();
206 201 if (isGraphicsItem) {
207 202 polyId = "%1->type() == " + clazz->qualifiedCppName() + "::Type";
208 203 }
209 204 s << " if ("
210 205 << polyId.replace("%1", "object")
211 206 << ") {" << endl
212 207 << " *class_name = \"" << clazz->name() << "\";" << endl
213 208 << " return (" << clazz->qualifiedCppName() << "*)object;" << endl
214 209 << " }" << endl;
215 210 } else {
216 211 QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set")
217 212 .arg(clazz->name())
218 213 .arg(cls->name());
219 214
220 215 ReportHandler::warning(warning);
221 216 }
222 217 }
223 218 }
224 219
225 220 // Close the function if it has been opened
226 221 if (!first) {
227 222 s << " return NULL;" << endl
228 223 << "}" << endl;
229 224 }
230 225 }
231 226
232 227 return handlers;
233 228 }
@@ -1,64 +1,68
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 SETUPGENERATOR_H
43 43 #define SETUPGENERATOR_H
44 44
45 45 #include "generator.h"
46 46 #include "metaqtscript.h"
47 47
48 48 class SetupGenerator : public Generator
49 49 {
50 50 Q_OBJECT
51 51
52 52 public:
53 53 virtual void generate();
54 54
55 55 void addClass(const AbstractMetaClass *cls);
56 56
57 static void writeInclude(QTextStream &stream, const Include &inc);
58
59 static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun);
60
57 61 private:
58 62 QStringList writePolymorphicHandler(QTextStream &s, const QString &package,
59 63 const AbstractMetaClassList &classes);
60 64
61 65 QHash<QString, QList<const AbstractMetaClass*> > packHash;
62 66 };
63 67 #endif // SETUPGENERATOR_H
64 68
@@ -1,374 +1,377
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 "shellgenerator.h"
43 43 #include "reporthandler.h"
44 44
45 45 #include "metaqtscript.h"
46 46
47 47 bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
48 48 {
49 49 uint cg = meta_class->typeEntry()->codeGeneration();
50 50 if (meta_class->name().startsWith("QtScript")) return false;
51 51 if (meta_class->name().startsWith("QFuture")) return false;
52 52 if (meta_class->name().startsWith("Global")) return false;
53 53 if (meta_class->name().startsWith("QStyleOptionComplex")) return false;
54 54 if (meta_class->name().startsWith("QTextLayout")) return false;
55 55 //if (meta_class->name().startsWith("QTextStream")) return false; // because of >> operators
56 56 //if (meta_class->name().startsWith("QDataStream")) return false; // "
57 57 return ((cg & TypeEntry::GenerateCode) != 0);
58 58 }
59 59
60 60 void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option options)
61 61 {
62 62 if ((options & OriginalTypeDescription) && !type->originalTypeDescription().isEmpty()) {
63 63 s << type->originalTypeDescription();
64 64 return;
65 65 }
66 66
67 67 if (type->isArray()) {
68 68 writeTypeInfo(s, type->arrayElementType(), options);
69 69 if (options & ArrayAsPointer) {
70 70 s << "*";
71 71 } else {
72 72 s << "[" << type->arrayElementCount() << "]";
73 73 }
74 74 return;
75 75 }
76 76
77 77 const TypeEntry *te = type->typeEntry();
78 78
79 79 if (type->isConstant() && !(options & ExcludeConst))
80 80 s << "const ";
81 81
82 82 if ((options & EnumAsInts) && (te->isEnum() || te->isFlags())) {
83 83 s << "int";
84 84 } else if (te->isFlags()) {
85 85 s << ((FlagsTypeEntry *) te)->originalName();
86 86 } else {
87 87 s << fixCppTypeName(te->qualifiedCppName());
88 88 }
89 89
90 90 if (type->instantiations().size() > 0
91 91 && (!type->isContainer()
92 92 || (static_cast<const ContainerTypeEntry *>(te))->type() != ContainerTypeEntry::StringListContainer)) {
93 93 s << '<';
94 94 QList<AbstractMetaType *> args = type->instantiations();
95 95 bool nested_template = false;
96 96 for (int i=0; i<args.size(); ++i) {
97 97 if (i != 0)
98 98 s << ", ";
99 99 nested_template |= args.at(i)->isContainer();
100 100 writeTypeInfo(s, args.at(i));
101 101 }
102 102 if (nested_template)
103 103 s << ' ';
104 104 s << '>';
105 105 }
106 106
107 107 s << QString(type->indirections(), '*');
108 108
109 109 if (type->isReference() && !(options & ExcludeReference) && !(options & ConvertReferenceToPtr))
110 110 s << "&";
111 111
112 112 if (type->isReference() && (options & ConvertReferenceToPtr)) {
113 113 s << "*";
114 114 }
115 115
116 116
117 117 if (!(options & SkipName))
118 118 s << ' ';
119 119 }
120 120
121 121
122 122 void ShellGenerator::writeFunctionArguments(QTextStream &s, const AbstractMetaClass* owner,
123 123 const AbstractMetaArgumentList &arguments,
124 124 Option option,
125 125 int numArguments)
126 126 {
127 127 if (numArguments < 0) numArguments = arguments.size();
128 128
129 129 for (int i=0; i<numArguments; ++i) {
130 130 if (i != 0)
131 131 s << ", ";
132 132 AbstractMetaArgument *arg = arguments.at(i);
133 133 writeTypeInfo(s, arg->type(), option);
134 134 if (!(option & SkipName))
135 135 s << " " << arg->argumentName();
136 136 if ((option & IncludeDefaultExpression) && !arg->originalDefaultValueExpression().isEmpty()) {
137 137 s << " = ";
138 138
139 139 QString expr = arg->originalDefaultValueExpression();
140 140 if (expr != "0") {
141 141 QString qualifier;
142 142 if (arg->type()->typeEntry()->isEnum() && expr.indexOf("::") < 0) {
143 143 qualifier = ((EnumTypeEntry *)arg->type()->typeEntry())->qualifier();
144 144 } else if (arg->type()->typeEntry()->isFlags() && expr.indexOf("::") < 0) {
145 145 qualifier = ((FlagsTypeEntry *)arg->type()->typeEntry())->originator()->qualifier();
146 146 }
147 147 if (!qualifier.isEmpty()) {
148 148 s << qualifier << "::";
149 149 }
150 150 }
151 151 if (expr.contains("defaultConnection")) {
152 152 expr.replace("defaultConnection","QSqlDatabase::defaultConnection");
153 153 }
154 154 if (expr == "MediaSource()") {
155 155 expr = "Phonon::MediaSource()";
156 156 }
157 157 s << expr;
158 158 }
159 159 }
160 160 }
161 161
162 162 /*!
163 163 * Writes the function \a meta_function signature to the textstream \a s.
164 164 *
165 165 * The \a name_prefix can be used to give the function name a prefix,
166 166 * like "__public_" or "__override_" and \a classname_prefix can
167 167 * be used to give the class name a prefix.
168 168 *
169 169 * The \a option flags can be used to tweak various parameters, such as
170 170 * showing static, original vs renamed name, underscores for space etc.
171 171 *
172 172 * The \a extra_arguments list is a list of extra arguments on the
173 173 * form "bool static_call".
174 174 */
175 175
176 176 void ShellGenerator::writeFunctionSignature(QTextStream &s,
177 177 const AbstractMetaFunction *meta_function,
178 178 const AbstractMetaClass *implementor,
179 179 const QString &name_prefix,
180 180 Option option,
181 181 const QString &classname_prefix,
182 182 const QStringList &extra_arguments,
183 183 int numArguments)
184 184 {
185 185 // ### remove the implementor
186 186 AbstractMetaType *function_type = meta_function->type();
187 187
188 188
189 189 if ((option & SkipReturnType) == 0) {
190 190 if (function_type) {
191 191 writeTypeInfo(s, function_type, option);
192 192 s << " ";
193 193 } else if (!meta_function->isConstructor()) {
194 194 s << "void ";
195 195 }
196 196 }
197 197
198 198 if (implementor) {
199 199 if (classname_prefix.isEmpty())
200 200 s << wrapperClassName(implementor) << "::";
201 201 else
202 202 s << classname_prefix << implementor->name() << "::";
203 203 }
204 204
205 205
206 206 QString function_name;
207 207 if (option & OriginalName)
208 208 function_name = meta_function->originalName();
209 209 else
210 210 function_name = meta_function->name();
211 211
212 212 if (option & UnderscoreSpaces)
213 213 function_name = function_name.replace(' ', '_');
214 214
215 215 if (meta_function->isConstructor())
216 216 function_name = meta_function->ownerClass()->name();
217 217
218 218 if (meta_function->isStatic() && (option & ShowStatic)) {
219 219 function_name = "static_" + meta_function->ownerClass()->name() + "_" + function_name;
220 220 }
221 221
222 222 if (function_name.startsWith("operator")) {
223 223 function_name = meta_function->name();
224 224 }
225 225
226 226 s << name_prefix << function_name;
227 227
228 228 if (meta_function->attributes() & AbstractMetaAttributes::SetterFunction)
229 229 s << "_setter";
230 230 else if (meta_function->attributes() & AbstractMetaAttributes::GetterFunction)
231 231 s << "_getter";
232 232
233 233 s << "(";
234 234
235 235 if ((option & FirstArgIsWrappedObject) && meta_function->ownerClass() && !meta_function->isConstructor() && !meta_function->isStatic()) {
236 236 s << meta_function->ownerClass()->qualifiedCppName() << "* theWrappedObject";
237 237 if (meta_function->arguments().size() != 0) {
238 238 s << ", ";
239 239 }
240 240 }
241 241
242 242 writeFunctionArguments(s, meta_function->ownerClass(), meta_function->arguments(), Option(option & Option(~ConvertReferenceToPtr)), numArguments);
243 243
244 244 // The extra arguments...
245 245 for (int i=0; i<extra_arguments.size(); ++i) {
246 246 if (i > 0 || meta_function->arguments().size() != 0)
247 247 s << ", ";
248 248 s << extra_arguments.at(i);
249 249 }
250 250
251 251 s << ")";
252 252 if (meta_function->isConstant())
253 253 s << " const";
254 254 }
255 255
256 256 AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaClass* meta_class)
257 257 {
258 258 AbstractMetaFunctionList functions = meta_class->queryFunctions(
259 259 AbstractMetaClass::NormalFunctions | AbstractMetaClass::WasPublic
260 260 | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
261 261 );
262 262 AbstractMetaFunctionList functions2 = meta_class->queryFunctions(
263 263 AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
264 264 | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
265 265 );
266 266 QSet<AbstractMetaFunction*> set1 = QSet<AbstractMetaFunction*>::fromList(functions);
267 267 foreach(AbstractMetaFunction* func, functions2) {
268 268 set1.insert(func);
269 269 }
270 270
271 271 AbstractMetaFunctionList resultFunctions;
272 272
273 273 foreach(AbstractMetaFunction* func, set1.toList()) {
274 274 if (!func->isAbstract() && func->implementingClass()==meta_class) {
275 275 resultFunctions << func;
276 276 }
277 277 }
278 278 return resultFunctions;
279 279 }
280 280
281 281 AbstractMetaFunctionList ShellGenerator::getVirtualFunctionsForShell(const AbstractMetaClass* meta_class)
282 282 {
283 283 AbstractMetaFunctionList functions = meta_class->queryFunctions(
284 284 AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
285 285 // | AbstractMetaClass::NotRemovedFromTargetLang
286 286 );
287 287 return functions;
288 288 }
289 289
290 290 AbstractMetaFunctionList ShellGenerator::getProtectedFunctionsThatNeedPromotion(const AbstractMetaClass* meta_class)
291 291 {
292 292 AbstractMetaFunctionList functions;
293 293 AbstractMetaFunctionList functions1 = getFunctionsToWrap(meta_class);
294 294 foreach(AbstractMetaFunction* func, functions1) {
295 295 if (!func->isPublic() || func->isVirtual()) {
296 296 functions << func;
297 297 }
298 298 }
299 299 return functions;
300 300 }
301 301
302 302 /*!
303 303 Writes the include defined by \a inc to \a stream.
304 304 */
305 305 void ShellGenerator::writeInclude(QTextStream &stream, const Include &inc)
306 306 {
307 307 if (inc.name.isEmpty())
308 308 return;
309 309 if (inc.type == Include::TargetLangImport)
310 310 return;
311 311 stream << "#include ";
312 312 if (inc.type == Include::IncludePath)
313 313 stream << "<";
314 314 else
315 315 stream << "\"";
316 316 stream << inc.name;
317 317 if (inc.type == Include::IncludePath)
318 318 stream << ">";
319 319 else
320 320 stream << "\"";
321 321 stream << endl;
322 322 }
323 323
324 324 /*!
325 325 Returns true if the given function \a fun is operator>>() or
326 326 operator<<() that streams from/to a Q{Data,Text}Stream, false
327 327 otherwise.
328 328 */
329 329 bool ShellGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun)
330 330 {
331 331 return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction)
332 332 && (fun->arguments().size() == 1)
333 333 && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom"))
334 334 || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo"))));
335 335 }
336 336
337 337 bool ShellGenerator::isBuiltIn(const QString& name) {
338 338
339 339 static QSet<QString> builtIn;
340 340 if (builtIn.isEmpty()) {
341 341 builtIn.insert("Qt");
342 342 builtIn.insert("QFont");
343 343 builtIn.insert("QPixmap");
344 344 builtIn.insert("QBrush");
345 builtIn.insert("QBitArray");
345 346 builtIn.insert("QPalette");
347 builtIn.insert("QPen");
346 348 builtIn.insert("QIcon");
347 349 builtIn.insert("QImage");
348 350 builtIn.insert("QPolygon");
349 351 builtIn.insert("QRegion");
350 352 builtIn.insert("QBitmap");
351 353 builtIn.insert("QCursor");
352 354 builtIn.insert("QColor");
353 355 builtIn.insert("QSizePolicy");
354 356 builtIn.insert("QKeySequence");
355 357 builtIn.insert("QTextLength");
356 358 builtIn.insert("QTextFormat");
357 359 builtIn.insert("QMatrix");
358 360 builtIn.insert("QDate");
359 361 builtIn.insert("QTime");
360 362 builtIn.insert("QDateTime");
361 363 builtIn.insert("QUrl");
362 364 builtIn.insert("QLocale");
363 365 builtIn.insert("QRect");
364 366 builtIn.insert("QRectF");
365 367 builtIn.insert("QSize");
366 368 builtIn.insert("QSizeF");
367 369 builtIn.insert("QLine");
368 370 builtIn.insert("QLineF");
369 371 builtIn.insert("QPoint");
370 372 builtIn.insert("QPointF");
371 373 builtIn.insert("QRegExp");
372 374 }
373 375 return builtIn.contains(name);
374 376 }
377
@@ -1,100 +1,102
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 SHELLGENERATOR_H
43 43 #define SHELLGENERATOR_H
44 44
45 45 #include "generator.h"
46 46 #include "metaqtscript.h"
47 47 #include "prigenerator.h"
48 48
49 #define MAX_CLASSES_PER_FILE 20
50
49 51 class ShellGenerator : public Generator
50 52 {
51 53 Q_OBJECT
52 54
53 55 public:
54 56 virtual QString subDirectoryForClass(const AbstractMetaClass *cls) const
55 57 {
56 58 return "generated_cpp/" + cls->package().replace(".", "_") + "/";
57 59 }
58 60
59 61 static void writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option option = NoOption);
60 62 static void writeFunctionSignature(QTextStream &s, const AbstractMetaFunction *meta_function,
61 63 const AbstractMetaClass *implementor = 0,
62 64 const QString &name_prefix = QString(),
63 65 Option option = NoOption,
64 66 const QString &classname_prefix = QString(),
65 67 const QStringList &extra_arguments = QStringList(),
66 68 int numArguments = -1);
67 69 static void writeFunctionArguments(QTextStream &s, const AbstractMetaClass* owner, const AbstractMetaArgumentList &arguments,
68 70 Option option = NoOption,
69 71 int numArguments = -1);
70 72
71 73 bool shouldGenerate(const AbstractMetaClass *meta_class) const;
72 74
73 75 static QString shellClassName(const AbstractMetaClass *meta_class) {
74 76 return "PythonQtShell_" + meta_class->name();
75 77 }
76 78 static QString wrapperClassName(const AbstractMetaClass *meta_class) {
77 79 return "PythonQtWrapper_" + meta_class->name();
78 80 }
79 81 static QString promoterClassName(const AbstractMetaClass *meta_class) {
80 82 return "PythonQtPublicPromoter_" + meta_class->name();
81 83 }
82 84
83 85 static AbstractMetaFunctionList getFunctionsToWrap(const AbstractMetaClass* cls);
84 86 static AbstractMetaFunctionList getVirtualFunctionsForShell(const AbstractMetaClass* cls);
85 87 static AbstractMetaFunctionList getProtectedFunctionsThatNeedPromotion(const AbstractMetaClass* cls);
86 88
87 89 // PythonQt builtins..., dont put them in pri files and dont register them, but generate the code
88 90 static bool isBuiltIn(const QString& name);
89 91
90 92 static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun);
91
93
92 94 static void writeInclude(QTextStream &stream, const Include &inc);
93 95
94 96 protected:
95 97 PriGenerator *priGenerator;
96 98
97 99 };
98 100
99 101
100 102 #endif // SHELLGENERATOR_H
@@ -1,293 +1,289
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 void writeQtScriptQtBindingsLicense(QTextStream &stream);
55
56 54 void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
57 55 {
58
59 setupGenerator->addClass(meta_class);
60
61 if (FileOut::license)
62 writeQtScriptQtBindingsLicense(s);
56 if (!ShellGenerator::isBuiltIn(meta_class->name())) {
57 setupGenerator->addClass(meta_class);
58 }
63 59
64 60 QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H";
65 61
66 62 s << "#ifndef " << include_block << endl
67 63 << "#define " << include_block << endl << endl;
68 64
69 65 Include inc = meta_class->typeEntry()->include();
70 66 ShellGenerator::writeInclude(s, inc);
71 67
72 68 s << "#include <QObject>" << endl << endl;
73 69 s << "#include <PythonQt.h>" << endl << endl;
74 70
75 71 IncludeList list = meta_class->typeEntry()->extraIncludes();
76 72 qSort(list.begin(), list.end());
77 73 foreach (const Include &inc, list) {
78 74 ShellGenerator::writeInclude(s, inc);
79 75 }
80 76 s << endl;
81 77
82 78 QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri";
83 79
84 80 // if (!meta_class->generateShellClass()) {
85 81 // s << "#endif" << endl << endl;
86 82 // priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
87 83 // return ;
88 84 // }
89 85
90 86 AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
91 87 | AbstractMetaClass::WasVisible
92 88 | AbstractMetaClass::NotRemovedFromTargetLang);
93 89
94 90 // Shell-------------------------------------------------------------------
95 91 if (meta_class->generateShellClass()) {
96 92
97 93 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
98 94
99 95 s << "class " << shellClassName(meta_class)
100 96 << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl;
101 97 s << "public:" << endl;
102 98 foreach(AbstractMetaFunction* fun, ctors) {
103 99 s << " ";
104 100 writeFunctionSignature(s, fun, 0,"PythonQtShell_",
105 101 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
106 102 s << ":" << meta_class->qualifiedCppName() << "(";
107 103 QString scriptFunctionName = fun->originalName();
108 104 AbstractMetaArgumentList args = fun->arguments();
109 105 for (int i = 0; i < args.size(); ++i) {
110 106 if (i > 0)
111 107 s << ", ";
112 108 s << args.at(i)->argumentName();
113 109 }
114 110 s << "),_wrapper(NULL) {};" << endl;
115 111 }
116 112 s << endl;
117 113
118 114 foreach(AbstractMetaFunction* fun, virtualsForShell) {
119 115 s << "virtual ";
120 116 writeFunctionSignature(s, fun, 0, QString(),
121 117 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
122 118 s << ";" << endl;
123 119 }
124 120 s << endl;
125 121 s << " PythonQtInstanceWrapper* _wrapper; " << endl;
126 122
127 123 s << "};" << endl << endl;
128 124 }
129 125
130 126 // Promoter-------------------------------------------------------------------
131 127 AbstractMetaFunctionList promoteFunctions = getProtectedFunctionsThatNeedPromotion(meta_class);
132 128 if (!promoteFunctions.isEmpty()) {
133 129 s << "class " << promoterClassName(meta_class)
134 130 << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl;
135 131
136 132 foreach(AbstractMetaFunction* fun, promoteFunctions) {
137 133 s << "inline ";
138 134 writeFunctionSignature(s, fun, 0, "promoted_",
139 135 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
140 136 s << " { ";
141 137 QString scriptFunctionName = fun->originalName();
142 138 AbstractMetaArgumentList args = fun->arguments();
143 139 if (fun->type())
144 140 s << "return ";
145 141 s << meta_class->qualifiedCppName() << "::";
146 142 s << fun->originalName() << "(";
147 143 for (int i = 0; i < args.size(); ++i) {
148 144 if (i > 0)
149 145 s << ", ";
150 146 s << args.at(i)->argumentName();
151 147 }
152 148 s << "); }" << endl;
153 149 }
154 150
155 151 s << "};" << endl << endl;
156 152 }
157 153
158 154 // Wrapper-------------------------------------------------------------------
159 155
160 156 s << "class " << wrapperClassName(meta_class)
161 157 << " : public QObject" << endl
162 158 << "{ Q_OBJECT" << endl;
163 159
164 160 s << "public:" << endl;
165 161
166 162 AbstractMetaEnumList enums1 = meta_class->enums();
167 163 AbstractMetaEnumList enums;
168 164 QList<FlagsTypeEntry*> flags;
169 165 foreach(AbstractMetaEnum* enum1, enums1) {
170 166 // catch gadgets and enums that are not exported on QObjects...
171 167 if (enum1->wasPublic() && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration())) {
172 168 enums << enum1;
173 169 if (enum1->typeEntry()->flags()) {
174 170 flags << enum1->typeEntry()->flags();
175 171 }
176 172 }
177 173 }
178 174 if (enums.count()) {
179 175 s << "Q_ENUMS(";
180 176 foreach(AbstractMetaEnum* enum1, enums) {
181 177 s << enum1->name() << " ";
182 178 }
183 179 s << ")" << endl;
184 180
185 181 if (flags.count()) {
186 182 s << "Q_FLAGS(";
187 183 foreach(FlagsTypeEntry* flag1, flags) {
188 184 QString origName = flag1->originalName();
189 185 int idx = origName.lastIndexOf("::");
190 186 if (idx!= -1) {
191 187 origName = origName.mid(idx+2);
192 188 }
193 189 s << origName << " ";
194 190 }
195 191 s << ")" << endl;
196 192 }
197 193
198 194 foreach(AbstractMetaEnum* enum1, enums) {
199 195 s << "enum " << enum1->name() << "{" << endl;
200 196 bool first = true;
201 197 foreach(AbstractMetaEnumValue* value, enum1->values()) {
202 198 if (first) { first = false; }
203 199 else { s << ", "; }
204 200 s << " " << value->name() << " = " << meta_class->qualifiedCppName() << "::" << value->name();
205 201 }
206 202 s << "};" << endl;
207 203 }
208 204 if (flags.count()) {
209 205 foreach(AbstractMetaEnum* enum1, enums) {
210 206 if (enum1->typeEntry()->flags()) {
211 207 QString origName = enum1->typeEntry()->flags()->originalName();
212 208 int idx = origName.lastIndexOf("::");
213 209 if (idx!= -1) {
214 210 origName = origName.mid(idx+2);
215 211 }
216 212 s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<<endl;
217 213 }
218 214 }
219 215 }
220 216 }
221 217 s << "public slots:" << endl;
222 218 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
223 219
224 220 bool copyConstructorSeen = false;
225 221 bool defaultConstructorSeen = false;
226 222 foreach (const AbstractMetaFunction *fun, ctors) {
227 223 if (!fun->isPublic() || fun->isAbstract()) { continue; }
228 224 s << meta_class->qualifiedCppName() << "* ";
229 225 writeFunctionSignature(s, fun, 0, "new_",
230 226 Option(IncludeDefaultExpression | OriginalName | ShowStatic));
231 227 s << ";" << endl;
232 228 if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) {
233 229 copyConstructorSeen = true;
234 230 }
235 231 if (fun->arguments().size()==0) {
236 232 defaultConstructorSeen = true;
237 233 }
238 234 }
239 235
240 236 if (meta_class->typeEntry()->isValue()
241 237 && !copyConstructorSeen && defaultConstructorSeen) {
242 238 QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName();
243 239 s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl;
244 240 s << className << "* a = new " << className << "();" << endl;
245 241 s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl;
246 242 s << "return a; }" << endl;
247 243 }
248 244 }
249 245 if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) {
250 246 s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } ";
251 247 s << endl;
252 248 }
253 249 if (meta_class->name()=="QTreeWidgetItem") {
254 250 s << "bool hasOwner(QTreeWidgetItem* theWrappedObject) { return theWrappedObject->treeWidget()!=NULL || theWrappedObject->parent()!=NULL; }" << endl;
255 251 } else if (meta_class->name()=="QGraphicsItem") {
256 252 s << "bool hasOwner(QGraphicsItem* theWrappedObject) { return theWrappedObject->scene()!=NULL || theWrappedObject->parentItem()!=NULL; }" << endl;
257 253 }
258 254
259 255 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
260 256
261 257 foreach (const AbstractMetaFunction *function, functions) {
262 258 if (!function->isSlot()) {
263 259 s << " ";
264 260 writeFunctionSignature(s, function, 0, QString(),
265 261 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
266 262 s << ";" << endl;
267 263 }
268 264 }
269 265 if (!meta_class->hasDefaultToStringFunction() && meta_class->hasToStringCapability()) {
270 266 s << " QString toString(" << meta_class->qualifiedCppName() << "*);" << endl;
271 267 }
272 268
273 269 // writeInjectedCode(s, meta_class);
274 270
275 271 // s << endl << " QScriptValue __qtscript_self;" << endl;
276 272
277 273 s << "};" << endl << endl
278 274 << "#endif // " << include_block << endl;
279 275
280 276 if (!ShellGenerator::isBuiltIn(meta_class->name())) {
281 277 priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
282 278 }
283 279 }
284 280
285 281 void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
286 282 {
287 283 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
288 284 foreach (const CodeSnip &cs, code_snips) {
289 285 if (cs.language == TypeSystem::ShellDeclaration) {
290 286 s << cs.code() << endl;
291 287 }
292 288 }
293 289 }
@@ -1,313 +1,309
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 "shellimplgenerator.h"
43 43 #include "reporthandler.h"
44 44 #include "fileout.h"
45 45
46 46 extern void declareFunctionMetaTypes(QTextStream &stream,
47 47 const AbstractMetaFunctionList &functions,
48 48 QSet<QString> &registeredTypeNames);
49 49
50 50 QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
51 51 {
52 52 return QString("PythonQtWrapper_%1.cpp").arg(meta_class->name());
53 53 }
54 54
55 55 static bool include_less_than(const Include &a, const Include &b)
56 56 {
57 57 return a.name < b.name;
58 58 }
59 59
60 60 static void writeHelperCode(QTextStream &s, const AbstractMetaClass *)
61 61 {
62 62 }
63 63
64 void writeQtScriptQtBindingsLicense(QTextStream &stream);
65
66 64 void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
67 65 {
68 if (FileOut::license)
69 writeQtScriptQtBindingsLicense(s);
70 66
71 67 QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri";
72 68
73 69 if (!ShellGenerator::isBuiltIn(meta_class->name())) {
74 70 priGenerator->addSource(pro_file_name, fileNameForClass(meta_class));
75 71 }
76 72
77 73 s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl;
78 74
79 75 s << "#include <PythonQtSignalReceiver.h>" << endl;
80 76 s << "#include <PythonQtMethodInfo.h>" << endl;
81 77 s << "#include <PythonQtConversion.h>" << endl;
82 78
83 79 //if (!meta_class->generateShellClass())
84 80 // return;
85 81
86 82 IncludeList list = meta_class->typeEntry()->extraIncludes();
87 83 qSort(list.begin(), list.end());
88 84 foreach (const Include &inc, list) {
89 85 ShellGenerator::writeInclude(s, inc);
90 86 }
91 87 s << endl;
92 88
93 89 writeHelperCode(s, meta_class);
94 90
95 91 // find constructors
96 92 AbstractMetaFunctionList ctors;
97 93 ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
98 94 | AbstractMetaClass::WasVisible
99 95 | AbstractMetaClass::NotRemovedFromTargetLang);
100 96 // find member functions
101 97 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
102 98
103 99 // write metatype declarations
104 100 {
105 101 // QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
106 102 // declareFunctionMetaTypes(s, functions, registeredTypeNames);
107 103 // s << endl;
108 104 }
109 105
110 106 if (meta_class->generateShellClass()) {
111 107 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
112 108 foreach (const AbstractMetaFunction *fun, virtualsForShell) {
113 109 bool hasReturnValue = (fun->type());
114 110 writeFunctionSignature(s, fun, meta_class, QString(),
115 111 Option(OriginalName | ShowStatic | UnderscoreSpaces),
116 112 "PythonQtShell_");
117 113 s << endl << "{" << endl;
118 114
119 115 Option typeOptions = Option(OriginalName | UnderscoreSpaces | SkipName);
120 116 AbstractMetaArgumentList args = fun->arguments();
121 117
122 118 s << "if (_wrapper) {" << endl;
123 119 s << " PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, \"" << fun->name() << "\");" << endl;
124 120 s << " PyErr_Clear();" << endl;
125 121 s << " if (obj && !PythonQtSlotFunction_Check(obj)) {" << endl;
126 122 s << " static const char* argumentList[] ={\"";
127 123 if (hasReturnValue) {
128 124 // write the arguments, return type first
129 125 writeTypeInfo(s, fun->type(), typeOptions);
130 126 }
131 127 s << "\"";
132 128 for (int i = 0; i < args.size(); ++i) {
133 129 s << " , \"";
134 130 writeTypeInfo(s, args.at(i)->type(), typeOptions);
135 131 s << "\"";
136 132 }
137 133 s << "};" << endl;
138 134 s << " static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(" << QString::number(args.size()+1) << ", argumentList);" << endl;
139 135
140 136 if (hasReturnValue) {
141 137 s << " ";
142 138 writeTypeInfo(s, fun->type(), typeOptions);
143 139 s << " returnValue;" << endl;
144 140 // TODO: POD init to default is missing...
145 141 }
146 142 s << " void* args[" << QString::number(args.size()+1) << "] = {NULL";
147 143 for (int i = 0; i < args.size(); ++i) {
148 144 s << ", (void*)&" << args.at(i)->argumentName();
149 145 }
150 146 s << "};" << endl;
151 147
152 148 s << " PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);" << endl;
153 149 if (hasReturnValue) {
154 150 s << " if (result) {" << endl;
155 151 s << " args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);" << endl;
156 152 s << " if (args[0]!=&returnValue) {" << endl;
157 153 s << " if (args[0]==NULL) {" << endl;
158 154 s << " PythonQt::priv()->handleVirtualOverloadReturnError(\"" << fun->name() << "\", methodInfo, result);" << endl;
159 155 s << " } else {" << endl;
160 156 s << " returnValue = *((";
161 157 writeTypeInfo(s, fun->type(), typeOptions);
162 158 s << "*)args[0]);" << endl;
163 159 s << " }" << endl;
164 160 s << " }" << endl;
165 161 s << " }" << endl;
166 162 }
167 163 s << " if (result) { Py_DECREF(result); } " << endl;
168 164 s << " Py_DECREF(obj);" << endl;
169 165 if (hasReturnValue) {
170 166 s << " return returnValue;" << endl;
171 167 } else {
172 168 s << " return;" << endl;
173 169 }
174 170 s << " }" << endl;
175 171 s << "}" << endl;
176 172
177 173 s << " ";
178 174 if (fun->isAbstract()) {
179 175 if (fun->type()) {
180 176 // return empty default object
181 177 writeTypeInfo(s, fun->type(), typeOptions);
182 178 s << " result;" << endl;
183 179 s << "return result";
184 180 s << ";";
185 181 }
186 182 } else {
187 183 if (fun->type()) {
188 184 s << "return ";
189 185 }
190 186 s << meta_class->qualifiedCppName() << "::";
191 187 s << fun->originalName() << "(";
192 188 for (int i = 0; i < args.size(); ++i) {
193 189 if (i > 0)
194 190 s << ", ";
195 191 s << args.at(i)->argumentName();
196 192 }
197 193 s << ");";
198 194 }
199 195 s << endl << "}" << endl;
200 196 }
201 197 }
202 198
203 199 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
204 200
205 201 // write constructors
206 202 foreach (const AbstractMetaFunction *ctor, ctors) {
207 203 if (!ctor->isPublic() || ctor->isAbstract()) { continue; }
208 204
209 205 s << meta_class->qualifiedCppName() << "* ";
210 206 s << "PythonQtWrapper_" << meta_class->name() << "::";
211 207 writeFunctionSignature(s, ctor, 0, "new_", Option(OriginalName | ShowStatic));
212 208 s << endl;
213 209 s << "{ " << endl;
214 210 s << "return new " << (meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName()) << "(";
215 211 AbstractMetaArgumentList args = ctor->arguments();
216 212 for (int i = 0; i < args.size(); ++i) {
217 213 if (i > 0)
218 214 s << ", ";
219 215 s << args.at(i)->argumentName();
220 216 }
221 217 s << ");" << " }" << endl << endl;
222 218 }
223 219 }
224 220
225 221 QString wrappedObject = " (*theWrappedObject)";
226 222
227 223 // write member functions
228 224 for (int i = 0; i < functions.size(); ++i) {
229 225 AbstractMetaFunction *fun = functions.at(i);
230 226 if (fun->isSlot()) continue;
231 227
232 228 writeFunctionSignature(s, fun, meta_class, QString(),
233 229 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | OriginalName | ShowStatic | UnderscoreSpaces),
234 230 "PythonQtWrapper_");
235 231 s << endl << "{" << endl;
236 232 s << " ";
237 233 if (ShellGenerator::isSpecialStreamingOperator(fun)) {
238 234 s << fun->arguments().at(0)->argumentName();
239 235 if (fun->originalName().startsWith("operator>>")) {
240 236 s << " >> ";
241 237 } else {
242 238 s << " << ";
243 239 }
244 240 s << wrappedObject;
245 241 } else {
246 242 QString scriptFunctionName = fun->originalName();
247 243 AbstractMetaArgumentList args = fun->arguments();
248 244 // call the C++ implementation
249 245 if (fun->type()) {
250 246 s << "return ";
251 247 // call the C++ implementation
252 248 if (fun->type()->isReference()) {
253 249 s << "&";
254 250 }
255 251 }
256 252 s << "(";
257 253 if (scriptFunctionName.startsWith("operator>>")) {
258 254 s << wrappedObject << " >>" << args.at(0)->argumentName();
259 255 } else if (scriptFunctionName.startsWith("operator<<")) {
260 256 s << wrappedObject << " <<" << args.at(0)->argumentName();
261 257 } else if (scriptFunctionName.startsWith("operator[]")) {
262 258 s << wrappedObject << "[" << args.at(0)->argumentName() << "]";
263 259 } else if (scriptFunctionName.startsWith("operator") && args.size()==1) {
264 260 QString op = scriptFunctionName.mid(8);
265 261 s << wrappedObject << op << " " << args.at(0)->argumentName();
266 262 } else {
267 263 if (fun->isStatic()) {
268 264 s << meta_class->qualifiedCppName() << "::";
269 265 } else {
270 266 if (!fun->isPublic() || fun->isVirtual()) {
271 267 s << " ((" << promoterClassName(meta_class) << "*)theWrappedObject)->promoted_";
272 268 } else {
273 269 s << " theWrappedObject->";
274 270 }
275 271 }
276 272 s << fun->originalName() << "(";
277 273 for (int i = 0; i < args.size(); ++i) {
278 274 if (i > 0)
279 275 s << ", ";
280 276 s << args.at(i)->argumentName();
281 277 }
282 278 s << ")";
283 279 }
284 280 s << ")";
285 281 }
286 282 s << ";" << endl;
287 283
288 284 s << "}" << endl << endl;
289 285 }
290 286
291 287 if (!meta_class->hasDefaultToStringFunction() && meta_class->hasToStringCapability()) {
292 288 FunctionModelItem fun = meta_class->hasToStringCapability();
293 289 int indirections = fun->arguments().at(1)->type().indirections();
294 290 QString deref = QLatin1String(indirections == 0 ? "*" : "");
295 291 s << "QString PythonQtWrapper_" << meta_class->name() << "::toString(" << meta_class->qualifiedCppName() << "* obj) {" << endl;
296 292 s << " QString result;" << endl;
297 293 s << " QDebug d(&result);" << endl;
298 294 s << " d << " << deref << "obj;" << endl;
299 295 s << " return result;" << endl;
300 296 s << "}" << endl << endl;
301 297 }
302 298
303 299 }
304 300
305 301 void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
306 302 {
307 303 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
308 304 foreach (const CodeSnip &cs, code_snips) {
309 305 if (cs.language == TypeSystem::ShellCode) {
310 306 s << cs.code() << endl;
311 307 }
312 308 }
313 309 }
General Comments 0
You need to be logged in to leave comments. Login now