1
|
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
|
238
|
385 priGenerator->addSource(cls->package(), cppFilename());
|
1
|
386 }
|
|
387
|
|
388 if (!(cls->attributes() & AbstractMetaAttributes::Fake)) {
|
|
389 if (f != 0) {
|
|
390 if (cls->typeEntry()->isObject()
|
|
391 && !cls->typeEntry()->isQObject()
|
|
392 && !cls->isInterface()) {
|
|
393 writeDestructors(f->stream, cls);
|
|
394 }
|
|
395 writeCustomStructors(f->stream, cls->typeEntry());
|
|
396 }
|
|
397
|
|
398 if (cls->typeEntry()->isPolymorphicBase())
|
|
399 classes_with_polymorphic_id.append(cls);
|
|
400 }
|
|
401
|
|
402 #if defined(QTJAMBI_DEBUG_TOOLS)
|
|
403 if (cls->typeEntry()->isValue() && shouldGenerate(cls->typeEntry()))
|
|
404 writeNameLiteral(f->stream, cls->typeEntry(), f->name());
|
|
405 #endif
|
|
406 }
|
|
407
|
|
408 QHash<QString, QStringList> handlers_to_register;
|
|
409 foreach (QString package, fileHash.keys()) {
|
|
410 FileOut *f = fileHash.value(package, 0);
|
|
411 if (f != 0) {
|
|
412 writeSignalsAndSlots(f->stream, package);
|
|
413 writeEnums(f->stream, package);
|
|
414 handlers_to_register[package] = writePolymorphicHandler(f->stream, package, classes_with_polymorphic_id);
|
|
415 }
|
|
416 }
|
|
417
|
|
418 // Primitive types must be added to all packages, in case the other packages are
|
|
419 // not referenced from the generated code.
|
|
420 foreach (FileOut *f, fileHash.values()) {
|
|
421 for (it=entries.begin(); it!=entries.end(); ++it) {
|
|
422 QList<TypeEntry *> entries = it.value();
|
|
423 foreach (TypeEntry *entry, entries) {
|
|
424 if (shouldGenerate(entry) && entry->isPrimitive()) {
|
|
425 writeCustomStructors(f->stream, entry);
|
|
426 #if defined(QTJAMBI_DEBUG_TOOLS)
|
|
427 writeNameLiteral(f->stream, entry, f->name());
|
|
428 #endif
|
|
429 }
|
|
430 }
|
|
431 }
|
|
432
|
|
433 // Initialization function: Registers meta types
|
|
434 writeInitializationFunctionName(f->stream, fileHash.key(f, ""), true);
|
|
435 f->stream << endl << "{" << endl;
|
|
436 for (it=entries.begin(); it!=entries.end(); ++it) {
|
|
437 QList<TypeEntry *> entries = it.value();
|
|
438 foreach (TypeEntry *entry, entries) {
|
|
439 if (entry &&
|
|
440 ( (shouldGenerate(entry) && entry->isPrimitive())
|
|
441 || entry->isString()
|
|
442 || entry->isChar())) {
|
|
443 writeInitialization(f->stream, entry, 0);
|
|
444 }
|
|
445 }
|
|
446 }
|
|
447 writeRegisterSignalsAndSlots(f->stream);
|
|
448 writeRegisterEnums(f->stream);
|
|
449 }
|
|
450
|
|
451 foreach (AbstractMetaClass *cls, classList) {
|
|
452 FileOut *f = fileHash.value(cls->package(), 0);
|
|
453
|
|
454 if (f != 0) {
|
|
455 writeInitialization(f->stream, cls->typeEntry(), cls, shouldGenerate(cls));
|
|
456 }
|
|
457 }
|
|
458
|
|
459 foreach (QString package, fileHash.keys()) {
|
|
460 FileOut *f = fileHash.value(package, 0);
|
|
461 if (f != 0) {
|
|
462 foreach (QString handler, handlers_to_register.value(package, QStringList())) {
|
|
463 f->stream << " qtjambi_register_polymorphic_id(\"" << handler << "\","
|
|
464 << "polymorphichandler_" << handler << ");" << endl;
|
|
465 }
|
|
466
|
|
467 f->stream << "}" << endl << endl;
|
|
468 if( f->done() )
|
|
469 ++m_num_generated_written;
|
|
470 ++m_num_generated;
|
|
471
|
|
472 delete f;
|
|
473 }
|
|
474 }
|
|
475 }
|
|
476
|
|
477 void MetaInfoGenerator::writeHeaderFile()
|
|
478 {
|
|
479 AbstractMetaClassList classList = classes();
|
|
480 QHash<QString, bool> fileHash;
|
|
481
|
|
482 foreach (AbstractMetaClass *cls, classList) {
|
|
483 bool hasGenerated = fileHash.value(cls->package(), false);
|
|
484 if (!hasGenerated && generated(cls)) {
|
|
485 FileOut file(outputDirectory() + "/" + subDirectoryForClass(cls, CppDirectory) + "/" + headerFilename());
|
|
486 file.stream << "#ifndef " << filenameStub().toUpper() << "_H" << endl;
|
|
487 file.stream << "#define " << filenameStub().toUpper() << "_H" << endl << endl;
|
|
488 writeInitializationFunctionName(file.stream, cls->package(), true);
|
|
489 file.stream << ";" << endl << "#endif" << endl << endl;
|
|
490
|
|
491 fileHash.insert(cls->package(), true);
|
|
492
|
238
|
493 priGenerator->addHeader(cls->package(), headerFilename());
|
1
|
494
|
|
495 if( file.done() )
|
|
496 ++m_num_generated_written;
|
|
497 ++m_num_generated;
|
|
498 }
|
|
499 }
|
|
500 }
|
|
501
|
|
502 void MetaInfoGenerator::writeCodeBlock(QTextStream &s, const QString &code)
|
|
503 {
|
|
504 QStringList lines = code.split('\n');
|
|
505 QString indent;
|
|
506 foreach (QString str, lines) {
|
|
507 s << " " << indent << str.trimmed() << endl;
|
|
508 if (!str.trimmed().endsWith(";") && !str.trimmed().isEmpty())
|
|
509 indent = " ";
|
|
510 else
|
|
511 indent = "";
|
|
512 }
|
|
513 }
|
|
514
|
|
515 const AbstractMetaClass* MetaInfoGenerator::lookupClassWithPublicDestructor(const AbstractMetaClass *cls)
|
|
516 {
|
|
517 while (cls != 0) {
|
|
518 if (cls->hasPublicDestructor()) {
|
|
519 return cls;
|
|
520 } else {
|
|
521 cls = cls->baseClass();
|
|
522 }
|
|
523 }
|
|
524 return 0;
|
|
525 }
|
|
526
|
|
527 void MetaInfoGenerator::writeDestructors(QTextStream &s, const AbstractMetaClass *cls)
|
|
528 {
|
|
529 // We can only delete classes with public destructors
|
|
530 const AbstractMetaClass *clsWithPublicDestructor = lookupClassWithPublicDestructor(cls);
|
|
531 if(clsWithPublicDestructor != 0) {
|
|
532 const ComplexTypeEntry *entry = cls->typeEntry();
|
|
533 if ((entry->codeGeneration() & TypeEntry::GenerateCode) != 0) {
|
|
534 s << "void destructor_" << entry->javaPackage().replace(".", "_") << "_"
|
|
535 << entry->lookupName().replace(".", "_").replace("$", "_") << "(void *ptr)" << endl
|
|
536 << "{" << endl
|
|
537 << " delete reinterpret_cast<" << clsWithPublicDestructor->qualifiedCppName() << " *>(ptr);" << endl;
|
|
538
|
|
539 #if defined(QTJAMBI_DEBUG_TOOLS)
|
|
540 s << " qtjambi_increase_destructorFunctionCalledCount(QString::fromLatin1(\"" << cls->name() << "\"));" << endl;
|
|
541 #endif
|
|
542
|
|
543 s << "}" << endl << endl;
|
|
544 }
|
|
545 }
|
|
546 }
|
|
547
|
|
548 void MetaInfoGenerator::writeCustomStructors(QTextStream &s, const TypeEntry *entry)
|
|
549 {
|
|
550 if (!entry->preferredConversion())
|
|
551 return ;
|
|
552
|
|
553 CustomFunction customConstructor = entry->customConstructor();
|
|
554 CustomFunction customDestructor = entry->customDestructor();
|
|
555
|
|
556 if (!customConstructor.name.isEmpty() && !customDestructor.name.isEmpty()) {
|
|
557 s << "// Custom constructor and destructor for " << entry->qualifiedCppName() << endl
|
|
558 << "static void *" << customConstructor.name << "("
|
|
559 << "const " << entry->qualifiedCppName() << " *" << customConstructor.param_name
|
|
560 << ")" << endl
|
|
561 << "{" << endl;
|
|
562 writeCodeBlock(s, customConstructor.code());
|
|
563 s << "}" << endl << endl;
|
|
564
|
|
565 s << "static void " << customDestructor.name << "("
|
|
566 << "const " << entry->qualifiedCppName() << " *" << customDestructor.param_name
|
|
567 << ")" << endl
|
|
568 << "{" << endl;
|
|
569 writeCodeBlock(s, customDestructor.code());
|
|
570 s << "}" << endl << endl;
|
|
571 }
|
|
572 }
|
|
573
|
|
574 static void generateInitializer(QTextStream &s, const QString &package, CodeSnip::Position pos)
|
|
575 {
|
|
576 QList<CodeSnip> snips =
|
|
577 ((TypeSystemTypeEntry *) TypeDatabase::instance()->findType(package))->snips;
|
|
578
|
|
579 foreach (const CodeSnip &snip, snips)
|
|
580 if (snip.position == pos)
|
|
581 s << snip.code();
|
|
582 }
|
|
583
|
|
584 void MetaInfoGenerator::writeLibraryInitializers()
|
|
585 {
|
|
586 // from cppimplgenerator.cpp
|
|
587 extern QString jni_function_signature(QString package,
|
|
588 QString class_name,
|
|
589 const QString &function_name,
|
|
590 const QString &return_type,
|
|
591 const QString &mangled_arguments = QString(),
|
|
592 uint options = CppImplGenerator::StandardJNISignature);
|
|
593
|
|
594 // We need to generate a library initializer in Java for all packages
|
|
595 // that have generated classes in Java, and in C++ for all packages
|
|
596 // that have generated metainfo.
|
|
597
|
|
598 QList<QString> known_packages = m_skip_list.keys();
|
|
599 foreach (QString package, known_packages) {
|
|
600 if (generatedMetaInfo(package)) { // write cpp file
|
|
601
|
|
602 FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, CppDirectory) + "/qtjambi_libraryinitializer.cpp");
|
|
603
|
|
604 QString signature = jni_function_signature(package, "QtJambi_LibraryInitializer",
|
|
605 "__qt_initLibrary", "void");
|
|
606 QTextStream &s = fileOut.stream;
|
|
607 s << "#include \"metainfo.h\"" << endl
|
|
608 << "#include \"qtjambi_global.h\"" << endl << endl
|
|
609 << signature << "(JNIEnv *, jclass)" << endl
|
|
610 << "{" << endl
|
|
611 << " ";
|
|
612 writeInitializationFunctionName(s, package, false);
|
|
613 s << ";" << endl
|
|
614 << "}" << endl << endl;
|
|
615
|
238
|
616 priGenerator->addSource(package, "qtjambi_libraryinitializer.cpp");
|
1
|
617
|
|
618 if( fileOut.done() )
|
|
619 ++m_num_generated_written;
|
|
620 ++m_num_generated;
|
|
621 }
|
|
622
|
|
623 if (generatedJavaClasses(package)) {
|
|
624
|
|
625 FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(package, JavaDirectory) + "/QtJambi_LibraryInitializer.java");
|
|
626
|
|
627 QTextStream &s = fileOut.stream;
|
|
628 s << "package " << package << ";" << endl << endl
|
|
629 << "class QtJambi_LibraryInitializer" << endl
|
|
630 << "{" << endl
|
|
631 << " static {" << endl;
|
|
632
|
|
633 generateInitializer(s, package, CodeSnip::Beginning);
|
|
634
|
|
635 s << " qt.Utilities.loadJambiLibrary(\""
|
|
636 << QString(package).replace(".", "_") << "\");" << endl;
|
|
637
|
|
638 if (generatedMetaInfo(package))
|
|
639 s << " __qt_initLibrary();" << endl;
|
|
640
|
|
641 generateInitializer(s, package, CodeSnip::End);
|
|
642
|
|
643 s << " }" << endl;
|
|
644
|
|
645 if (generatedMetaInfo(package))
|
|
646 s << " private native static void __qt_initLibrary();" << endl;
|
|
647
|
|
648 s << " static void init() { };" << endl
|
|
649 << "}" << endl << endl;
|
|
650
|
|
651 if( fileOut.done() )
|
|
652 ++m_num_generated_written;
|
|
653 ++m_num_generated;
|
|
654 }
|
|
655 }
|
|
656 }
|
|
657
|
|
658 void MetaInfoGenerator::writeInclude(QTextStream &s, const Include &inc)
|
|
659 {
|
|
660 if (inc.name.isEmpty())
|
|
661 return;
|
|
662
|
|
663 s << "#include ";
|
|
664 if (inc.type == Include::LocalPath)
|
|
665 s << "\"" << inc.name << "\"";
|
|
666 else
|
|
667 s << "<" << inc.name << ">";
|
|
668 s << endl;
|
|
669 }
|
|
670
|
|
671 void MetaInfoGenerator::writeIncludeStatements(QTextStream &s, const AbstractMetaClassList &classList,
|
|
672 const QString &package)
|
|
673 {
|
|
674 writeInclude(s, Include(Include::LocalPath, headerFilename()));
|
|
675 writeInclude(s, Include(Include::IncludePath, "QMetaType"));
|
|
676 writeInclude(s, Include(Include::IncludePath, "QString"));
|
|
677 writeInclude(s, Include(Include::IncludePath, "QLatin1String"));
|
|
678 writeInclude(s, Include(Include::IncludePath, "QHash"));
|
|
679 writeInclude(s, Include(Include::IncludePath, "QReadWriteLock"));
|
|
680 writeInclude(s, Include(Include::IncludePath, "QReadLocker"));
|
|
681 writeInclude(s, Include(Include::IncludePath, "QWriteLocker"));
|
|
682 writeInclude(s, Include(Include::IncludePath, "qtjambi_cache.h"));
|
|
683 writeInclude(s, Include(Include::IncludePath, "qtjambi_core.h"));
|
|
684
|
|
685 #if defined(QTJAMBI_DEBUG_TOOLS)
|
|
686 writeInclude(s, Include(Include::IncludePath, "qtjambidebugtools_p.h"));
|
|
687 #endif
|
|
688
|
|
689 s << endl;
|
|
690
|
|
691 foreach (AbstractMetaClass *cls, classList) {
|
|
692 if (generated(cls) && !cls->isInterface() && cls->package() == package) {
|
|
693 const ComplexTypeEntry *ctype = cls->typeEntry();
|
|
694
|
|
695 Include inc = ctype->include();
|
|
696 writeInclude(s, inc);
|
|
697 }
|
|
698 }
|
|
699 }
|
|
700
|
|
701 void MetaInfoGenerator::writeInitializationFunctionName(QTextStream &s, const QString &package, bool fullSignature)
|
|
702 {
|
|
703 if (fullSignature)
|
|
704 s << "void ";
|
|
705 s << "__metainfo_init_" << QString(package).replace(".", "_") << "()";
|
|
706 }
|
|
707
|
|
708 void MetaInfoGenerator::writeInitialization(QTextStream &s, const TypeEntry *entry, const AbstractMetaClass *cls,
|
|
709 bool registerMetaType)
|
|
710 {
|
|
711 if (entry->codeGeneration() == TypeEntry::GenerateForSubclass)
|
|
712 return;
|
|
713
|
|
714 if (cls && cls->attributes() & AbstractMetaAttributes::Fake)
|
|
715 return;
|
|
716
|
|
717
|
|
718 QString constructorName = entry->customConstructor().name;
|
|
719 QString destructorName = entry->customDestructor().name;
|
|
720 #if defined(QTJAMBI_DEBUG_TOOLS)
|
|
721
|
|
722 if (constructorName.isEmpty())
|
|
723 constructorName = "genericConstructor<" + entry->qualifiedCppName() + ">";
|
|
724
|
|
725 if (destructorName.isEmpty())
|
|
726 destructorName = "genericDestructor<" + entry->qualifiedCppName() + ", __name_" + entry->name() + ">";
|
|
727
|
|
728 #endif
|
|
729
|
|
730
|
|
731 if (constructorName.isEmpty() != destructorName.isEmpty()) {
|
|
732 ReportHandler::warning(QString("specify either no custom functions, or both "
|
|
733 "constructor and destructor for type '%1'").arg(entry->name()));
|
|
734 }
|
|
735
|
|
736 QString javaPackage = entry->javaPackage();
|
|
737
|
|
738 QString javaName = entry->lookupName();
|
|
739 if(!javaPackage.isEmpty()){
|
|
740 javaName.prepend(javaPackage.replace(".", "/") + "/");
|
|
741 }
|
|
742
|
|
743
|
|
744 if (entry->isComplex()) {
|
|
745 const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry);
|
|
746 if (centry->typeFlags() & ComplexTypeEntry::DeleteInMainThread)
|
|
747 s << " registerDeletionPolicy(\"" << javaName << "\", DeletionPolicyDeleteInMainThread);" << endl;
|
|
748 }
|
|
749
|
|
750 QString qtName = entry->qualifiedCppName();
|
|
751 if ((!entry->isInterface())
|
|
752 && (!entry->isPrimitive() || ((PrimitiveTypeEntry *) entry)->preferredTargetLangType()))
|
|
753 s << " registerQtToJava(\"" << qtName << "\", \"" << javaName << "\");" << endl;
|
|
754
|
|
755 if (!entry->preferredConversion())
|
|
756 return ;
|
|
757
|
|
758 s << " registerJavaToQt(\"" << javaName << "\", \"" << qtName << "\");" << endl;
|
|
759 if (entry->isComplex() && entry->isObject() && !((ComplexTypeEntry *)entry)->isQObject() && !entry->isInterface()) {
|
|
760 QString patchedName = QString(javaName).replace("/", "_").replace("$", "_");
|
|
761
|
|
762 if(lookupClassWithPublicDestructor(cls))
|
|
763 s << " registerDestructor(\"" << javaName << "\", destructor_" << patchedName << ");" << endl;
|
|
764 }
|
|
765
|
|
766 if (!registerMetaType)
|
|
767 return ;
|
|
768
|
|
769 int metaType = QMetaType::type(entry->name().toLocal8Bit().constData());
|
|
770 if (metaType != QMetaType::Void)
|
|
771 return ;
|
|
772
|
|
773
|
|
774 if (!constructorName.isEmpty() && !destructorName.isEmpty()) {
|
|
775 s << " QMetaType::registerType(\"" << entry->qualifiedCppName() << "\"," << endl
|
|
776 << " reinterpret_cast<QMetaType::Destructor>("
|
|
777 << destructorName
|
|
778 << ")," << endl
|
|
779 << " reinterpret_cast<QMetaType::Constructor>("
|
|
780 << constructorName
|
|
781 << "));" << endl;
|
|
782 } else {
|
|
783 // Look for default constructor, required for qRegisterMetaType
|
|
784 if (cls != 0) {
|
|
785 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::WasPublic | AbstractMetaClass::Constructors);
|
|
786
|
|
787 bool hasDefaultConstructor = false;
|
|
788 foreach (AbstractMetaFunction *function, functions) {
|
|
789 // Default constructor has to be present
|
|
790 if (function->wasPublic() && function->actualMinimumArgumentCount() == 0)
|
|
791 hasDefaultConstructor = true;
|
|
792 }
|
|
793
|
|
794 if (!hasDefaultConstructor) {
|
|
795 ReportHandler::warning(QString("Value type '%1' is missing a default constructor. "
|
|
796 "The resulting C++ code will not compile. If necessary, use <custom-constructor> and "
|
|
797 "<custom-destructor> tags to provide the constructors.").arg(cls->fullName()));
|
|
798 }
|
|
799
|
|
800 }
|
|
801 s << " qRegisterMetaType<" << entry->qualifiedCppName() << ">(\"" << entry->qualifiedCppName() << "\");" << endl;
|
|
802 }
|
|
803
|
|
804 }
|