Mercurial > projects > qtd
comparison generator/metainfogenerator.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 1349940724eb |
comparison
equal
deleted
inserted
replaced
0:36fb74dc547d | 1:e78566595089 |
---|---|
1 /**************************************************************************** | |
2 ** | |
3 ** Copyright (C) 1992-2008 Nokia. All rights reserved. | |
4 ** | |
5 ** This file is part of Qt Jambi. | |
6 ** | |
7 ** * Commercial Usage | |
8 * Licensees holding valid Qt Commercial licenses may use this file in | |
9 * accordance with the Qt Commercial License Agreement provided with the | |
10 * Software or, alternatively, in accordance with the terms contained in | |
11 * a written agreement between you and Nokia. | |
12 * | |
13 * | |
14 * GNU General Public License Usage | |
15 * Alternatively, this file may be used under the terms of the GNU | |
16 * General Public License versions 2.0 or 3.0 as published by the Free | |
17 * Software Foundation and appearing in the file LICENSE.GPL included in | |
18 * the packaging of this file. Please review the following information | |
19 * to ensure GNU General Public Licensing requirements will be met: | |
20 * http://www.fsf.org/licensing/licenses/info/GPLv2.html and | |
21 * http://www.gnu.org/copyleft/gpl.html. In addition, as a special | |
22 * exception, Nokia gives you certain additional rights. These rights | |
23 * are described in the Nokia Qt GPL Exception version 1.2, included in | |
24 * the file GPL_EXCEPTION.txt in this package. | |
25 * | |
26 * Qt for Windows(R) Licensees | |
27 * As a special exception, Nokia, as the sole copyright holder for Qt | |
28 * Designer, grants users of the Qt/Eclipse Integration plug-in the | |
29 * right for the Qt/Eclipse Integration to link to functionality | |
30 * provided by Qt Designer and its related libraries. | |
31 * | |
32 * | |
33 * If you are unsure which license is appropriate for your use, please | |
34 * contact the sales department at qt-sales@nokia.com. | |
35 | |
36 ** | |
37 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | |
38 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
39 ** | |
40 ****************************************************************************/ | |
41 | |
42 #include "metainfogenerator.h" | |
43 #include "reporthandler.h" | |
44 #include "cppimplgenerator.h" | |
45 #include "fileout.h" | |
46 | |
47 #include <QDir> | |
48 #include <QMetaType> | |
49 | |
50 MetaInfoGenerator::MetaInfoGenerator(PriGenerator *pri): | |
51 DGenerator(), | |
52 priGenerator(pri) | |
53 | |
54 { | |
55 setFilenameStub("metainfo"); | |
56 } | |
57 | |
58 QString MetaInfoGenerator::subDirectoryForPackage(const QString &package, OutputDirectoryType type) const | |
59 { | |
60 switch (type) { | |
61 case CppDirectory: | |
62 return "cpp/" + QString(package).replace(".", "_") + "/"; | |
63 case JavaDirectory: | |
64 return QString(package).replace(".", "/"); | |
65 default: | |
66 return QString(); // kill nonsense warnings | |
67 } | |
68 } | |
69 | |
70 QString MetaInfoGenerator::subDirectoryForClass(const AbstractMetaClass *cls, OutputDirectoryType type) const | |
71 { | |
72 Q_ASSERT(cls); | |
73 return subDirectoryForPackage(cls->package(), type); | |
74 } | |
75 | |
76 void MetaInfoGenerator::generate() | |
77 { | |
78 buildSkipList(); | |
79 writeCppFile(); | |
80 writeHeaderFile(); | |
81 writeLibraryInitializers(); | |
82 } | |
83 | |
84 bool MetaInfoGenerator::shouldGenerate(const TypeEntry *entry) const | |
85 { | |
86 return entry != 0 && !entry->isNamespace() && !entry->isEnum() && (entry->codeGeneration() & TypeEntry::GenerateCpp); | |
87 } | |
88 | |
89 bool MetaInfoGenerator::shouldGenerate(const AbstractMetaClass *cls) const | |
90 { | |
91 return (!cls->isInterface() && cls->typeEntry()->isValue() && !cls->isNamespace() | |
92 && !cls->isAbstract() && (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateCpp)); | |
93 } | |
94 | |
95 QString MetaInfoGenerator::fileNameForClass(const AbstractMetaClass *) const | |
96 { | |
97 return filenameStub() + ".cpp"; | |
98 } | |
99 | |
100 void MetaInfoGenerator::write(QTextStream &, const AbstractMetaClass *) | |
101 { | |
102 // not used | |
103 } | |
104 | |
105 bool MetaInfoGenerator::generated(const AbstractMetaClass *cls) const | |
106 { | |
107 return generatedMetaInfo(cls->package()); | |
108 } | |
109 | |
110 bool MetaInfoGenerator::generatedMetaInfo(const QString &package) const | |
111 { | |
112 return (m_skip_list.value(package, 0x0) & GeneratedMetaInfo); | |
113 } | |
114 | |
115 bool MetaInfoGenerator::generatedJavaClasses(const QString &package) const | |
116 { | |
117 return (m_skip_list.value(package, 0x0) & GeneratedJavaClasses); | |
118 } | |
119 | |
120 static void metainfo_write_name_list(QTextStream &s, const char *var_name, const QList<QString> &strs, | |
121 int offset, int skip) | |
122 { | |
123 s << "static const char *" << var_name << "[] = {" << endl; | |
124 for (int i=offset; i<strs.size(); i += skip) { | |
125 s << " \"" << strs.at(i).toLatin1() << "\""; | |
126 if (i < strs.size() - 1) | |
127 s << ","; | |
128 s << endl; | |
129 } | |
130 s << "};" << endl << endl; | |
131 } | |
132 | |
133 void MetaInfoGenerator::writeEnums(QTextStream &s, const QString &package) | |
134 { | |
135 TypeEntryHash entries = TypeDatabase::instance()->allEntries(); | |
136 TypeEntryHash::iterator it; | |
137 | |
138 QList<QString> strs; | |
139 for (it=entries.begin(); it!=entries.end(); ++it) { | |
140 QList<TypeEntry *> entries = it.value(); | |
141 foreach (TypeEntry *entry, entries) { | |
142 if ((entry->isFlags() || entry->isEnum()) && entry->javaPackage() == package) { | |
143 EnumTypeEntry *eentry = entry->isEnum() ? static_cast<EnumTypeEntry *>(entry) : static_cast<FlagsTypeEntry *>(entry)->originator(); | |
144 | |
145 // The Qt flags names should map to the enum names, this is | |
146 // required for the designer plugin to find the enum type of | |
147 // a flags type since this functionality is not available in | |
148 // Qt. This may be a little bit inconsistent, but it saves | |
149 // us making yet another hash table for lookups. If it causes | |
150 // problems, make a new one for this particular purpose. | |
151 strs.append((eentry->javaPackage().isEmpty() ? QString() : eentry->javaPackage().replace('.', '/') + "/") | |
152 + eentry->javaQualifier() + "$" + eentry->targetLangName()); | |
153 strs.append(entry->isFlags() ? static_cast<FlagsTypeEntry *>(entry)->originalName() : entry->qualifiedCppName()); | |
154 } | |
155 } | |
156 } | |
157 | |
158 Q_ASSERT(strs.size() % 2 == 0); | |
159 | |
160 s << "static int enum_count = " << (strs.size() / 2) << ";" << endl; | |
161 if (strs.size() > 0) { | |
162 metainfo_write_name_list(s, "enumJavaNames", strs, 0, 2); | |
163 metainfo_write_name_list(s, "enumCppNames", strs, 1, 2); | |
164 } else { | |
165 s << "static const char **enumCppNames = 0;" << endl | |
166 << "static const char **enumJavaNames = 0;" << endl; | |
167 } | |
168 } | |
169 | |
170 void MetaInfoGenerator::writeSignalsAndSlots(QTextStream &s, const QString &package) | |
171 { | |
172 AbstractMetaClassList classes = this->classes(); | |
173 | |
174 QList<QString> strs; | |
175 foreach (AbstractMetaClass *cls, classes) { | |
176 if (cls->package() == package) { | |
177 AbstractMetaFunctionList functions = cls->functions(); | |
178 foreach (AbstractMetaFunction *f, functions) { | |
179 if (f->implementingClass() == cls && (f->isSignal() || f->isSlot())) { | |
180 | |
181 AbstractMetaArgumentList arguments = f->arguments(); | |
182 int numOverloads = arguments.size(); | |
183 for (int i=arguments.size()-1; i>=0; --i) { | |
184 if (arguments.at(i)->defaultValueExpression().isEmpty()) { | |
185 numOverloads = arguments.size() - i - 1; | |
186 break; | |
187 } | |
188 } | |
189 | |
190 for (int i=0; i<=numOverloads; ++i) { | |
191 Option option = Option(SkipAttributes | SkipReturnType | SkipName); | |
192 QString qtName; | |
193 { | |
194 | |
195 QTextStream qtNameStream(&qtName); | |
196 CppGenerator::writeFunctionSignature(qtNameStream, f, 0, QString(), | |
197 Option(option | OriginalName | NormalizeAndFixTypeSignature | OriginalTypeDescription), | |
198 QString(), QStringList(), arguments.size() - i); | |
199 } | |
200 qtName = f->implementingClass()->qualifiedCppName() + "::" + qtName; | |
201 qtName = QMetaObject::normalizedSignature(qtName.toLatin1().constData()); | |
202 | |
203 QString javaFunctionName = functionSignature(f, 0, 0, option, arguments.size() - (f->isSignal() ? 0 : i)); | |
204 QString javaObjectName = f->isSignal() | |
205 ? f->name() | |
206 : javaFunctionName; | |
207 | |
208 javaFunctionName = f->implementingClass()->fullName() + "." + javaFunctionName; | |
209 javaObjectName = f->implementingClass()->fullName() + "." + javaObjectName; | |
210 | |
211 QString javaSignature = "("; | |
212 for (int j=0; j < (arguments.size() - (f->isSignal() ? 0 : i)); ++j) { | |
213 AbstractMetaArgument *arg = arguments.at(j); | |
214 javaSignature += jni_signature(arg->type(), SlashesAndStuff); | |
215 } | |
216 javaSignature += ")" + jni_signature(f->type(), SlashesAndStuff); | |
217 | |
218 strs.append(qtName); | |
219 strs.append(javaFunctionName); | |
220 strs.append(javaObjectName); | |
221 strs.append(javaSignature); | |
222 } | |
223 } | |
224 } | |
225 } | |
226 } | |
227 | |
228 Q_ASSERT(strs.size() % 4 == 0); | |
229 | |
230 s << "static int sns_count = " << (strs.size() / 4) << ";" << endl; | |
231 if (strs.size() > 0) { | |
232 metainfo_write_name_list(s, "qtNames", strs, 0, 4); | |
233 metainfo_write_name_list(s, "javaFunctionNames", strs, 1, 4); | |
234 metainfo_write_name_list(s, "javaObjectNames", strs, 2, 4); | |
235 metainfo_write_name_list(s, "javaSignatures", strs, 3, 4); | |
236 } else { | |
237 s << "static const char **qtNames = 0;" << endl | |
238 << "static const char **javaFunctionNames = 0;" << endl | |
239 << "static const char **javaObjectNames = 0;" << endl | |
240 << "static const char **javaSignatures = 0;" << endl; | |
241 } | |
242 } | |
243 | |
244 void MetaInfoGenerator::writeRegisterSignalsAndSlots(QTextStream &s) | |
245 { | |
246 s << " for (int i=0;i<sns_count; ++i) {" << endl | |
247 << " registerQtToJava(qtNames[i], javaFunctionNames[i]);" << endl | |
248 << " if (getQtName(javaObjectNames[i]).length() < QByteArray(qtNames[i]).size())" << endl | |
249 << " registerJavaToQt(javaObjectNames[i], qtNames[i]);" << endl | |
250 << " registerJavaSignature(qtNames[i], javaSignatures[i]);" << endl | |
251 << " }" << endl; | |
252 } | |
253 | |
254 void MetaInfoGenerator::writeRegisterEnums(QTextStream &s) | |
255 { | |
256 s << " for (int i=0;i<enum_count; ++i) {" << endl | |
257 << " registerQtToJava(enumCppNames[i], enumJavaNames[i]);" << endl | |
258 << " registerJavaToQt(enumJavaNames[i], enumCppNames[i]);" << endl | |
259 << " }" << endl; | |
260 } | |
261 | |
262 void MetaInfoGenerator::buildSkipList() | |
263 { | |
264 AbstractMetaClassList classList = classes(); | |
265 foreach (AbstractMetaClass *cls, classList) { | |
266 if (!m_skip_list.contains(cls->package())) | |
267 m_skip_list[cls->package()] = 0x0; | |
268 | |
269 if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateCpp) | |
270 m_skip_list[cls->package()] |= GeneratedMetaInfo; | |
271 | |
272 if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) | |
273 m_skip_list[cls->package()] |= GeneratedJavaClasses; | |
274 } | |
275 } | |
276 | |
277 QStringList MetaInfoGenerator::writePolymorphicHandler(QTextStream &s, const QString &package, | |
278 const AbstractMetaClassList &classes) | |
279 { | |
280 QStringList handlers; | |
281 foreach (AbstractMetaClass *cls, classes) { | |
282 const ComplexTypeEntry *centry = cls->typeEntry(); | |
283 if (!centry->isPolymorphicBase()) | |
284 continue; | |
285 | |
286 AbstractMetaClassList classList = this->classes(); | |
287 bool first = true; | |
288 foreach (AbstractMetaClass *clazz, classList) { | |
289 if (clazz->package() == package && clazz->inheritsFrom(cls)) { | |
290 if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) { | |
291 // On first find, open the function | |
292 if (first) { | |
293 first = false; | |
294 | |
295 QString handler = jni_signature(cls->fullName(), Underscores); | |
296 handlers.append(handler); | |
297 | |
298 s << "static bool polymorphichandler_" << handler | |
299 << "(const void *ptr, char **class_name, char **package)" << endl | |
300 << "{" << endl | |
301 << " Q_ASSERT(ptr != 0);" << endl | |
302 << " " << cls->qualifiedCppName() << " *object = (" | |
303 << cls->qualifiedCppName() << " *)ptr;" << endl; | |
304 } | |
305 | |
306 // For each, add case label | |
307 s << " if (" | |
308 << clazz->typeEntry()->polymorphicIdValue().replace("%1", "object") | |
309 << ") {" << endl | |
310 << " *class_name = \"" << clazz->name() << "\";" << endl | |
311 << " *package = \"" << clazz->package().replace(".", "/") << "/\";" << endl | |
312 << " return true;" << endl | |
313 << " }" << endl; | |
314 } else { | |
315 QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set") | |
316 .arg(clazz->name()) | |
317 .arg(cls->name()); | |
318 | |
319 ReportHandler::warning(warning); | |
320 } | |
321 } | |
322 } | |
323 | |
324 // Close the function if it has been opened | |
325 if (!first) { | |
326 s << " return false;" << endl | |
327 << "}" << endl; | |
328 } | |
329 } | |
330 | |
331 return handlers; | |
332 } | |
333 | |
334 #if defined(QTJAMBI_DEBUG_TOOLS) | |
335 void MetaInfoGenerator::writeNameLiteral(QTextStream &s, const TypeEntry *entry, const QString &fileName) | |
336 { | |
337 static QSet<QString> used; | |
338 | |
339 if (!used.contains(fileName + ":" + entry->name())) { | |
340 s << "char __name_" << QString(entry->name()).replace(':', '_').replace(' ', '_') << "[] = \"" << entry->name() << "\";" << endl; | |
341 used.insert(fileName + ":" + entry->name()); | |
342 } | |
343 } | |
344 #endif | |
345 | |
346 void MetaInfoGenerator::writeCppFile() | |
347 { | |
348 TypeEntryHash entries = TypeDatabase::instance()->allEntries(); | |
349 TypeEntryHash::iterator it; | |
350 | |
351 AbstractMetaClassList classes_with_polymorphic_id; | |
352 AbstractMetaClassList classList = classes(); | |
353 QHash<QString, FileOut *> fileHash; | |
354 | |
355 // Seems continue is not supported by our foreach loop, so | |
356 foreach (AbstractMetaClass *cls, classList) { | |
357 | |
358 FileOut *f = fileHash.value(cls->package(), 0); | |
359 if (f == 0 && generated(cls)) { | |
360 f = new FileOut(outputDirectory() + "/" + subDirectoryForClass(cls, CppDirectory) + "/" + cppFilename()); | |
361 | |
362 writeIncludeStatements(f->stream, classList, cls->package()); | |
363 f->stream << endl; | |
364 | |
365 #if defined(QTJAMBI_DEBUG_TOOLS) | |
366 // Write the generic destructors and constructors | |
367 f->stream << "template <typename T, const char *NAME>" << endl | |
368 << "void genericDestructor(void *t)" << endl | |
369 << "{" << endl | |
370 << " delete (T *) t;" << endl | |
371 << " qtjambi_increase_destructorFunctionCalledCount(QString::fromLatin1(NAME));" << endl | |
372 << "}" << endl << endl | |
373 << "template <typename T>" << endl | |
374 << "void *genericConstructor(const void *t)" << endl | |
375 << "{" << endl | |
376 << " if (!t)" << endl | |
377 << " return new T;" << endl | |
378 << " return new T(*reinterpret_cast<const T *>(t));" << endl | |
379 << "}" << endl; | |
380 #endif | |
381 | |
382 | |
383 fileHash.insert(cls->package(), f); | |
384 | |
385 QString pro_file_name = cls->package().replace(".", "_") + "/" + cls->package().replace(".", "_") + ".pri"; | |
386 priGenerator->addSource(pro_file_name, cppFilename()); | |
387 } | |
388 | |
389 if (!(cls->attributes() & AbstractMetaAttributes::Fake)) { | |
390 if (f != 0) { | |
391 if (cls->typeEntry()->isObject() | |
392 && !cls->typeEntry()->isQObject() | |
393 && !cls->isInterface()) { | |
394 writeDestructors(f->stream, cls); | |
395 } | |
396 writeCustomStructors(f->stream, cls->typeEntry()); | |
397 } | |
398 | |
399 if (cls->typeEntry()->isPolymorphicBase()) | |
400 classes_with_polymorphic_id.append(cls); | |
401 } | |
402 | |
403 #if defined(QTJAMBI_DEBUG_TOOLS) | |
404 if (cls->typeEntry()->isValue() && shouldGenerate(cls->typeEntry())) | |
405 writeNameLiteral(f->stream, cls->typeEntry(), f->name()); | |
406 #endif | |
407 } | |
408 | |
409 QHash<QString, QStringList> handlers_to_register; | |
410 foreach (QString package, fileHash.keys()) { | |
411 FileOut *f = fileHash.value(package, 0); | |
412 if (f != 0) { | |
413 writeSignalsAndSlots(f->stream, package); | |
414 writeEnums(f->stream, package); | |
415 handlers_to_register[package] = writePolymorphicHandler(f->stream, package, classes_with_polymorphic_id); | |
416 } | |
417 } | |
418 | |
419 // Primitive types must be added to all packages, in case the other packages are | |
420 // not referenced from the generated code. | |
421 foreach (FileOut *f, fileHash.values()) { | |
422 for (it=entries.begin(); it!=entries.end(); ++it) { | |
423 QList<TypeEntry *> entries = it.value(); | |
424 foreach (TypeEntry *entry, entries) { | |
425 if (shouldGenerate(entry) && entry->isPrimitive()) { | |
426 writeCustomStructors(f->stream, entry); | |
427 #if defined(QTJAMBI_DEBUG_TOOLS) | |
428 writeNameLiteral(f->stream, entry, f->name()); | |
429 #endif | |
430 } | |
431 } | |
432 } | |
433 | |
434 // Initialization function: Registers meta types | |
435 writeInitializationFunctionName(f->stream, fileHash.key(f, ""), true); | |
436 f->stream << endl << "{" << endl; | |
437 for (it=entries.begin(); it!=entries.end(); ++it) { | |
438 QList<TypeEntry *> entries = it.value(); | |
439 foreach (TypeEntry *entry, entries) { | |
440 if (entry && | |
441 ( (shouldGenerate(entry) && entry->isPrimitive()) | |
442 || entry->isString() | |
443 || entry->isChar())) { | |
444 writeInitialization(f->stream, entry, 0); | |
445 } | |
446 } | |
447 } | |
448 writeRegisterSignalsAndSlots(f->stream); | |
449 writeRegisterEnums(f->stream); | |
450 } | |
451 | |
452 foreach (AbstractMetaClass *cls, classList) { | |
453 FileOut *f = fileHash.value(cls->package(), 0); | |
454 | |
455 if (f != 0) { | |
456 writeInitialization(f->stream, cls->typeEntry(), cls, shouldGenerate(cls)); | |
457 } | |
458 } | |
459 | |
460 foreach (QString package, fileHash.keys()) { | |
461 FileOut *f = fileHash.value(package, 0); | |
462 if (f != 0) { | |
463 foreach (QString handler, handlers_to_register.value(package, QStringList())) { | |
464 f->stream << " qtjambi_register_polymorphic_id(\"" << handler << "\"," | |
465 << "polymorphichandler_" << handler << ");" << endl; | |
466 } | |
467 | |
468 f->stream << "}" << endl << endl; | |
469 if( f->done() ) | |
470 ++m_num_generated_written; | |
471 ++m_num_generated; | |
472 | |
473 delete f; | |
474 } | |
475 } | |
476 } | |
477 | |
478 void MetaInfoGenerator::writeHeaderFile() | |
479 { | |
480 AbstractMetaClassList classList = classes(); | |
481 QHash<QString, bool> fileHash; | |
482 | |
483 foreach (AbstractMetaClass *cls, classList) { | |
484 bool hasGenerated = fileHash.value(cls->package(), false); | |
485 if (!hasGenerated && generated(cls)) { | |
486 FileOut file(outputDirectory() + "/" + subDirectoryForClass(cls, CppDirectory) + "/" + headerFilename()); | |
487 file.stream << "#ifndef " << filenameStub().toUpper() << "_H" << endl; | |
488 file.stream << "#define " << filenameStub().toUpper() << "_H" << endl << endl; | |
489 writeInitializationFunctionName(file.stream, cls->package(), true); | |
490 file.stream << ";" << endl << "#endif" << endl << endl; | |
491 | |
492 fileHash.insert(cls->package(), true); | |
493 | |
494 QString pro_file_name = cls->package().replace(".", "_") + "/" + cls->package().replace(".", "_") + ".pri"; | |
495 priGenerator->addHeader(pro_file_name, headerFilename()); | |
496 | |
497 if( file.done() ) | |
498 ++m_num_generated_written; | |
499 ++m_num_generated; | |
500 } | |
501 } | |
502 } | |
503 | |
504 void MetaInfoGenerator::writeCodeBlock(QTextStream &s, const QString &code) | |
505 { | |
506 QStringList lines = code.split('\n'); | |
507 QString indent; | |
508 foreach (QString str, lines) { | |
509 s << " " << indent << str.trimmed() << endl; | |
510 if (!str.trimmed().endsWith(";") && !str.trimmed().isEmpty()) | |
511 indent = " "; | |
512 else | |
513 indent = ""; | |
514 } | |
515 } | |
516 | |
517 const AbstractMetaClass* MetaInfoGenerator::lookupClassWithPublicDestructor(const AbstractMetaClass *cls) | |
518 { | |
519 while (cls != 0) { | |
520 if (cls->hasPublicDestructor()) { | |
521 return cls; | |
522 } else { | |
523 cls = cls->baseClass(); | |
524 } | |
525 } | |
526 return 0; | |
527 } | |
528 | |
529 void MetaInfoGenerator::writeDestructors(QTextStream &s, const AbstractMetaClass *cls) | |
530 { | |
531 // We can only delete classes with public destructors | |
532 const AbstractMetaClass *clsWithPublicDestructor = lookupClassWithPublicDestructor(cls); | |
533 if(clsWithPublicDestructor != 0) { | |
534 const ComplexTypeEntry *entry = cls->typeEntry(); | |
535 if ((entry->codeGeneration() & TypeEntry::GenerateCode) != 0) { | |
536 s << "void destructor_" << entry->javaPackage().replace(".", "_") << "_" | |
537 << entry->lookupName().replace(".", "_").replace("$", "_") << "(void *ptr)" << endl | |
538 << "{" << endl | |
539 << " delete reinterpret_cast<" << clsWithPublicDestructor->qualifiedCppName() << " *>(ptr);" << endl; | |
540 | |
541 #if defined(QTJAMBI_DEBUG_TOOLS) | |
542 s << " qtjambi_increase_destructorFunctionCalledCount(QString::fromLatin1(\"" << cls->name() << "\"));" << endl; | |
543 #endif | |
544 | |
545 s << "}" << endl << endl; | |
546 } | |
547 } | |
548 } | |
549 | |
550 void MetaInfoGenerator::writeCustomStructors(QTextStream &s, const TypeEntry *entry) | |
551 { | |
552 if (!entry->preferredConversion()) | |
553 return ; | |
554 | |
555 CustomFunction customConstructor = entry->customConstructor(); | |
556 CustomFunction customDestructor = entry->customDestructor(); | |
557 | |
558 if (!customConstructor.name.isEmpty() && !customDestructor.name.isEmpty()) { | |
559 s << "// Custom constructor and destructor for " << entry->qualifiedCppName() << endl | |
560 << "static void *" << customConstructor.name << "(" | |
561 << "const " << entry->qualifiedCppName() << " *" << customConstructor.param_name | |
562 << ")" << endl | |
563 << "{" << endl; | |
564 writeCodeBlock(s, customConstructor.code()); | |
565 s << "}" << endl << endl; | |
566 | |
567 s << "static void " << customDestructor.name << "(" | |
568 << "const " << entry->qualifiedCppName() << " *" << customDestructor.param_name | |
569 << ")" << endl | |
570 << "{" << endl; | |
571 writeCodeBlock(s, customDestructor.code()); | |
572 s << "}" << endl << endl; | |
573 } | |
574 } | |
575 | |
576 static void generateInitializer(QTextStream &s, const QString &package, CodeSnip::Position pos) | |
577 { | |
578 QList<CodeSnip> snips = | |
579 ((TypeSystemTypeEntry *) TypeDatabase::instance()->findType(package))->snips; | |
580 | |
581 foreach (const CodeSnip &snip, snips) | |
582 if (snip.position == pos) | |
583 s << snip.code(); | |
584 } | |
585 | |
586 void MetaInfoGenerator::writeLibraryInitializers() | |
587 { | |
588 // from cppimplgenerator.cpp | |
589 extern QString jni_function_signature(QString package, | |
590 QString class_name, | |
591 const QString &function_name, | |
592 const QString &return_type, | |
593 const QString &mangled_arguments = QString(), | |
594 uint options = CppImplGenerator::StandardJNISignature); | |
595 | |
596 // We need to generate a library initializer in Java for all packages | |
597 // that have generated classes in Java, and in C++ for all packages | |
598 // that have generated metainfo. | |
599 | |
600 QList<QString> known_packages = m_skip_list.keys(); | |
601 foreach (QString package, known_packages) { | |
602 if (generatedMetaInfo(package)) { // write cpp file | |
603 | |
604 FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, CppDirectory) + "/qtjambi_libraryinitializer.cpp"); | |
605 | |
606 QString signature = jni_function_signature(package, "QtJambi_LibraryInitializer", | |
607 "__qt_initLibrary", "void"); | |
608 QTextStream &s = fileOut.stream; | |
609 s << "#include \"metainfo.h\"" << endl | |
610 << "#include \"qtjambi_global.h\"" << endl << endl | |
611 << signature << "(JNIEnv *, jclass)" << endl | |
612 << "{" << endl | |
613 << " "; | |
614 writeInitializationFunctionName(s, package, false); | |
615 s << ";" << endl | |
616 << "}" << endl << endl; | |
617 | |
618 QString pro_file_name = QString(package).replace(".", "_"); | |
619 | |
620 priGenerator->addSource(pro_file_name + "/" + pro_file_name + ".pri", "qtjambi_libraryinitializer.cpp"); | |
621 | |
622 if( fileOut.done() ) | |
623 ++m_num_generated_written; | |
624 ++m_num_generated; | |
625 } | |
626 | |
627 if (generatedJavaClasses(package)) { | |
628 | |
629 FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, JavaDirectory) + "/QtJambi_LibraryInitializer.java"); | |
630 | |
631 QTextStream &s = fileOut.stream; | |
632 s << "package " << package << ";" << endl << endl | |
633 << "class QtJambi_LibraryInitializer" << endl | |
634 << "{" << endl | |
635 << " static {" << endl; | |
636 | |
637 generateInitializer(s, package, CodeSnip::Beginning); | |
638 | |
639 s << " qt.Utilities.loadJambiLibrary(\"" | |
640 << QString(package).replace(".", "_") << "\");" << endl; | |
641 | |
642 if (generatedMetaInfo(package)) | |
643 s << " __qt_initLibrary();" << endl; | |
644 | |
645 generateInitializer(s, package, CodeSnip::End); | |
646 | |
647 s << " }" << endl; | |
648 | |
649 if (generatedMetaInfo(package)) | |
650 s << " private native static void __qt_initLibrary();" << endl; | |
651 | |
652 s << " static void init() { };" << endl | |
653 << "}" << endl << endl; | |
654 | |
655 if( fileOut.done() ) | |
656 ++m_num_generated_written; | |
657 ++m_num_generated; | |
658 } | |
659 } | |
660 } | |
661 | |
662 void MetaInfoGenerator::writeInclude(QTextStream &s, const Include &inc) | |
663 { | |
664 if (inc.name.isEmpty()) | |
665 return; | |
666 | |
667 s << "#include "; | |
668 if (inc.type == Include::LocalPath) | |
669 s << "\"" << inc.name << "\""; | |
670 else | |
671 s << "<" << inc.name << ">"; | |
672 s << endl; | |
673 } | |
674 | |
675 void MetaInfoGenerator::writeIncludeStatements(QTextStream &s, const AbstractMetaClassList &classList, | |
676 const QString &package) | |
677 { | |
678 writeInclude(s, Include(Include::LocalPath, headerFilename())); | |
679 writeInclude(s, Include(Include::IncludePath, "QMetaType")); | |
680 writeInclude(s, Include(Include::IncludePath, "QString")); | |
681 writeInclude(s, Include(Include::IncludePath, "QLatin1String")); | |
682 writeInclude(s, Include(Include::IncludePath, "QHash")); | |
683 writeInclude(s, Include(Include::IncludePath, "QReadWriteLock")); | |
684 writeInclude(s, Include(Include::IncludePath, "QReadLocker")); | |
685 writeInclude(s, Include(Include::IncludePath, "QWriteLocker")); | |
686 writeInclude(s, Include(Include::IncludePath, "qtjambi_cache.h")); | |
687 writeInclude(s, Include(Include::IncludePath, "qtjambi_core.h")); | |
688 | |
689 #if defined(QTJAMBI_DEBUG_TOOLS) | |
690 writeInclude(s, Include(Include::IncludePath, "qtjambidebugtools_p.h")); | |
691 #endif | |
692 | |
693 s << endl; | |
694 | |
695 foreach (AbstractMetaClass *cls, classList) { | |
696 if (generated(cls) && !cls->isInterface() && cls->package() == package) { | |
697 const ComplexTypeEntry *ctype = cls->typeEntry(); | |
698 | |
699 Include inc = ctype->include(); | |
700 writeInclude(s, inc); | |
701 } | |
702 } | |
703 } | |
704 | |
705 void MetaInfoGenerator::writeInitializationFunctionName(QTextStream &s, const QString &package, bool fullSignature) | |
706 { | |
707 if (fullSignature) | |
708 s << "void "; | |
709 s << "__metainfo_init_" << QString(package).replace(".", "_") << "()"; | |
710 } | |
711 | |
712 void MetaInfoGenerator::writeInitialization(QTextStream &s, const TypeEntry *entry, const AbstractMetaClass *cls, | |
713 bool registerMetaType) | |
714 { | |
715 if (entry->codeGeneration() == TypeEntry::GenerateForSubclass) | |
716 return; | |
717 | |
718 if (cls && cls->attributes() & AbstractMetaAttributes::Fake) | |
719 return; | |
720 | |
721 | |
722 QString constructorName = entry->customConstructor().name; | |
723 QString destructorName = entry->customDestructor().name; | |
724 #if defined(QTJAMBI_DEBUG_TOOLS) | |
725 | |
726 if (constructorName.isEmpty()) | |
727 constructorName = "genericConstructor<" + entry->qualifiedCppName() + ">"; | |
728 | |
729 if (destructorName.isEmpty()) | |
730 destructorName = "genericDestructor<" + entry->qualifiedCppName() + ", __name_" + entry->name() + ">"; | |
731 | |
732 #endif | |
733 | |
734 | |
735 if (constructorName.isEmpty() != destructorName.isEmpty()) { | |
736 ReportHandler::warning(QString("specify either no custom functions, or both " | |
737 "constructor and destructor for type '%1'").arg(entry->name())); | |
738 } | |
739 | |
740 QString javaPackage = entry->javaPackage(); | |
741 | |
742 QString javaName = entry->lookupName(); | |
743 if(!javaPackage.isEmpty()){ | |
744 javaName.prepend(javaPackage.replace(".", "/") + "/"); | |
745 } | |
746 | |
747 | |
748 if (entry->isComplex()) { | |
749 const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry); | |
750 if (centry->typeFlags() & ComplexTypeEntry::DeleteInMainThread) | |
751 s << " registerDeletionPolicy(\"" << javaName << "\", DeletionPolicyDeleteInMainThread);" << endl; | |
752 } | |
753 | |
754 QString qtName = entry->qualifiedCppName(); | |
755 if ((!entry->isInterface()) | |
756 && (!entry->isPrimitive() || ((PrimitiveTypeEntry *) entry)->preferredTargetLangType())) | |
757 s << " registerQtToJava(\"" << qtName << "\", \"" << javaName << "\");" << endl; | |
758 | |
759 if (!entry->preferredConversion()) | |
760 return ; | |
761 | |
762 s << " registerJavaToQt(\"" << javaName << "\", \"" << qtName << "\");" << endl; | |
763 if (entry->isComplex() && entry->isObject() && !((ComplexTypeEntry *)entry)->isQObject() && !entry->isInterface()) { | |
764 QString patchedName = QString(javaName).replace("/", "_").replace("$", "_"); | |
765 | |
766 if(lookupClassWithPublicDestructor(cls)) | |
767 s << " registerDestructor(\"" << javaName << "\", destructor_" << patchedName << ");" << endl; | |
768 } | |
769 | |
770 if (!registerMetaType) | |
771 return ; | |
772 | |
773 int metaType = QMetaType::type(entry->name().toLocal8Bit().constData()); | |
774 if (metaType != QMetaType::Void) | |
775 return ; | |
776 | |
777 | |
778 if (!constructorName.isEmpty() && !destructorName.isEmpty()) { | |
779 s << " QMetaType::registerType(\"" << entry->qualifiedCppName() << "\"," << endl | |
780 << " reinterpret_cast<QMetaType::Destructor>(" | |
781 << destructorName | |
782 << ")," << endl | |
783 << " reinterpret_cast<QMetaType::Constructor>(" | |
784 << constructorName | |
785 << "));" << endl; | |
786 } else { | |
787 // Look for default constructor, required for qRegisterMetaType | |
788 if (cls != 0) { | |
789 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::WasPublic | AbstractMetaClass::Constructors); | |
790 | |
791 bool hasDefaultConstructor = false; | |
792 foreach (AbstractMetaFunction *function, functions) { | |
793 // Default constructor has to be present | |
794 if (function->wasPublic() && function->actualMinimumArgumentCount() == 0) | |
795 hasDefaultConstructor = true; | |
796 } | |
797 | |
798 if (!hasDefaultConstructor) { | |
799 ReportHandler::warning(QString("Value type '%1' is missing a default constructor. " | |
800 "The resulting C++ code will not compile. If necessary, use <custom-constructor> and " | |
801 "<custom-destructor> tags to provide the constructors.").arg(cls->fullName())); | |
802 } | |
803 | |
804 } | |
805 s << " qRegisterMetaType<" << entry->qualifiedCppName() << ">(\"" << entry->qualifiedCppName() << "\");" << endl; | |
806 } | |
807 | |
808 } |