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
|
|
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 }
|