Merge branch 'master' of git://labs.trolltech.com/qtscriptgenerator
[qtscriptgenerator/amarok.git] / generator / setupgenerator.cpp
blob622d0714128bd5b0da84ecfaceece20b593c7534
1 /****************************************************************************
2 **
3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 **
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file. Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** sales department at sales@trolltech.com.
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 ****************************************************************************/
24 #include "setupgenerator.h"
25 #include "reporthandler.h"
26 #include "fileout.h"
28 //#define Q_SCRIPT_LAZY_GENERATOR
30 void SetupGenerator::addClass(const AbstractMetaClass *cls)
32 packHash[cls->package()].append(cls);
35 void writeQtScriptQtBindingsLicense(QTextStream &stream);
37 static void writeIncludes(QTextStream &stream)
39 stream << "#include <QtScript/QScriptExtensionPlugin>" << endl
40 << "#include <QtScript/QScriptValue>" << endl
41 << "#include <QtScript/QScriptEngine>" << endl;
42 #ifdef Q_SCRIPT_LAZY_GENERATOR
43 stream << "#include <QtScript/QScriptClass>" << endl
44 << "#include <QtScript/QScriptString>" << endl;
45 #endif
46 stream << "#include <QtCore/QDebug>" << endl;
49 void writeInclude(QTextStream &stream, const Include &inc);
50 void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
51 QSet<QString> &registeredTypeNames);
52 bool hasDefaultConstructor(const AbstractMetaClass *meta_class);
54 void SetupGenerator::generate()
56 QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
57 while (pack.hasNext()) {
58 pack.next();
59 QList<const AbstractMetaClass*> list = pack.value();
60 if (list.isEmpty())
61 continue;
63 QString packName = pack.key();
64 QStringList components = packName.split(".");
65 if ((components.size() > 2) && (components.at(0) == "com")
66 && (components.at(1) == "trolltech")) {
67 // kill com.trolltech in key
68 components.removeAt(0);
69 components.removeAt(0);
71 packName.replace(".", "_");
72 FileOut file(m_out_dir + "/generated_cpp/" + packName + "/main.cpp");
73 QTextStream &s = file.stream;
75 if (FileOut::license)
76 writeQtScriptQtBindingsLicense(s);
78 writeIncludes(s);
79 s << endl;
80 foreach (const AbstractMetaClass *cls, list)
81 writeInclude(s, cls->typeEntry()->include());
82 s << endl;
84 // declare individual class creation functions
85 foreach (const AbstractMetaClass *cls, list) {
86 s << "QScriptValue qtscript_create_" << cls->name() << "_class(QScriptEngine *engine);" << endl;
88 s << endl;
90 // write table of class names
92 s << "static const char * const qtscript_" << packName << "_class_names[] = {" << endl;
93 bool needComma = false;
94 foreach (const AbstractMetaClass *cls, list) {
95 s << " ";
96 if (needComma)
97 s << ", ";
98 s << "\"" << cls->name() << "\"" << endl;
99 needComma = true;
101 s << "};" << endl << endl;
104 // write table of function pointers
106 s << "typedef QScriptValue (*QtBindingCreator)(QScriptEngine *engine);" << endl;
107 s << "static const QtBindingCreator qtscript_" << packName << "_class_functions[] = {" << endl;
108 bool needComma = false;
109 foreach (const AbstractMetaClass *cls, list) {
110 s << " ";
111 if (needComma)
112 s << ", ";
113 s << "qtscript_create_" << cls->name() << "_class" << endl;
114 needComma = true;
116 s << "};" << endl << endl;
119 #ifdef Q_SCRIPT_LAZY_GENERATOR
121 // declare meta-types
122 QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
123 foreach (const AbstractMetaClass *cls, list) {
124 if (cls->isNamespace())
125 continue;
126 QString name = cls->qualifiedCppName();
127 if (cls->typeEntry()->isValue() && ::hasDefaultConstructor(cls))
128 maybeDeclareMetaType(s, name, registeredTypeNames);
129 maybeDeclareMetaType(s, name + "*", registeredTypeNames);
131 s << endl;
132 // write table of metatype-ids
133 s << "static const int qtscript_" << packName << "_metatype_ids[] = {" << endl;
134 for (int i = 0; i < list.size(); ++i) {
135 const AbstractMetaClass *cls = list.at(i);
136 s << " ";
137 if (i > 0)
138 s << ", ";
139 if (cls->isNamespace()) {
140 s << "-1, -1";
141 } else {
142 QString name = cls->qualifiedCppName();
143 if (cls->typeEntry()->isValue() && ::hasDefaultConstructor(cls))
144 s << "qMetaTypeId<" << name << ">()";
145 else
146 s << "-1";
147 s << ", qMetaTypeId<" << name << "*>()";
149 s << endl;
151 s << "};" << endl << endl;
154 // write the fake prototype class
156 s << "class qtscript_" << packName << "_FakePrototype : public QScriptClass" << endl
157 << "{" << endl
158 << "public:" << endl
159 << " qtscript_" << packName << "_FakePrototype(QScriptEngine *engine)" << endl
160 << " : QScriptClass(engine) {}" << endl << endl
162 << " QueryFlags queryProperty(const QScriptValue &fake," << endl
163 << " const QScriptString &name, QueryFlags flags, uint *)" << endl
164 << " {" << endl
165 << " if (fake.prototype().isValid())" << endl
166 << " return 0;" << endl
167 << " int classIndex = fake.data().toInt32();" << endl
168 << " const char *className = qtscript_" << packName << "_class_names[classIndex];" << endl
169 // << " qDebug() << \"faking\" << className;" << endl
170 << " QScriptValue extensionObject = engine()->globalObject();" << endl
171 << " QScriptValue ctor = extensionObject.property(className);" << endl
172 << " QScriptValue genuine = ctor.property(\"prototype\");" << endl
173 << " Q_ASSERT(genuine.isObject());" << endl
174 << " const_cast<QScriptValue&>(fake).setPrototype(genuine);" << endl
175 << " if (!genuine.property(name).isValid())" << endl
176 << " flags &= ~HandlesReadAccess;" << endl
177 << " return flags & ~HandlesWriteAccess;" << endl
178 << " }" << endl << endl
180 << " QScriptValue property(const QScriptValue &fake, "
181 << "const QScriptString &name, uint)" << endl
182 << " {" << endl
183 << " return fake.prototype().property(name, QScriptValue::ResolveLocal);" << endl
184 << " }" << endl
185 << "};" << endl << endl;
188 // write the lazy class loader
190 s << "static QScriptValue qtscript_" << packName << "_getSetClass("
191 << "QScriptContext *context, QScriptEngine *engine)" << endl
192 << "{" << endl
193 << " QScriptValue target = context->thisObject();" << endl
194 << " int classIndex = context->callee().data().toInt32();" << endl
195 << " const char *className = qtscript_" << packName << "_class_names[classIndex];" << endl
196 << " qDebug() << \"loading\" << className;" << endl
197 << " target.setProperty(className, QScriptValue(), "
198 << "QScriptValue::PropertyGetter|QScriptValue::PropertySetter);" << endl
199 << " if (context->argumentCount() == 1) {" << endl
200 << " target.setProperty(className, context->argument(0));" << endl
201 << " } else {" << endl
202 << " target.setProperty(className, qtscript_"
203 << packName << "_class_functions[classIndex](engine)," << endl
204 << " QScriptValue::SkipInEnumeration);" << endl
205 << " }" << endl
206 << " return target.property(className);" << endl
207 << "}" << endl << endl;
209 #endif
211 // plugin class declaration
212 s << "class " << packName << "_ScriptPlugin : public QScriptExtensionPlugin" << endl
213 << "{" << endl
214 << "public:" << endl
215 << " QStringList keys() const;" << endl
216 << " void initialize(const QString &key, QScriptEngine *engine);" << endl
217 << "};" << endl
218 << "" << endl;
220 // keys()
221 s << "QStringList " << packName << "_ScriptPlugin::keys() const" << endl
222 << "{" << endl
223 << " QStringList list;" << endl;
225 QString key;
226 for (int i = 0; i < components.size(); ++i) {
227 if (i > 0)
228 key.append(".");
229 key.append(components.at(i));
230 s << " list << QLatin1String(\"" << key << "\");" << endl;
233 s << " return list;" << endl
234 << "}" << endl;
236 // initialize()
237 s << endl
238 << "void " << packName << "_ScriptPlugin::initialize(const QString &key, QScriptEngine *engine)" << endl
239 << "{";
241 QString key;
242 for (int i = 0; i < components.size(); ++i) {
243 s << endl << " ";
244 if (i > 0) {
245 key.append(".");
246 s << "} else ";
248 key.append(components.at(i));
249 s << "if (key == QLatin1String(\"" << key << "\")) {";
252 s << endl << " QScriptValue extensionObject = ";
253 // ### generalize
254 if (packName == "com.trolltech.qt.phonon")
255 s << "setupPackage(\"phonon\", engine)";
256 else
257 s << "engine->globalObject()";
258 s << ";" << endl;
260 #ifdef Q_SCRIPT_LAZY_GENERATOR
261 s << " qtscript_" << packName << "_FakePrototype *fakeProtoClass;" << endl
262 << " fakeProtoClass = new qtscript_" << packName << "_FakePrototype(engine);" << endl;
263 #endif
264 s << " for (int i = 0; i < " << list.size() << "; ++i) {" << endl
265 #ifndef Q_SCRIPT_LAZY_GENERATOR
266 << " extensionObject.setProperty(qtscript_" << packName << "_class_names[i]," << endl
267 << " qtscript_" << packName << "_class_functions[i](engine)," << endl
268 << " QScriptValue::SkipInEnumeration);" << endl
269 #else
270 << " QScriptValue classIndex(engine, i);" << endl
271 << " QScriptValue fakeCtor = engine->newFunction(qtscript_" << packName << "_getSetClass);" << endl
272 << " fakeCtor.setData(classIndex);" << endl
273 << " extensionObject.setProperty(qtscript_" << packName << "_class_names[i]," << endl
274 << " fakeCtor, QScriptValue::PropertyGetter|QScriptValue::PropertySetter"
275 << "|QScriptValue::SkipInEnumeration);" << endl
276 << " QScriptValue fakeProto = engine->newObject(fakeProtoClass, classIndex);" << endl
277 << " fakeProto.setPrototype(QScriptValue());" << endl
278 << " if (qtscript_" << packName << "_metatype_ids[i*2] != -1)" << endl
279 << " engine->setDefaultPrototype(qtscript_"
280 << packName << "_metatype_ids[i*2], fakeProto);" << endl
281 << " if (qtscript_" << packName << "_metatype_ids[i*2+1] != -1)" << endl
282 << " engine->setDefaultPrototype(qtscript_"
283 << packName << "_metatype_ids[i*2+1], fakeProto);" << endl
284 #endif
285 << " }" << endl;
287 s << " } else {" << endl
288 << " Q_ASSERT_X(false, \"" << packName << "::initialize\", qPrintable(key));" << endl
289 << " }" << endl
290 << "}" << endl;
292 s << "Q_EXPORT_STATIC_PLUGIN(" << packName << "_ScriptPlugin)" << endl
293 << "Q_EXPORT_PLUGIN2(qtscript_" << packName.toLower() << ", " << packName << "_ScriptPlugin)" << endl << endl;
295 if (file.done())
296 ++m_num_generated_written;
297 ++m_num_generated;