Mercurial > projects > qtd
comparison generator/uiconverter.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children |
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 "uiconverter.h" | |
43 #include "metajava.h" | |
44 | |
45 #include "reporthandler.h" | |
46 | |
47 #include <QtCore/QFileInfo> | |
48 #include <QtXml/QDomDocument> | |
49 | |
50 void UiConverter::convertToJui(const QString &uiFile, const QString &customWidgetFiles) | |
51 { | |
52 ReportHandler::setContext(QLatin1String("UiConverter to .jui")); | |
53 | |
54 traverseCustomWidgets(customWidgetFiles); | |
55 | |
56 QFileInfo fileInfo(uiFile); | |
57 | |
58 if (!fileInfo.exists()) { | |
59 ReportHandler::warning(QString::fromLatin1("Ui File %1 doesn't exist...\n").arg(uiFile)); | |
60 return; | |
61 } | |
62 | |
63 if (fileInfo.suffix() != QLatin1String("ui")) { | |
64 ReportHandler::warning(QString::fromLatin1("File doesn't have .ui extension: %1") | |
65 .arg(uiFile)); | |
66 return; | |
67 } | |
68 | |
69 QString juiFile = fileInfo.absolutePath() + QLatin1Char('/') + fileInfo.baseName() | |
70 + QLatin1String(".jui"); | |
71 | |
72 QFile inputFile(uiFile); | |
73 | |
74 if (!inputFile.open(QFile::ReadOnly | QFile::Text)) { | |
75 ReportHandler::warning(QString::fromLatin1("Could not open '%1' for reading").arg(uiFile)); | |
76 return; | |
77 } | |
78 | |
79 QDomDocument dom; | |
80 QString error; | |
81 if (!dom.setContent(&inputFile, false, &error)) { | |
82 ReportHandler::warning(QString::fromLatin1("Xml loading %1 failed: %2") | |
83 .arg(uiFile).arg(error)); | |
84 inputFile.close(); | |
85 return; | |
86 } | |
87 inputFile.close(); | |
88 | |
89 QDomNodeList customWidgets = dom.documentElement().elementsByTagName("customwidget"); | |
90 for (int i=0; i<customWidgets.size(); ++i) { | |
91 QDomNode customWidget = customWidgets.at(i); | |
92 | |
93 QDomElement el = customWidget.toElement(); | |
94 fixCustomWidgetNode(el, &dom); | |
95 } | |
96 | |
97 traverse(dom.documentElement(), &dom); | |
98 | |
99 QFile outputFile(juiFile); | |
100 if (!outputFile.open(QFile::WriteOnly | QFile::Text)) { | |
101 ReportHandler::warning(QString::fromLatin1("Could not open '%1' for writing") | |
102 .arg(juiFile)); | |
103 return; | |
104 } | |
105 | |
106 outputFile.write(dom.toByteArray()); | |
107 outputFile.close(); | |
108 } | |
109 | |
110 void UiConverter::traverseCustomWidgetFile(const QString &customWidgetFile) | |
111 { | |
112 if (customWidgetFile.isEmpty()) | |
113 return; | |
114 | |
115 QFile file(customWidgetFile); | |
116 if (!file.open(QIODevice::ReadOnly)) { | |
117 ReportHandler::warning("Can't read custom widget file '" | |
118 + customWidgetFile | |
119 + "'"); | |
120 return; | |
121 } | |
122 | |
123 QXmlStreamReader reader(&file); | |
124 while (!reader.atEnd()) { | |
125 reader.readNext(); | |
126 if (reader.isStartElement() && reader.name() == "qt-jambi-custom-widget") { | |
127 QXmlStreamAttributes attributes = reader.attributes(); | |
128 QString className = attributes.value("class").toString(); | |
129 | |
130 int pos = className.lastIndexOf("."); | |
131 m_custom_widgets.insertMulti(className.mid(pos+1), CustomWidget(className, 0)); | |
132 } | |
133 } | |
134 | |
135 if (reader.hasError()) { | |
136 ReportHandler::warning("Error when parsing custom widget file '" | |
137 + customWidgetFile | |
138 + "': " | |
139 + reader.errorString()); | |
140 } | |
141 } | |
142 | |
143 void UiConverter::traverseCustomWidgets(const QString &customWidgetFiles) | |
144 { | |
145 #ifdef Q_OS_WIN32 | |
146 char separator = ';'; | |
147 #else | |
148 char separator = ':'; | |
149 #endif | |
150 | |
151 QStringList customWidgets = customWidgetFiles.split(separator); | |
152 foreach (QString customWidget, customWidgets) | |
153 traverseCustomWidgetFile(customWidget); | |
154 } | |
155 | |
156 void UiConverter::traverse(QDomNode node, QDomDocument *doc) | |
157 { | |
158 if (node.isNull()) | |
159 return; | |
160 | |
161 QDomElement element = node.toElement(); | |
162 if (!element.isNull()) { | |
163 if (element.nodeName() == QLatin1String("ui")) | |
164 fixUiNode(element, doc); | |
165 else if (element.nodeName() == QLatin1String("set")) | |
166 fixSetNode(element, doc); | |
167 else if (element.nodeName() == QLatin1String("enum")) | |
168 fixEnumNode(element, doc); | |
169 else if (element.nodeName() == QLatin1String("connection")) | |
170 fixConnectionNode(element, doc); | |
171 else if (element.nodeName() == QLatin1String("widget")) | |
172 fixWidgetNode(element, doc); | |
173 } | |
174 | |
175 QDomNodeList list = node.childNodes(); | |
176 for (int i=0; i<list.size(); ++i) | |
177 traverse(list.at(i), doc); | |
178 } | |
179 | |
180 | |
181 void UiConverter::fixUiNode(QDomElement el, QDomDocument *) | |
182 { | |
183 el.setAttribute("language", "jambi"); | |
184 } | |
185 | |
186 void UiConverter::fixCustomWidgetNode(QDomElement el, QDomDocument *) | |
187 { | |
188 QDomNodeList classes = el.elementsByTagName("class"); | |
189 if (classes.size() < 1) { | |
190 ReportHandler::warning("Custom widget missing 'class' child"); | |
191 return; | |
192 } | |
193 | |
194 QDomNodeList extendss = el.elementsByTagName("extends"); | |
195 if (extendss.size() < 1) { | |
196 ReportHandler::warning("Custom widget missing 'extends' child"); | |
197 return; | |
198 } | |
199 | |
200 QString className = classes.at(0).toElement().text(); | |
201 QString extends = extendss.at(0).toElement().text(); | |
202 | |
203 AbstractMetaClass *javaClass = m_java_classes.findClass(extends); | |
204 if (javaClass == 0) { | |
205 ReportHandler::warning("Couldn't find super class for custom widget: '" + extends + "'"); | |
206 return; | |
207 } | |
208 | |
209 QList<CustomWidget> fullNames = m_custom_widgets.values(className); | |
210 if (fullNames.size() == 0) { | |
211 ReportHandler::warning("Couldn't find custom widget entry for '" + className + "'." | |
212 " You need to specify this class in a custom widget file and" | |
213 " pass the file name on the command line using the --custom-widgets option."); | |
214 return; | |
215 } | |
216 | |
217 if (fullNames.size() > 1) { | |
218 ReportHandler::warning("More than custom widget type matching '" + className + "'. " | |
219 + "Will use first seen entry: '" + fullNames.at(0).first + "'"); | |
220 } | |
221 | |
222 QString fullName = fullNames.at(0).first; | |
223 classes.at(0).namedItem("#text").toText().setData(fullName); | |
224 | |
225 QMap<QString, CustomWidget>::iterator it; | |
226 for (it=m_custom_widgets.begin(); it!=m_custom_widgets.end(); ++it) { | |
227 if (it.key() == className) | |
228 (*it).second = javaClass; | |
229 } | |
230 } | |
231 | |
232 void UiConverter::fixSetNode(QDomElement el, QDomDocument *) | |
233 { | |
234 QStringList cppSet = el.firstChild().nodeValue().split(QLatin1Char('|')); | |
235 | |
236 QStringList javaSet; | |
237 for (int i=0; i<cppSet.size(); ++i) | |
238 javaSet << translateEnumValue(cppSet.at(i)); | |
239 | |
240 el.firstChild().setNodeValue(javaSet.join(QLatin1String("|"))); | |
241 } | |
242 | |
243 | |
244 void UiConverter::fixEnumNode(QDomElement el, QDomDocument *) | |
245 { | |
246 QDomNode valueNode = el.firstChild(); | |
247 if (valueNode.isNull()) { | |
248 ReportHandler::warning(QString::fromLatin1("Bad enum value at '%1'").arg(el.nodeValue())); | |
249 return; | |
250 } | |
251 | |
252 QString cppEnumValue = valueNode.nodeValue(); | |
253 QString javaEnumValue = translateEnumValue(cppEnumValue); | |
254 valueNode.setNodeValue(javaEnumValue); | |
255 } | |
256 | |
257 | |
258 void UiConverter::fixConnectionNode(QDomElement el, QDomDocument *) | |
259 { | |
260 QString senderName = el.namedItem("sender").firstChild().nodeValue(); | |
261 AbstractMetaClass *senderClass = m_named_widgets[senderName]; | |
262 if (!senderClass) { | |
263 ReportHandler::warning(QString::fromLatin1("sender unknown '%1'").arg(senderName)); | |
264 return; | |
265 } | |
266 QDomNode signalSignatureNode = el.namedItem("signal").toElement().firstChild(); | |
267 QString signalSignature = signalSignatureNode.nodeValue(); | |
268 const AbstractMetaFunction *signalFunction = findFunction(senderClass, | |
269 signalSignature, | |
270 SignalSearch); | |
271 if (!signalFunction) { | |
272 ReportHandler::warning(QString::fromLatin1("Signal not found '%1' in '%2'") | |
273 .arg(signalSignature).arg(senderClass->qualifiedCppName())); | |
274 return; | |
275 } | |
276 signalSignatureNode.setNodeValue(signalFunction->modifiedName()); | |
277 | |
278 QString receiverName = el.namedItem("receiver").firstChild().nodeValue(); | |
279 AbstractMetaClass *receiverClass = m_named_widgets[receiverName]; | |
280 if (!receiverClass) { | |
281 ReportHandler::warning(QString::fromLatin1("receiver unknown '%1'").arg(receiverName)); | |
282 return; | |
283 } | |
284 | |
285 QDomNode slotSignatureNode = el.namedItem("slot").firstChild(); | |
286 QString slotSignature = slotSignatureNode.nodeValue(); | |
287 const AbstractMetaFunction *slotFunction = findFunction(receiverClass, slotSignature, SlotSearch); | |
288 if (!signalFunction) { | |
289 ReportHandler::warning(QString::fromLatin1("Slot not found '%1' in '%2'") | |
290 .arg(slotSignature).arg(receiverClass->qualifiedCppName())); | |
291 return; | |
292 } | |
293 | |
294 slotSignatureNode.setNodeValue(slotFunction->targetLangSignature(true)); | |
295 } | |
296 | |
297 | |
298 void UiConverter::fixWidgetNode(QDomElement el, QDomDocument *) | |
299 { | |
300 QString className = el.attribute(QLatin1String("class")); | |
301 QList<CustomWidget> customWidgetNames = m_custom_widgets.values(className); | |
302 QString customWidgetName = customWidgetNames.size() > 0 ? customWidgetNames.at(0).first : QString(); | |
303 | |
304 AbstractMetaClass *javaClass = customWidgetName.isEmpty() ? m_java_classes.findClass(className) : customWidgetNames.at(0).second; | |
305 if (!javaClass) { | |
306 ReportHandler::warning(QString::fromLatin1("Class '%1' is unknown").arg(className)); | |
307 return; | |
308 } | |
309 | |
310 if (!customWidgetName.isEmpty()) | |
311 el.setAttribute(QLatin1String("class"), customWidgetName); | |
312 else if (javaClass->package() != QLatin1String("qt.gui")) | |
313 el.setAttribute(QLatin1String("class"), javaClass->fullName()); | |
314 | |
315 m_named_widgets.insert(el.attribute(QLatin1String("name")), javaClass); | |
316 } | |
317 | |
318 | |
319 QString UiConverter::translateEnumValue(const QString &cppEnumValue) { | |
320 if (!cppEnumValue.contains(QLatin1String("::"))) { | |
321 ReportHandler::warning(QString::fromLatin1("Expected '::' in enum value '%1'") | |
322 .arg(cppEnumValue)); | |
323 return QString(); | |
324 } | |
325 | |
326 QStringList names = cppEnumValue.split(QLatin1String("::")); | |
327 AbstractMetaClass *javaClass = m_java_classes.findClass(names.at(0)); | |
328 | |
329 if (!javaClass) { | |
330 ReportHandler::warning(QString::fromLatin1("Class '%1' is unknown").arg(names.at(0))); | |
331 return QString(); | |
332 } | |
333 | |
334 AbstractMetaEnum *javaEnum = javaClass->findEnumForValue(names.at(1)); | |
335 if (!javaEnum) { | |
336 ReportHandler::warning(QString::fromLatin1("Enum value '%1' was not found in '%2'") | |
337 .arg(names.at(1)).arg(names.at(0))); | |
338 return QString(); | |
339 } | |
340 | |
341 AbstractMetaEnumValueList enumValues = javaEnum->values(); | |
342 AbstractMetaEnumValue *enumValue = enumValues.find(names.at(1)); | |
343 int value = enumValue->value(); | |
344 | |
345 if (javaEnum->typeEntry()->isEnumValueRejected(enumValue->name())) { | |
346 for (int i=0; i<enumValues.size(); ++i) { | |
347 AbstractMetaEnumValue *ev = enumValues.at(i); | |
348 if (ev->value() == value) { | |
349 enumValue = ev; | |
350 break; | |
351 } | |
352 } | |
353 } | |
354 | |
355 return javaEnum->fullName() + QLatin1String(".") + enumValue->name(); | |
356 } | |
357 | |
358 const AbstractMetaFunction *UiConverter::findFunction(AbstractMetaClass *javaClass, | |
359 const QString &signature, | |
360 SearchType type) | |
361 { | |
362 AbstractMetaFunctionList senderFunctions = javaClass->functions(); | |
363 foreach (const AbstractMetaFunction *f, senderFunctions) { | |
364 if (type == SignalSearch && !f->isSignal()) | |
365 continue; | |
366 | |
367 QString fsig = f->minimalSignature(); | |
368 | |
369 | |
370 int pos = 0; | |
371 while (pos < signature.length() | |
372 && fsig.constData()[pos] == signature.constData()[pos]) ++pos; | |
373 | |
374 if (pos == signature.length() | |
375 || (type == SignalSearch | |
376 && pos == signature.length() - 1 | |
377 && signature.constData()[pos] == QLatin1Char(')'))) { | |
378 return f; | |
379 } | |
380 } | |
381 | |
382 return 0; | |
383 } |