Mercurial > projects > qtd
diff generator/uiconverter.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generator/uiconverter.cpp Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2008 Nokia. All rights reserved. +** +** This file is part of Qt Jambi. +** +** * Commercial Usage +* Licensees holding valid Qt Commercial licenses may use this file in +* accordance with the Qt Commercial License Agreement provided with the +* Software or, alternatively, in accordance with the terms contained in +* a written agreement between you and Nokia. +* +* +* GNU General Public License Usage +* Alternatively, this file may be used under the terms of the GNU +* General Public License versions 2.0 or 3.0 as published by the Free +* Software Foundation and appearing in the file LICENSE.GPL included in +* the packaging of this file. Please review the following information +* to ensure GNU General Public Licensing requirements will be met: +* http://www.fsf.org/licensing/licenses/info/GPLv2.html and +* http://www.gnu.org/copyleft/gpl.html. In addition, as a special +* exception, Nokia gives you certain additional rights. These rights +* are described in the Nokia Qt GPL Exception version 1.2, included in +* the file GPL_EXCEPTION.txt in this package. +* +* Qt for Windows(R) Licensees +* As a special exception, Nokia, as the sole copyright holder for Qt +* Designer, grants users of the Qt/Eclipse Integration plug-in the +* right for the Qt/Eclipse Integration to link to functionality +* provided by Qt Designer and its related libraries. +* +* +* If you are unsure which license is appropriate for your use, please +* contact the sales department at qt-sales@nokia.com. + +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "uiconverter.h" +#include "metajava.h" + +#include "reporthandler.h" + +#include <QtCore/QFileInfo> +#include <QtXml/QDomDocument> + +void UiConverter::convertToJui(const QString &uiFile, const QString &customWidgetFiles) +{ + ReportHandler::setContext(QLatin1String("UiConverter to .jui")); + + traverseCustomWidgets(customWidgetFiles); + + QFileInfo fileInfo(uiFile); + + if (!fileInfo.exists()) { + ReportHandler::warning(QString::fromLatin1("Ui File %1 doesn't exist...\n").arg(uiFile)); + return; + } + + if (fileInfo.suffix() != QLatin1String("ui")) { + ReportHandler::warning(QString::fromLatin1("File doesn't have .ui extension: %1") + .arg(uiFile)); + return; + } + + QString juiFile = fileInfo.absolutePath() + QLatin1Char('/') + fileInfo.baseName() + + QLatin1String(".jui"); + + QFile inputFile(uiFile); + + if (!inputFile.open(QFile::ReadOnly | QFile::Text)) { + ReportHandler::warning(QString::fromLatin1("Could not open '%1' for reading").arg(uiFile)); + return; + } + + QDomDocument dom; + QString error; + if (!dom.setContent(&inputFile, false, &error)) { + ReportHandler::warning(QString::fromLatin1("Xml loading %1 failed: %2") + .arg(uiFile).arg(error)); + inputFile.close(); + return; + } + inputFile.close(); + + QDomNodeList customWidgets = dom.documentElement().elementsByTagName("customwidget"); + for (int i=0; i<customWidgets.size(); ++i) { + QDomNode customWidget = customWidgets.at(i); + + QDomElement el = customWidget.toElement(); + fixCustomWidgetNode(el, &dom); + } + + traverse(dom.documentElement(), &dom); + + QFile outputFile(juiFile); + if (!outputFile.open(QFile::WriteOnly | QFile::Text)) { + ReportHandler::warning(QString::fromLatin1("Could not open '%1' for writing") + .arg(juiFile)); + return; + } + + outputFile.write(dom.toByteArray()); + outputFile.close(); +} + +void UiConverter::traverseCustomWidgetFile(const QString &customWidgetFile) +{ + if (customWidgetFile.isEmpty()) + return; + + QFile file(customWidgetFile); + if (!file.open(QIODevice::ReadOnly)) { + ReportHandler::warning("Can't read custom widget file '" + + customWidgetFile + + "'"); + return; + } + + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == "qt-jambi-custom-widget") { + QXmlStreamAttributes attributes = reader.attributes(); + QString className = attributes.value("class").toString(); + + int pos = className.lastIndexOf("."); + m_custom_widgets.insertMulti(className.mid(pos+1), CustomWidget(className, 0)); + } + } + + if (reader.hasError()) { + ReportHandler::warning("Error when parsing custom widget file '" + + customWidgetFile + + "': " + + reader.errorString()); + } +} + +void UiConverter::traverseCustomWidgets(const QString &customWidgetFiles) +{ +#ifdef Q_OS_WIN32 + char separator = ';'; +#else + char separator = ':'; +#endif + + QStringList customWidgets = customWidgetFiles.split(separator); + foreach (QString customWidget, customWidgets) + traverseCustomWidgetFile(customWidget); +} + +void UiConverter::traverse(QDomNode node, QDomDocument *doc) +{ + if (node.isNull()) + return; + + QDomElement element = node.toElement(); + if (!element.isNull()) { + if (element.nodeName() == QLatin1String("ui")) + fixUiNode(element, doc); + else if (element.nodeName() == QLatin1String("set")) + fixSetNode(element, doc); + else if (element.nodeName() == QLatin1String("enum")) + fixEnumNode(element, doc); + else if (element.nodeName() == QLatin1String("connection")) + fixConnectionNode(element, doc); + else if (element.nodeName() == QLatin1String("widget")) + fixWidgetNode(element, doc); + } + + QDomNodeList list = node.childNodes(); + for (int i=0; i<list.size(); ++i) + traverse(list.at(i), doc); +} + + +void UiConverter::fixUiNode(QDomElement el, QDomDocument *) +{ + el.setAttribute("language", "jambi"); +} + +void UiConverter::fixCustomWidgetNode(QDomElement el, QDomDocument *) +{ + QDomNodeList classes = el.elementsByTagName("class"); + if (classes.size() < 1) { + ReportHandler::warning("Custom widget missing 'class' child"); + return; + } + + QDomNodeList extendss = el.elementsByTagName("extends"); + if (extendss.size() < 1) { + ReportHandler::warning("Custom widget missing 'extends' child"); + return; + } + + QString className = classes.at(0).toElement().text(); + QString extends = extendss.at(0).toElement().text(); + + AbstractMetaClass *javaClass = m_java_classes.findClass(extends); + if (javaClass == 0) { + ReportHandler::warning("Couldn't find super class for custom widget: '" + extends + "'"); + return; + } + + QList<CustomWidget> fullNames = m_custom_widgets.values(className); + if (fullNames.size() == 0) { + ReportHandler::warning("Couldn't find custom widget entry for '" + className + "'." + " You need to specify this class in a custom widget file and" + " pass the file name on the command line using the --custom-widgets option."); + return; + } + + if (fullNames.size() > 1) { + ReportHandler::warning("More than custom widget type matching '" + className + "'. " + + "Will use first seen entry: '" + fullNames.at(0).first + "'"); + } + + QString fullName = fullNames.at(0).first; + classes.at(0).namedItem("#text").toText().setData(fullName); + + QMap<QString, CustomWidget>::iterator it; + for (it=m_custom_widgets.begin(); it!=m_custom_widgets.end(); ++it) { + if (it.key() == className) + (*it).second = javaClass; + } +} + +void UiConverter::fixSetNode(QDomElement el, QDomDocument *) +{ + QStringList cppSet = el.firstChild().nodeValue().split(QLatin1Char('|')); + + QStringList javaSet; + for (int i=0; i<cppSet.size(); ++i) + javaSet << translateEnumValue(cppSet.at(i)); + + el.firstChild().setNodeValue(javaSet.join(QLatin1String("|"))); +} + + +void UiConverter::fixEnumNode(QDomElement el, QDomDocument *) +{ + QDomNode valueNode = el.firstChild(); + if (valueNode.isNull()) { + ReportHandler::warning(QString::fromLatin1("Bad enum value at '%1'").arg(el.nodeValue())); + return; + } + + QString cppEnumValue = valueNode.nodeValue(); + QString javaEnumValue = translateEnumValue(cppEnumValue); + valueNode.setNodeValue(javaEnumValue); +} + + +void UiConverter::fixConnectionNode(QDomElement el, QDomDocument *) +{ + QString senderName = el.namedItem("sender").firstChild().nodeValue(); + AbstractMetaClass *senderClass = m_named_widgets[senderName]; + if (!senderClass) { + ReportHandler::warning(QString::fromLatin1("sender unknown '%1'").arg(senderName)); + return; + } + QDomNode signalSignatureNode = el.namedItem("signal").toElement().firstChild(); + QString signalSignature = signalSignatureNode.nodeValue(); + const AbstractMetaFunction *signalFunction = findFunction(senderClass, + signalSignature, + SignalSearch); + if (!signalFunction) { + ReportHandler::warning(QString::fromLatin1("Signal not found '%1' in '%2'") + .arg(signalSignature).arg(senderClass->qualifiedCppName())); + return; + } + signalSignatureNode.setNodeValue(signalFunction->modifiedName()); + + QString receiverName = el.namedItem("receiver").firstChild().nodeValue(); + AbstractMetaClass *receiverClass = m_named_widgets[receiverName]; + if (!receiverClass) { + ReportHandler::warning(QString::fromLatin1("receiver unknown '%1'").arg(receiverName)); + return; + } + + QDomNode slotSignatureNode = el.namedItem("slot").firstChild(); + QString slotSignature = slotSignatureNode.nodeValue(); + const AbstractMetaFunction *slotFunction = findFunction(receiverClass, slotSignature, SlotSearch); + if (!signalFunction) { + ReportHandler::warning(QString::fromLatin1("Slot not found '%1' in '%2'") + .arg(slotSignature).arg(receiverClass->qualifiedCppName())); + return; + } + + slotSignatureNode.setNodeValue(slotFunction->targetLangSignature(true)); +} + + +void UiConverter::fixWidgetNode(QDomElement el, QDomDocument *) +{ + QString className = el.attribute(QLatin1String("class")); + QList<CustomWidget> customWidgetNames = m_custom_widgets.values(className); + QString customWidgetName = customWidgetNames.size() > 0 ? customWidgetNames.at(0).first : QString(); + + AbstractMetaClass *javaClass = customWidgetName.isEmpty() ? m_java_classes.findClass(className) : customWidgetNames.at(0).second; + if (!javaClass) { + ReportHandler::warning(QString::fromLatin1("Class '%1' is unknown").arg(className)); + return; + } + + if (!customWidgetName.isEmpty()) + el.setAttribute(QLatin1String("class"), customWidgetName); + else if (javaClass->package() != QLatin1String("qt.gui")) + el.setAttribute(QLatin1String("class"), javaClass->fullName()); + + m_named_widgets.insert(el.attribute(QLatin1String("name")), javaClass); +} + + +QString UiConverter::translateEnumValue(const QString &cppEnumValue) { + if (!cppEnumValue.contains(QLatin1String("::"))) { + ReportHandler::warning(QString::fromLatin1("Expected '::' in enum value '%1'") + .arg(cppEnumValue)); + return QString(); + } + + QStringList names = cppEnumValue.split(QLatin1String("::")); + AbstractMetaClass *javaClass = m_java_classes.findClass(names.at(0)); + + if (!javaClass) { + ReportHandler::warning(QString::fromLatin1("Class '%1' is unknown").arg(names.at(0))); + return QString(); + } + + AbstractMetaEnum *javaEnum = javaClass->findEnumForValue(names.at(1)); + if (!javaEnum) { + ReportHandler::warning(QString::fromLatin1("Enum value '%1' was not found in '%2'") + .arg(names.at(1)).arg(names.at(0))); + return QString(); + } + + AbstractMetaEnumValueList enumValues = javaEnum->values(); + AbstractMetaEnumValue *enumValue = enumValues.find(names.at(1)); + int value = enumValue->value(); + + if (javaEnum->typeEntry()->isEnumValueRejected(enumValue->name())) { + for (int i=0; i<enumValues.size(); ++i) { + AbstractMetaEnumValue *ev = enumValues.at(i); + if (ev->value() == value) { + enumValue = ev; + break; + } + } + } + + return javaEnum->fullName() + QLatin1String(".") + enumValue->name(); +} + +const AbstractMetaFunction *UiConverter::findFunction(AbstractMetaClass *javaClass, + const QString &signature, + SearchType type) +{ + AbstractMetaFunctionList senderFunctions = javaClass->functions(); + foreach (const AbstractMetaFunction *f, senderFunctions) { + if (type == SignalSearch && !f->isSignal()) + continue; + + QString fsig = f->minimalSignature(); + + + int pos = 0; + while (pos < signature.length() + && fsig.constData()[pos] == signature.constData()[pos]) ++pos; + + if (pos == signature.length() + || (type == SignalSearch + && pos == signature.length() - 1 + && signature.constData()[pos] == QLatin1Char(')'))) { + return f; + } + } + + return 0; +}