summaryrefslogtreecommitdiffstats
path: root/src/wrappedobjects/qxmireader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wrappedobjects/qxmireader.cpp')
-rw-r--r--src/wrappedobjects/qxmireader.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/wrappedobjects/qxmireader.cpp b/src/wrappedobjects/qxmireader.cpp
new file mode 100644
index 00000000..3cb93787
--- /dev/null
+++ b/src/wrappedobjects/qxmireader.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Sandro S. Andrade <sandroandrade@kde.org>
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtWrappedObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 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 the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qxmireader.h"
+#include "qxmireader_p.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QStack>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QCoreApplication>
+
+#include <QtWrappedObjects/QWrappedObject>
+#include <QtWrappedObjects/QMetaModelPlugin>
+#include <QtWrappedObjects/QMetaWrappedObject>
+
+QT_BEGIN_NAMESPACE
+
+QXmiReaderPrivate::QXmiReaderPrivate()
+{
+}
+
+QXmiReaderPrivate::~QXmiReaderPrivate()
+{
+}
+
+QXmiReader::QXmiReader(QObject *parent) :
+ QObject(*new QXmiReaderPrivate, parent)
+{
+ loadPlugins();
+}
+
+QXmiReader::~QXmiReader()
+{
+}
+
+void QXmiReader::loadPlugins()
+{
+ Q_D(QXmiReader);
+
+ d->metaModelPlugins.clear();
+ QMetaModelPlugin *metaModelPlugin = 0;
+ foreach (QString pluginPath, QCoreApplication::libraryPaths()) {
+ QDir pluginsDir(pluginPath);
+ pluginsDir.cd(QString::fromLatin1("metamodels"));
+ foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
+ QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+ QObject *plugin = loader.instance();
+ if (plugin && (metaModelPlugin = qobject_cast<QMetaModelPlugin *>(plugin)))
+ d->metaModelPlugins.insert(metaModelPlugin->metaModelNamespaceUri(), metaModelPlugin);
+ }
+ }
+}
+
+QWrappedObject *QXmiReader::readFile(QIODevice *device)
+{
+ Q_D(QXmiReader);
+
+ d->errors.clear();
+ d->reader.setDevice(device);
+ QWrappedObject *rootElement = 0;
+
+ while (!d->reader.atEnd()) {
+ d->reader.readNext();
+
+ if (d->reader.isStartElement()) {
+ foreach (const QXmlStreamNamespaceDeclaration &namespaceDeclaration, d->reader.namespaceDeclarations()) {
+ QMetaModelPlugin *metaModelPlugin = d->metaModelPlugins.value(namespaceDeclaration.namespaceUri().toString());
+ if (metaModelPlugin)
+ metaModelPlugin->initMetaModel();
+ else
+ d->errors << QString::fromLatin1("Could not find metamodel for namespace URI '%1'").arg(namespaceDeclaration.namespaceUri().toString());
+ }
+ QString xmiType = d->reader.attributes().value(QString::fromLatin1("xmi:type")).toString().split(':').last();
+ if (xmiType.isEmpty() && d->reader.namespaceUri() == QString::fromLatin1("http://www.omg.org/spec/UML/20110701"))
+ xmiType = d->reader.name().toString();
+ if (xmiType.isEmpty())
+ continue;
+ QString instanceName = d->reader.attributes().value(QString::fromLatin1("name")).toString();
+ if (instanceName.isEmpty())
+ instanceName = d->reader.attributes().value(QString::fromLatin1("xmi:id")).toString();
+ QWrappedObject *wrappedObject = createInstance(xmiType.prepend(QString::fromLatin1("Q")).append(QString::fromLatin1("*")), instanceName);
+ if (wrappedObject) {
+ d->idMap.insert(d->reader.attributes().value(QString::fromLatin1("xmi:id")).toString(), wrappedObject);
+ if (!rootElement)
+ rootElement = wrappedObject;
+ }
+ else
+ d->errors << QString::fromLatin1("Could not create instance with id '%1' and type '%2'. Corresponding metamodel loaded ?").arg(instanceName).arg(xmiType);
+ }
+ }
+
+ device->reset();
+ d->reader.clear();
+ d->reader.setDevice(device);
+ QStack<QPair<QString, QWrappedObject *>> stack;
+
+ while (!d->reader.atEnd()) {
+ d->reader.readNext();
+
+ if (d->reader.isStartElement()) {
+ QString id = d->reader.attributes().value(QString::fromLatin1("xmi:id")).toString();
+ if (id.isEmpty())
+ id = d->reader.attributes().value(QString::fromLatin1("xmi:idref")).toString();
+ if (id.isEmpty())
+ id = d->reader.attributes().value(QString::fromLatin1("href")).toString();
+ if (id.isEmpty() && !stack.isEmpty())
+ continue;
+
+ QWrappedObject *wrappedObject = d->idMap.value(id);
+
+ if (wrappedObject) {
+ const QMetaWrappedObject *metaWrappedObject = wrappedObject->metaWrappedObject();
+ foreach (QXmlStreamAttribute attribute, d->reader.attributes()) {
+ int propertyIndex;
+ if ((propertyIndex = metaWrappedObject->indexOfProperty(attribute.name().toString().toLatin1())) != -1) {
+ QMetaPropertyInfo metaPropertyInfo = metaWrappedObject->property(propertyIndex);
+ QMetaProperty metaProperty = metaPropertyInfo.metaProperty;
+ if (metaProperty.type() == QVariant::Bool) {
+ if (!wrappedObject->setProperty(attribute.name().toString().toLatin1(), attribute.value().toString() == QString::fromLatin1("true") ? true:false))
+ d->errors << QString::fromLatin1("Error when setting property '%1' of object with id '%2'.").arg(attribute.name().toString()).arg(id);
+ }
+ else if (metaProperty.isEnumType()) {
+ if (!wrappedObject->setProperty(attribute.name().toString().toLatin1(), QString::fromLatin1(metaProperty.enumerator().valueToKey(attribute.value().toString().toInt())).toLower().remove(QString::fromLatin1(metaProperty.name())).toLatin1()))
+ d->errors << QString::fromLatin1("Error when setting property '%1' of object with id '%2'.").arg(attribute.name().toString()).arg(id);
+ }
+ else if (metaProperty.type() == QVariant::String) {
+ if (!wrappedObject->setProperty(attribute.name().toString().toLatin1(), attribute.value().toString()))
+ d->errors << QString::fromLatin1("Error when setting property '%1' of object with id '%2'.").arg(attribute.name().toString()).arg(id);
+ }
+ }
+ else
+ d->errors << QString::fromLatin1("Property '%1' not found in object of type '%2'. Corresponding metamodel loaded ?").arg(attribute.name().toString()).arg(QString::fromLatin1(wrappedObject->metaObject()->className()));
+ }
+ if (!stack.isEmpty()) {
+ QWrappedObject *containerObject = stack.top().second;
+ QString elementName = d->reader.name().toString();
+ elementName = elementName.left(1).toUpper() + elementName.mid(1);
+ int methodCount = containerObject->metaObject()->methodCount();
+ int i;
+ for (i = 0; i < methodCount; ++i) {
+ QMetaMethod metaMethod = containerObject->metaObject()->method(i);
+ if (QString::fromLatin1(metaMethod.name()) == QString::fromLatin1("add%1").arg(elementName) ||
+ QString::fromLatin1(metaMethod.name()) == QString::fromLatin1("set%1").arg(elementName)) {
+ if (!metaMethod.invoke(containerObject, ::Q_ARG(QWrappedObject *, wrappedObject)))
+ d->errors << QString::fromLatin1("Error when invoking metamethod '%1' on object '%2'.").arg(QString::fromLatin1(metaMethod.name())).arg(containerObject->objectName());
+ break;
+ }
+ }
+ if (i == methodCount)
+ d->errors << QString::fromLatin1("Metamethod add/set'%1' not found on object '%2'.").arg(elementName).arg(containerObject->objectName());
+ }
+ stack.push(QPair<QString, QWrappedObject *>(d->reader.name().toString(), wrappedObject));
+ }
+ else
+ d->errors << QString::fromLatin1("Could not cross reference instance with id '%1' in element '%2'. Bad formed XMI file ?").arg(id).arg(d->reader.name().toString());
+ }
+ else if (d->reader.isEndElement() && !stack.isEmpty() && stack.top().first == d->reader.name()) {
+ stack.pop();
+ }
+ }
+
+ return rootElement;
+}
+
+QWrappedObject *QXmiReader::createInstance(QString instanceClass, QString instanceName)
+{
+ int type;
+ if ((type = QMetaType::type(instanceClass.toLatin1())) != QMetaType::UnknownType) {
+ const QMetaObject *metaObject = QMetaType::metaObjectForType(type);
+ if (metaObject) {
+ QWrappedObject *wrappedObject = dynamic_cast<QWrappedObject *>(metaObject->newInstance());
+ if (wrappedObject) {
+ qTopLevelWrapper(wrappedObject)->setObjectName(instanceName);
+ return wrappedObject;
+ }
+ }
+ }
+ return 0;
+}
+
+QStringList QXmiReader::errorStrings() const
+{
+ Q_D(const QXmiReader);
+
+ return d->errors;
+}
+
+#include "moc_qxmireader.cpp"
+
+QT_END_NAMESPACE