diff options
Diffstat (limited to 'src/modeling')
-rw-r--r-- | src/modeling/modeling.pro | 20 | ||||
-rw-r--r-- | src/modeling/qmetamodelplugin.cpp (renamed from src/modeling/qwrappedobject.cpp) | 21 | ||||
-rw-r--r-- | src/modeling/qmetamodelplugin.h | 73 | ||||
-rw-r--r-- | src/modeling/qtmodelingglobal.h | 43 | ||||
-rw-r--r-- | src/modeling/qtmodelingnamespace.h | 12 | ||||
-rw-r--r-- | src/modeling/qwrappedobject.h | 246 | ||||
-rw-r--r-- | src/modeling/qxmireader.cpp | 317 | ||||
-rw-r--r-- | src/modeling/qxmireader.h | 84 | ||||
-rw-r--r-- | src/modeling/qxmireader_p.h | 80 | ||||
-rw-r--r-- | src/modeling/qxmiwriter.cpp | 287 | ||||
-rw-r--r-- | src/modeling/qxmiwriter.h | 83 | ||||
-rw-r--r-- | src/modeling/qxmiwriter_p.h | 81 |
12 files changed, 1079 insertions, 268 deletions
diff --git a/src/modeling/modeling.pro b/src/modeling/modeling.pro index 4fef7dbd..7c56cf48 100644 --- a/src/modeling/modeling.pro +++ b/src/modeling/modeling.pro @@ -1,17 +1,29 @@ load(qt_build_config) TARGET = QtModeling -QT = core core-private +QT = core-private QMAKE_DOCS = $$PWD/doc/qtmodeling.qdocconf load(qt_module) -HEADERS += \ +PUBLIC_HEADERS += \ qtmodelingglobal.h \ qtmodelingnamespace.h \ - qmodelingobject.h + qmodelingobject.h \ + qmetamodelplugin.h \ + qxmiwriter.h \ + qxmireader.h + +PRIVATE_HEADERS += \ + qxmiwriter_p.h \ + qxmireader_p.h SOURCES += \ qtmodelingnamespace.cpp \ - qmodelingobject.cpp + qmodelingobject.cpp \ + qmetamodelplugin.cpp \ + qxmiwriter.cpp \ + qxmireader.cpp + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/src/modeling/qwrappedobject.cpp b/src/modeling/qmetamodelplugin.cpp index 1f265a1a..69677943 100644 --- a/src/modeling/qwrappedobject.cpp +++ b/src/modeling/qmetamodelplugin.cpp @@ -38,29 +38,16 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "qwrappedobject.h" +#include "qmetamodelplugin.h" QT_BEGIN_NAMESPACE -QWrappedObject::QWrappedObject(QWrappedObject *wrapper, QObject *parent) : - QObject(*new QWrappedObjectPrivate, parent) +QMetaModelPlugin::QMetaModelPlugin(QObject *parent) + : QObject(parent) { - setWrapper(wrapper); } -QWrappedObject::~QWrappedObject() -{ - Q_D(QWrappedObject); - qDeleteAll(d->wrappedObjects); -} - -QWrappedObject::QWrappedObject(QWrappedObjectPrivate &dd, QWrappedObject *wrapper, QObject *parent) : - QObject(dd, parent) -{ - setWrapper(wrapper); -} - -#include "moc_qwrappedobject.cpp" +#include "moc_qmetamodelplugin.cpp" QT_END_NAMESPACE diff --git a/src/modeling/qmetamodelplugin.h b/src/modeling/qmetamodelplugin.h new file mode 100644 index 00000000..16ea2c08 --- /dev/null +++ b/src/modeling/qmetamodelplugin.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTMODELING_QMETAMODELPLUGIN_H +#define QTMODELING_QMETAMODELPLUGIN_H + +#include <QtModeling/QtModelingGlobal> + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(QtModeling) + +class QScriptEngine; +class QModelingObject; + +class Q_MODELING_EXPORT QMetaModelPlugin : public QObject +{ + Q_OBJECT + +public: + explicit QMetaModelPlugin(QObject *parent = 0); + + virtual void initMetaModel(QScriptEngine *scriptEngine = 0) = 0; + virtual QModelingObject *createModelingObject(QString type) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTMODELING_QMETAMODELPLUGIN_H + diff --git a/src/modeling/qtmodelingglobal.h b/src/modeling/qtmodelingglobal.h index c1f40d20..809531ed 100644 --- a/src/modeling/qtmodelingglobal.h +++ b/src/modeling/qtmodelingglobal.h @@ -43,6 +43,9 @@ #include <QtCore/QtGlobal> #include <QtCore/QVariant> +#include <QtScript/QScriptValue> +#include <QtScript/QScriptEngine> +#include <QtScript/QScriptValueIterator> QT_BEGIN_NAMESPACE @@ -63,7 +66,45 @@ class QModelingObject; template<class T> T qmodelingobjectproperty_cast(const QObject *object) { - return object->property("modelingObject").value<T>(); + return object ? object->property("modelingObject").value<T>():T(); +} + +template <class T> +QScriptValue qSetToScriptValue(QScriptEngine *engine, const QSet<T *> &elements) +{ + QScriptValue array = engine->newArray(); + foreach (T *element, elements) + array.property(QString::fromLatin1("push")).call(array, QScriptValueList() << engine->newQObject(element)); + return array; +} + +template <class T> +void scriptValueToQSet(const QScriptValue &obj, QSet<T *> &elements) +{ + QScriptValueIterator it(obj); + while (it.hasNext()) { + it.next(); + elements.insert(qobject_cast<T *>(it.value().toQObject())); + } +} + +template <class T> +QScriptValue qListToScriptValue(QScriptEngine *engine, const QList<T *> &elements) +{ + QScriptValue array = engine->newArray(); + foreach (T *element, elements) + array.property(QString::fromLatin1("push")).call(array, QScriptValueList() << engine->newQObject(element)); + return array; +} + +template <class T> +void scriptValueToQList(const QScriptValue &obj, QList<T *> &elements) +{ + QScriptValueIterator it(obj); + while (it.hasNext()) { + it.next(); + elements.append(qobject_cast<T *>(it.value().toQObject())); + } } #endif // QTMODELINGGLOBAL_H diff --git a/src/modeling/qtmodelingnamespace.h b/src/modeling/qtmodelingnamespace.h index 1c9459a8..e6f76bb0 100644 --- a/src/modeling/qtmodelingnamespace.h +++ b/src/modeling/qtmodelingnamespace.h @@ -56,6 +56,7 @@ class Q_MODELING_EXPORT QtModeling : public QObject Q_OBJECT Q_ENUMS(MetaPropertyDataRole) + Q_ENUMS(ModelingObjectRole) public: enum MetaPropertyDataRole @@ -72,12 +73,23 @@ public: UserRole = 0x0100 }; + enum ModelingObjectRole + { + ModelElementRole = 0, + ImportedElementRole, + ImportedPackageRole, + AppliedProfileRole + }; + private: explicit QtModeling(); }; QT_END_NAMESPACE +Q_DECLARE_METATYPE (QT_PREPEND_NAMESPACE(QtModeling::MetaPropertyDataRole)) +Q_DECLARE_METATYPE (QT_PREPEND_NAMESPACE(QtModeling::ModelingObjectRole)) + QT_END_HEADER #endif // QTMODELINGNAMESPACE_H diff --git a/src/modeling/qwrappedobject.h b/src/modeling/qwrappedobject.h deleted file mode 100644 index cf2d273d..00000000 --- a/src/modeling/qwrappedobject.h +++ /dev/null @@ -1,246 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtModeling module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, 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, Digia gives you certain additional -** rights. These rights are described in the Digia 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QWRAPPEDOBJECT_H -#define QWRAPPEDOBJECT_H - -#include <QtModeling/QtModelingGlobal> - -#include <QtCore/QObject> -#include "private/qobject_p.h" - -#include <QtCore/QSet> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(QtModeling) - -#define Q_WRAPPEDOBJECT_REGISTRY \ - QHash<QString, QWrappedObject *> &wrappedObjectsRegistry = this->wrappedObjectsRegistry(); \ - QWrappedObject *wrappedObject; - -#define Q_WRAP_OBJECT(className) \ - wrappedObject = wrappedObjectsRegistry.value(QStringLiteral(#className)); \ - if (!wrappedObject) { \ - wrappedObject = new className(this, parent); \ - wrappedObjectsRegistry.insert(QStringLiteral(#className), wrappedObject); \ - } \ - wrappedObject->setWrapper(this) - -#define Q_DERIVEDUNION_CONNECTION(subsetting, subsetted) \ - QObject::connect(&subsetting, SIGNAL(objectInserted(QObject*)), &subsetted, SLOT(insert(QObject*))); \ - QObject::connect(&subsetting, SIGNAL(objectRemoved(QObject*)), &subsetted, SLOT(remove(QObject*))); - -class QWrappedObjectPrivate; - -class Q_MODELING_EXPORT QWrappedObject : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QWrappedObject) - -public: - explicit QWrappedObject(QWrappedObject *wrapper, QObject *parent = 0); - - virtual ~QWrappedObject(); - - inline QWrappedObject *wrapper() const; - inline void setWrapper(QWrappedObject *wrapper); - inline QList<QPointer<QWrappedObject> > &wrappedObjects(); - - inline void setObjectName(const QString &name) - { - QObject::setObjectName(name); - foreach (QWrappedObject *wrapped, wrappedObjects()) - wrapped->setObjectName(name); - } - -// template <class T> -// inline const T *as() const; - - template <class T> - inline T *as(); - -// template <class T> -// inline const T *privateAs() const; - - template <class T> - inline T *privateAs(); - -protected: - explicit QWrappedObject(QWrappedObjectPrivate &dd, QWrappedObject *wrapper = 0, QObject *parent = 0); - inline QHash<QString, QWrappedObject *> &wrappedObjectsRegistry(); - -private: - inline void initialize(QWrappedObject *wrapper); -}; - -template <class T> -inline T qwrappedobject_cast(QWrappedObject *base, bool restoreToWrapper = true) -{ - if (!base) - return T(); // invalid pointer - while (restoreToWrapper && base->wrapper()) - base = base->wrapper(); - if (dynamic_cast<T>(base)) - return dynamic_cast<T>(base); - foreach (QWrappedObject *wrappedObject, base->wrappedObjects()) { - T returnValue = qwrappedobject_cast<T>(wrappedObject, false); - if (returnValue != T()) - return returnValue; - } - return T(); // not found -} - -template <class T> -inline T qwrappedobject_cast(const QWrappedObject *base, bool restoreToWrapper = true) -{ - return qwrappedobject_cast<T>(const_cast<QWrappedObject *>(base), restoreToWrapper); -} - -//template <class T> -//inline const T *QWrappedObject::QWrappedObject::as() const -//{ -// return qwrappedobject_cast<T *>(this); -//} - -template <class T> -inline T *QWrappedObject::QWrappedObject::as() -{ - return qwrappedobject_cast<T *>(this); -} - -//template <class T> -//inline const T *QWrappedObject::QWrappedObject::privateAs() const -//{ -// Q_D(const QWrappedObject); -// return qwrappedobject_cast<T *>(d); -//} - -template <class T> -inline T *QWrappedObject::QWrappedObject::privateAs() -{ - Q_D(QWrappedObject); - return qwrappedobject_cast<T *>(d); -} - -inline QWrappedObject *qTopLevelWrapper(QWrappedObject *wrapped) -{ - if (!wrapped) - return 0; - while (wrapped->wrapper()) - wrapped = wrapped->wrapper(); - return wrapped; -} - -class Q_MODELING_EXPORT QWrappedObjectPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QWrappedObject) - -public: - explicit QWrappedObjectPrivate() : wrapper(0) { } - - inline static QWrappedObjectPrivate *get(QWrappedObject *o) - { - return dynamic_cast<QWrappedObjectPrivate *>(o->d_func()); - } - - QWrappedObject *wrapper; - QList< QPointer<QWrappedObject> > wrappedObjects; - QHash<QString, QWrappedObject *>wrappedObjectsRegistry; -}; - -template <class T> -inline T qwrappedobject_cast(QWrappedObjectPrivate *base, bool restoreToWrapper = true) -{ - if (!base) - return T(); // invalid pointer - while (restoreToWrapper && base->wrapper) - base = QWrappedObjectPrivate::get(base->wrapper); - if (dynamic_cast<T>(base)) - return dynamic_cast<T>(base); - foreach (QWrappedObject *wrappedObject, base->wrappedObjects) { - T returnValue = qwrappedobject_cast<T>(QWrappedObjectPrivate::get(wrappedObject), false); - if (returnValue != T()) - return returnValue; - } - return T(); // not found -} - -template <class T> -inline T qwrappedobject_cast(const QWrappedObjectPrivate *base, bool restoreToWrapper = true) -{ - return qwrappedobject_cast<T>(const_cast<QWrappedObjectPrivate *>(base), restoreToWrapper); -} - -inline QWrappedObject *QWrappedObject::wrapper() const -{ - Q_D(const QWrappedObject); - return d->wrapper; -} - -inline void QWrappedObject::setWrapper(QWrappedObject *wrapper) -{ - Q_D(QWrappedObject); - if (wrapper) { - d->wrapper = wrapper; - QList< QPointer<QWrappedObject> > &wrappedObjects = wrapper->d_func()->wrappedObjects; - if (!wrappedObjects.contains(this)) - wrappedObjects.append(this); - } -} - -inline QList< QPointer<QWrappedObject> > &QWrappedObject::wrappedObjects() -{ - Q_D(QWrappedObject); - return d->wrappedObjects; -} - -inline QHash<QString, QWrappedObject *> &QWrappedObject::wrappedObjectsRegistry() -{ - return qTopLevelWrapper(this)->d_func()->wrappedObjectsRegistry; -} - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QWRAPPEDOBJECT_H diff --git a/src/modeling/qxmireader.cpp b/src/modeling/qxmireader.cpp new file mode 100644 index 00000000..58b938ec --- /dev/null +++ b/src/modeling/qxmireader.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxmireader.h" +#include "qxmireader_p.h" +#include "qmetamodelplugin.h" + +#include <QtModeling/QtModelingNamespace> + +#include <QtCore/QDir> +#include <QtCore/QUrl> +#include <QtCore/QStack> +#include <QtCore/QJsonObject> +#include <QtCore/QPluginLoader> +#include <QtCore/QMetaProperty> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +QXmiReaderPrivate::QXmiReaderPrivate() +{ +} + +QXmiReaderPrivate::~QXmiReaderPrivate() +{ +} + +QXmiReader::QXmiReader(QScriptEngine *scriptEngine, bool initMetaModel, QObject *parent) : + QObject(*new QXmiReaderPrivate, parent) +{ + Q_D(QXmiReader); + d->scriptEngine = scriptEngine; + d->initMetaModel = initMetaModel; + 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(loader.metaData().value(QString::fromLatin1("MetaData")).toObject().value(QString::fromLatin1("MetaModelNamespaceUri")).toString(), QPair<QMetaModelPlugin *, QJsonObject>(metaModelPlugin, loader.metaData().value(QString::fromLatin1("MetaData")).toObject())); + } + } +} + +QObjectList QXmiReader::readFile(QIODevice *device, QString importedId) +{ + Q_D(QXmiReader); + + if (importedId.isEmpty()) { + d->idMap.clear(); + d->errors.clear(); + d->xmlNamespaceToImplementationNamespace.clear(); + } + QXmlStreamReader reader; + reader.setDevice(device); + QObjectList modelingObjectList; + QObject *rootElement = 0; + bool importedIdFound = false; + QStack<QString> idStack; + int insertPosition = 0; + + while (!reader.atEnd()) { + reader.readNext(); + + if (!importedId.isEmpty() && !importedIdFound && reader.attributes().value(QString::fromLatin1("xmi:id")).toString() != importedId) + continue; + + if (!importedId.isEmpty() && !importedIdFound) + importedIdFound = true; + + if (reader.isStartElement()) { + idStack.push(reader.name().toString()); + QString elementName = reader.name().toString(); + if (elementName == QString::fromLatin1("importedPackage") || elementName == QString::fromLatin1("importedElement") || elementName == QString::fromLatin1("appliedProfile")) { + QFile importFile(reader.attributes().value(QString::fromLatin1("href")).toString().split(QString::fromLatin1("#")).first()); + if (!importFile.open(QFile::ReadOnly | QFile::Text)) + d->errors << QString::fromLatin1("Could not open imported file '%1'").arg(importFile.fileName()); + QObjectList importList = readFile(&importFile, reader.attributes().value(QString::fromLatin1("href")).toString().split(QString::fromLatin1("#")).last()); + if (importList.count() > 0) { + if (elementName == QString::fromLatin1("importedPackage")) + importList.first()->setProperty("role", QtModeling::ImportedPackageRole); + else if (elementName == QString::fromLatin1("importedElement")) + importList.first()->setProperty("role", QtModeling::ImportedElementRole); + else if (elementName == QString::fromLatin1("appliedProfile")) + importList.first()->setProperty("role", QtModeling::AppliedProfileRole); + } + foreach (QObject *importedObject, importList) { + modelingObjectList.append(importedObject); + } + } + + foreach (const QXmlStreamNamespaceDeclaration &namespaceDeclaration, reader.namespaceDeclarations()) { + QMetaModelPlugin *metaModelPlugin = d->metaModelPlugins.value(namespaceDeclaration.namespaceUri().toString()).first; + if (metaModelPlugin) { + if (d->initMetaModel) + metaModelPlugin->initMetaModel(d->scriptEngine); + d->xmlNamespaceToImplementationNamespace.insert(namespaceDeclaration.prefix().toString(), d->metaModelPlugins.value(namespaceDeclaration.namespaceUri().toString()).second.value(QString::fromLatin1("MetaModelPrefix")).toString()); + } + else { + d->errors << QString::fromLatin1("Could not find metamodel for namespace URI '%1'").arg(namespaceDeclaration.namespaceUri().toString()); + } + } + QString xmiType = reader.attributes().value(QString::fromLatin1("xmi:type")).toString(); + if (xmiType.isEmpty() && reader.qualifiedName() != reader.name()) + xmiType = reader.qualifiedName().toString(); + if (xmiType.isEmpty() || d->xmlNamespaceToImplementationNamespace[xmiType.split(':').first()].isEmpty()) + continue; + xmiType = QString::fromLatin1("%1%2 *").arg(d->xmlNamespaceToImplementationNamespace[xmiType.split(':').first()]).arg(xmiType.split(':').last()); + QString instanceName = reader.attributes().value(QString::fromLatin1("name")).toString(); + if (instanceName.isEmpty()) + instanceName = reader.attributes().value(QString::fromLatin1("xmi:id")).toString(); + QObject *modelingObject = createInstance(xmiType, instanceName); + if (modelingObject) { + d->idMap.insert(reader.attributes().value(QString::fromLatin1("xmi:id")).toString(), modelingObject); + if (!rootElement) { + rootElement = modelingObject; + modelingObjectList.insert(insertPosition, rootElement); + } + } + else + d->errors << QString::fromLatin1("Could not create instance with id '%1' and type '%2'. Corresponding metamodel loaded ?").arg(instanceName).arg(xmiType); + } + else if (reader.isEndElement()) { + idStack.pop(); + if (idStack.isEmpty() && !importedId.isEmpty()) + break; + if (idStack.count() == 1 && importedId.isEmpty()) { + rootElement = 0; + ++insertPosition; + } + } + } + + importedIdFound = false; + + device->reset(); + reader.clear(); + reader.setDevice(device); + QStack< QPair<QString, QObject *> > stack; + + while (!reader.atEnd()) { + reader.readNext(); + + if (!importedId.isEmpty() && !importedIdFound && reader.attributes().value(QString::fromLatin1("xmi:id")).toString() != importedId) + continue; + + if (!importedId.isEmpty() && !importedIdFound) + importedIdFound = true; + + if (reader.isStartElement()) { + QString id = reader.attributes().value(QString::fromLatin1("xmi:id")).toString(); + if (id.isEmpty()) + id = reader.attributes().value(QString::fromLatin1("xmi:idref")).toString(); + if (id.isEmpty()) + id = reader.attributes().value(QString::fromLatin1("href")).toString().split(QString::fromLatin1("#")).last(); + if (id.isEmpty() && !stack.isEmpty()) + continue; + + QObject *modelingObject = d->idMap.value(id); + + if (modelingObject) { + const QMetaObject *metaObject = modelingObject->metaObject(); + foreach (QXmlStreamAttribute attribute, reader.attributes()) { + int propertyIndex; + if ((propertyIndex = metaObject->indexOfProperty(attribute.name().toString().toLatin1())) != -1) { + QMetaProperty metaProperty = metaObject->property(propertyIndex); + if (metaProperty.type() == QVariant::Bool) { + if (!modelingObject->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()) { + QString enumName = attribute.value().toString(); + enumName = enumName.left(1).toUpper() + enumName.mid(1); + QString propertyName = QString::fromLatin1(metaProperty.name()); + enumName.prepend(propertyName.left(1).toUpper() + propertyName.mid(1)); + if (!modelingObject->setProperty(attribute.name().toString().toLatin1(), enumName)) + 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 (!modelingObject->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 if (metaProperty.type() == QVariant::UserType) { + QObject *propertyObject = d->idMap.value(attribute.value().toString()); + if (propertyObject) { + QString elementName = attribute.name().toString(); + elementName = elementName.left(1).toUpper() + elementName.mid(1); + int methodCount = modelingObject->metaObject()->methodCount(); + int i; + for (i = 0; i < methodCount; ++i) { + QMetaMethod metaMethod = modelingObject->metaObject()->method(i); + if (QString::fromLatin1(metaMethod.name()) == QString::fromLatin1("set%1").arg(elementName)) { + if (!metaMethod.invoke(modelingObject, ::Q_ARG(QObject *, propertyObject))) + d->errors << QString::fromLatin1("Error when invoking metamethod '%1' on object '%2'.").arg(QString::fromLatin1(metaMethod.name())).arg(propertyObject->objectName()); + break; + } + } + if (i == methodCount) + d->errors << QString::fromLatin1("Metamethod add/set'%1' not found on object '%2'.").arg(elementName).arg(propertyObject->objectName()); + + } + } + } + else + d->errors << QString::fromLatin1("Property '%1' not found in object of type '%2'. Corresponding metamodel loaded ?").arg(attribute.name().toString()).arg(QString::fromLatin1(modelingObject->metaObject()->className())); + } + if (!stack.isEmpty()) { + QObject *containerObject = stack.top().second; + QString elementName = 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(QObject *, modelingObject))) + 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, QObject *>(reader.name().toString(), modelingObject)); + } + else + d->errors << QString::fromLatin1("Could not cross reference instance with id '%1' in element '%2'. Bad formed XMI file ?").arg(id).arg(reader.name().toString()); + } + else if (reader.isEndElement() && !stack.isEmpty() && stack.top().first == reader.name()) { + stack.pop(); + if (stack.isEmpty() && !importedId.isEmpty()) + break; + } + } + + return modelingObjectList; +} + +QObject *QXmiReader::createInstance(QString instanceClass, QString instanceName) +{ + int type; + if ((type = QMetaType::type(instanceClass.toLatin1())) != QMetaType::UnknownType) { + const QMetaObject *metaObject = QMetaType::metaObjectForType(type); + if (metaObject) { + QObject *modelingObject = dynamic_cast<QObject *>(metaObject->newInstance()); + if (modelingObject) { + modelingObject->setObjectName(instanceName); + return modelingObject; + } + } + } + return 0; +} + +QStringList QXmiReader::errorStrings() const +{ + Q_D(const QXmiReader); + + return d->errors; +} + +#include "moc_qxmireader.cpp" + +QT_END_NAMESPACE + diff --git a/src/modeling/qxmireader.h b/src/modeling/qxmireader.h new file mode 100644 index 00000000..8dea082f --- /dev/null +++ b/src/modeling/qxmireader.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTMODELING_QXMIREADER_H +#define QTMODELING_QXMIREADER_H + +#include <QtModeling/QtModelingGlobal> + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(QtModeling) + +class QIODevice; +class QObject; + +class QScriptEngine; +class QXmiReaderPrivate; + +class Q_MODELING_EXPORT QXmiReader : public QObject +{ + Q_OBJECT + + Q_DISABLE_COPY(QXmiReader) + Q_DECLARE_PRIVATE(QXmiReader) + +public: + explicit QXmiReader(QScriptEngine *scriptEngine = 0, bool initMetaModel = false, QObject *parent = 0); + virtual ~QXmiReader(); + + QObjectList readFile(QIODevice *device, QString importedId = QString::fromLatin1("")); + QStringList errorStrings() const; + +protected: + void loadPlugins(); + QObject *createInstance(QString instanceClass, QString instanceName); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTMODELING_QXMIREADER_H + diff --git a/src/modeling/qxmireader_p.h b/src/modeling/qxmireader_p.h new file mode 100644 index 00000000..966d5971 --- /dev/null +++ b/src/modeling/qxmireader_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTMODELING_QXMIREADER_P_H +#define QTMODELING_QXMIREADER_P_H + +#include "qtmodelingglobal.h" +#include "private/qobject_p.h" + +#include <QtCore/QStringList> +#include <QtCore/QXmlStreamReader> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(QtModeling) + +class QMetaModelPlugin; +class QScriptEngine; + +class Q_MODELING_EXPORT QXmiReaderPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QXmiReader) + +public: + explicit QXmiReaderPrivate(); + virtual ~QXmiReaderPrivate(); + + QHash<QString, QObject *> idMap; + QHash< QString, QPair<QMetaModelPlugin *, QJsonObject> > metaModelPlugins; + QHash<QString, QString> xmlNamespaceToImplementationNamespace; + QStringList errors; + QScriptEngine *scriptEngine; + bool initMetaModel; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTMODELING_QXMIREADER_P_H + diff --git a/src/modeling/qxmiwriter.cpp b/src/modeling/qxmiwriter.cpp new file mode 100644 index 00000000..17fb00e3 --- /dev/null +++ b/src/modeling/qxmiwriter.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qxmiwriter.h" +#include "qxmiwriter_p.h" +#include "qmetamodelplugin.h" + +#include <QtModeling/QModelingObject> + +#include <QtCore/QSet> +#include <QtCore/QDir> +#include <QtCore/QJsonObject> +#include <QtCore/QPluginLoader> +#include <QtCore/QMetaClassInfo> +#include <QtCore/QCoreApplication> +#include <QtCore/QRegularExpression> + +QT_BEGIN_NAMESPACE + +QXmiWriterPrivate::QXmiWriterPrivate(QObject *modelingObject) + : modelingObject(modelingObject) +{ + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(2); +} + +QXmiWriterPrivate::~QXmiWriterPrivate() +{ +} + +QXmiWriter::QXmiWriter(QObject *modelingObject, QObject *parent) : + QObject(*new QXmiWriterPrivate(modelingObject), parent) +{ + loadPlugins(); +} + +QXmiWriter::~QXmiWriter() +{ +} + +void QXmiWriter::loadPlugins() +{ + Q_D(QXmiWriter); + + 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(loader.metaData().value(QString::fromLatin1("MetaData")).toObject().value(QString::fromLatin1("MetaModelNamespaceUri")).toString(), QPair<QMetaModelPlugin *, QJsonObject>(metaModelPlugin, loader.metaData().value(QString::fromLatin1("MetaData")).toObject())); + } + } +} + +bool QXmiWriter::writeFile(QIODevice *device) +{ + Q_D(QXmiWriter); + d->writer.setDevice(device); + + d->writer.writeStartDocument(); + d->writer.writeStartElement(QString::fromLatin1("xmi:XMI")); + d->writer.writeNamespace(QString::fromLatin1("http://www.omg.org/spec/XMI/20110701"), QString::fromLatin1("xmi")); + + QString metaModelClassName = QString::fromLatin1(d->modelingObject->metaObject()->className()); + int pos = 2; + while (metaModelClassName[pos] == metaModelClassName[pos].toLower()) pos++; + QString metaModelImplementationNamespace = metaModelClassName.left(pos); + typedef QPair<QMetaModelPlugin *, QJsonObject> PluginData; + foreach (const PluginData &pair, d->metaModelPlugins.values()) { + if (pair.second.value(QString::fromLatin1("MetaModelPrefix")).toString() == metaModelImplementationNamespace) { + d->metaModelXmlNamespace = pair.second.value(QString::fromLatin1("MetaModelPrefix")).toString().mid(1).toLower(); + d->writer.writeNamespace(pair.second.value(QString::fromLatin1("MetaModelNamespaceUri")).toString(), d->metaModelXmlNamespace); + break; + } + } + + d->idMap.clear(); + d->idStack.clear(); + d->blacklistedOppositeEnds.clear(); + + d->visitedObjects.clear(); + populateIdMap(d->modelingObject); + d->visitedObjects.clear(); + writeObject(d->modelingObject); + + d->writer.writeEndDocument(); + return true; +} + +void QXmiWriter::populateIdMap(QObject *modelingObject, int index) +{ + Q_D(QXmiWriter); + + if (modelingObject->metaObject()->indexOfProperty("name") != -1) + d->idStack << modelingObject->property("name").toString(); + else + d->idStack << QString::fromLatin1(modelingObject->metaObject()->className()).remove(QString::fromLatin1(modelingObject->metaObject()->classInfo(modelingObject->metaObject()->indexOfClassInfo("MetaModelPrefix")).value())) + + QString::fromLatin1((index != -1) ? ".%1":"").arg(index); + d->idMap.insert(modelingObject, d->idStack.join(QString::fromLatin1("-"))); + d->visitedObjects.append(modelingObject); + + const QMetaObject *metaObject = modelingObject->metaObject(); + int propertyCount = metaObject->propertyCount(); + + for (int i = 0; i < propertyCount; ++i) { + QMetaProperty metaProperty = metaObject->property(i); + QString typeName = QString::fromLatin1(metaProperty.typeName()); + QVariant variant = metaProperty.read(modelingObject); + QString aggregationRole = QModelingObject::propertyData(metaProperty, QtModeling::AggregationRole).toString(); + + if (aggregationRole == QString::fromLatin1("composite")) + if (!QModelingObject::propertyData(metaProperty, QtModeling::OppositeEndRole).toString().isEmpty()) { + d->blacklistedOppositeEnds << QModelingObject::propertyData(metaProperty, QtModeling::OppositeEndRole).toString(); + } + + if (QModelingObject::propertyData(metaProperty, QtModeling::AggregationRole).toString() != QString::fromLatin1("composite")) + continue; + + if (typeName.endsWith('*') && qvariant_cast<QObject *>(variant)) + populateIdMap(qvariant_cast<QObject *>(variant), 0); + else if (typeName.contains(QString::fromLatin1("QSet")) && variant.isValid()) { + QSet<QObject *> elements = *(static_cast<QSet<QObject *> *>(variant.data())); + int i = 0; + foreach (QObject *objectElement, elements) { + if (!d->visitedObjects.contains(objectElement)) + populateIdMap(objectElement, i++); + } + } + else if (typeName.contains(QString::fromLatin1("QList")) && variant.isValid()) { + QList<QObject *> elements = *(static_cast<QList<QObject *> *>(variant.data())); + int i = 0; + foreach (QObject *objectElement, elements) { + if (!d->visitedObjects.contains(objectElement)) + populateIdMap(objectElement, i++); + } + } + } + + d->idStack.removeLast(); +} + +void QXmiWriter::writeObject(QObject *modelingObject, QString elementName) +{ + Q_D(QXmiWriter); + + if (d->visitedObjects.contains(modelingObject)) + return; + + d->visitedObjects.append(modelingObject); + + d->writer.writeStartElement(elementName.isEmpty() ? QString::fromLatin1(d->modelingObject->metaObject()->className()).split(QString::fromLatin1("::")).last().remove(QString::fromLatin1(modelingObject->metaObject()->classInfo(modelingObject->metaObject()->indexOfClassInfo("MetaModelPrefix")).value())).prepend(QString::fromLatin1("%1:").arg(d->metaModelXmlNamespace)) + : + elementName); + if (!elementName.isEmpty()) + d->writer.writeAttribute(QString::fromLatin1("xmi:type"), QString::fromLatin1(modelingObject->metaObject()->className()).remove(QString::fromLatin1(modelingObject->metaObject()->classInfo(modelingObject->metaObject()->indexOfClassInfo("MetaModelPrefix")).value())).prepend(QString::fromLatin1(modelingObject->metaObject()->classInfo(modelingObject->metaObject()->indexOfClassInfo("MetaModelPrefix")).value()).mid(1).toLower().append(QString::fromLatin1(":")))); + + const QMetaObject *metaObject = modelingObject->metaObject(); + int propertyCount = metaObject->propertyCount(); + + for (int i = propertyCount - 1; i >= 0; --i) { + QMetaProperty metaProperty = metaObject->property(i); + QVariant variant = metaProperty.read(modelingObject); + + if (!metaProperty.isStored() || QString::fromLatin1(metaProperty.name()) == QString::fromLatin1("objectName") || QModelingObject::propertyData(metaProperty, QtModeling::IsDerivedUnionRole).toBool()) + continue; + + if (metaProperty.type() == QVariant::String) { + QString value = variant.toString(); + if (!value.isEmpty()) + d->writer.writeAttribute(QString::fromLatin1(metaProperty.name()), value); + } + else if (metaProperty.type() == QVariant::Bool) { + //if (!metaProperty.isResettable() || (metaProperty.isResettable() && modelingObject->isPropertyModified(metaProperty))) + d->writer.writeAttribute(QString::fromLatin1(metaProperty.name()), QString::fromLatin1(variant.toBool() ? "true":"false")); + } + else if (metaProperty.isEnumType()) { + //if (!metaProperty.isResettable() || (metaProperty.isResettable() && modelingObject->isPropertyModified(metaProperty))) { + QMetaEnum metaEnum = metaProperty.enumerator(); + if (!QString::fromLatin1(metaEnum.key(variant.toInt())).isEmpty()) + d->writer.writeAttribute(QString::fromLatin1(metaProperty.name()), QString::fromLatin1(metaEnum.key(variant.toInt())).toLower().remove(QString::fromLatin1(metaProperty.name()))); + //} + } + } + + d->writer.writeAttribute(QString::fromLatin1("xmi:id"), d->idMap.value(modelingObject)); + for (int i = propertyCount - 1; i >= 0; --i) { + QMetaProperty metaProperty = metaObject->property(i); + + if (d->blacklistedOppositeEnds.contains(QString::fromLatin1("%1::%2").arg(QString::fromLatin1(metaObject->className())).arg(QString::fromLatin1(metaProperty.name()).remove(QRegularExpression(QString::fromLatin1("_$")))))) + continue; + + QString typeName = QString::fromLatin1(metaProperty.typeName()); + QVariant variant = metaProperty.read(modelingObject); + QString aggregationRole = QModelingObject::propertyData(metaProperty, QtModeling::AggregationRole).toString(); + QString modifiedPropertyName = QString::fromLatin1(metaProperty.name()).remove(QRegularExpression(QString::fromLatin1("_$"))).remove(QRegularExpression(QString::fromLatin1("s$"))).replace(QRegularExpression(QString::fromLatin1("ie$")), QString::fromLatin1("y")).replace(QRegularExpression(QString::fromLatin1("sse$")), QString::fromLatin1("ss")).replace(QRegularExpression(QString::fromLatin1("ice$")), QString::fromLatin1("ex")).replace(QRegularExpression(QString::fromLatin1("ce$")), QString::fromLatin1("x")); + + if (!metaProperty.isStored() || QModelingObject::propertyData(metaProperty, QtModeling::IsDerivedUnionRole).toBool()) + continue; + + if (typeName.endsWith('*') && qvariant_cast<QObject *>(variant)) { + if (aggregationRole == QString::fromLatin1("composite")) { + writeObject(qvariant_cast<QObject *>(variant), modifiedPropertyName); + } + else { + d->writer.writeStartElement(QString::fromLatin1(metaProperty.name())); + d->writer.writeAttribute(QString::fromLatin1("xmi:idref"), d->idMap.value(qvariant_cast<QObject *>(variant))); + d->writer.writeEndElement(); + } + } + else if (typeName.contains(QString::fromLatin1("QSet")) && variant.isValid()) { + QSet<QObject *> elements = *(static_cast<QSet<QObject *> *>(variant.data())); + if (aggregationRole == QString::fromLatin1("composite")) { + foreach (QObject *objectElement, elements) + writeObject(objectElement, modifiedPropertyName); + } + else { + foreach (QObject *objectElement, elements) { + d->writer.writeStartElement(QString::fromLatin1(metaProperty.name())); + d->writer.writeAttribute(QString::fromLatin1("xmi:idref"), d->idMap.value(objectElement)); + d->writer.writeEndElement(); + } + } + } + else if (typeName.contains(QString::fromLatin1("QList")) && variant.isValid()) { + QList<QObject *> elements = *(static_cast<QList<QObject *> *>(variant.data())); + if (aggregationRole == QString::fromLatin1("composite")) { + foreach (QObject *objectElement, elements) + writeObject(objectElement, modifiedPropertyName); + } + else { + foreach (QObject *objectElement, elements) { + d->writer.writeStartElement(QString::fromLatin1(metaProperty.name())); + d->writer.writeAttribute(QString::fromLatin1("xmi:idref"), d->idMap.value(objectElement)); + d->writer.writeEndElement(); + } + } + } + } + + d->writer.writeEndElement(); +} + +#include "moc_qxmiwriter.cpp" + +QT_END_NAMESPACE + diff --git a/src/modeling/qxmiwriter.h b/src/modeling/qxmiwriter.h new file mode 100644 index 00000000..93795e85 --- /dev/null +++ b/src/modeling/qxmiwriter.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTMODELING_QXMIWRITER_H +#define QTMODELING_QXMIWRITER_H + +#include <QtModeling/QtModelingGlobal> + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(QtModeling) + +class QIODevice; +class QObject; + +class QXmiWriterPrivate; + +class Q_MODELING_EXPORT QXmiWriter : public QObject +{ + Q_OBJECT + + Q_DISABLE_COPY(QXmiWriter) + Q_DECLARE_PRIVATE(QXmiWriter) + +public: + explicit QXmiWriter(QObject *modelingObject, QObject *parent = 0); + virtual ~QXmiWriter(); + + bool writeFile(QIODevice *device); + +protected: + void loadPlugins(); + void populateIdMap(QObject *modelingObject, int index = -1); + void writeObject(QObject *modelingObject, QString elementName = QStringLiteral("")); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTMODELING_QXMIWRITER_H + diff --git a/src/modeling/qxmiwriter_p.h b/src/modeling/qxmiwriter_p.h new file mode 100644 index 00000000..ae99d850 --- /dev/null +++ b/src/modeling/qxmiwriter_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Sandro S. Andrade <sandroandrade@kde.org> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtModeling module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QTMODELING_QXMIWRITER_P_H +#define QTMODELING_QXMIWRITER_P_H + +#include "qtmodelingglobal.h" +#include "private/qobject_p.h" + +#include <QtCore/QStringList> +#include <QtCore/QXmlStreamWriter> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(QtModeling) + +class QMetaModelPlugin; + +class Q_MODELING_EXPORT QXmiWriterPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QXmiWriter) + +public: + explicit QXmiWriterPrivate(QObject *modelingObject); + virtual ~QXmiWriterPrivate(); + + QObject *modelingObject; + QXmlStreamWriter writer; + QHash< QString, QPair<QMetaModelPlugin *, QJsonObject> > metaModelPlugins; + QObjectList visitedObjects; + QHash<QObject *, QString> idMap; + QStringList idStack; + QString metaModelXmlNamespace; + QStringList blacklistedOppositeEnds; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTMODELING_QXMIWRITER_P_H + |