diff options
author | Dominik Holland <dominik.holland@pelagicore.com> | 2018-10-16 11:21:27 +0200 |
---|---|---|
committer | Dominik Holland <dominik.holland@pelagicore.com> | 2018-10-29 10:47:51 +0000 |
commit | e65f8d9783de9b0f24719c8299bc69382c6e9a67 (patch) | |
tree | bea6f02a94978bb76aa685a565726ad3fc517870 | |
parent | 3c44b7c2e68bb8df12e7317c3e094732019cba2b (diff) |
Add a way to load and parse the data to the QIviSimulationEngine
The new loadSimulationData() function can load a JSON file and store
it's content in the IviSimulator singelton.
The IviSimulator singleton provides functions to interpret the JSON
values and other helpers e.g. checking for min/max/domain values.
Task-number: AUTOSUITE-629
Change-Id: I2832cc0b29379144845a8ed295fc2d988273ff0c
Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
-rw-r--r-- | src/ivicore/ivicore.pro | 6 | ||||
-rw-r--r-- | src/ivicore/qiviqmlconversion_helper.cpp | 70 | ||||
-rw-r--r-- | src/ivicore/qiviqmlconversion_helper.h | 2 | ||||
-rw-r--r-- | src/ivicore/qivisimulationengine.cpp | 22 | ||||
-rw-r--r-- | src/ivicore/qivisimulationengine.h | 7 | ||||
-rw-r--r-- | src/ivicore/qivisimulationglobalobject.cpp | 189 | ||||
-rw-r--r-- | src/ivicore/qivisimulationglobalobject_p.h | 85 | ||||
-rw-r--r-- | src/tools/ivigenerator/templates_frontend/struct.cpp.tpl | 27 | ||||
-rw-r--r-- | src/tools/ivigenerator/templates_frontend/struct.h.tpl | 7 |
9 files changed, 409 insertions, 6 deletions
diff --git a/src/ivicore/ivicore.pro b/src/ivicore/ivicore.pro index f0c640c..ead09d6 100644 --- a/src/ivicore/ivicore.pro +++ b/src/ivicore/ivicore.pro @@ -58,7 +58,8 @@ HEADERS += \ qivipendingreply_p.h \ qivisimulationengine.h \ qivisimulationproxy.h \ - qtivicoremodule.h + qtivicoremodule.h \ + qivisimulationglobalobject_p.h SOURCES += \ qiviservicemanager.cpp \ @@ -83,7 +84,8 @@ SOURCES += \ qivipendingreply.cpp \ qivisimulationengine.cpp \ qivisimulationproxy.cpp \ - qtivicoremodule.cpp + qtivicoremodule.cpp \ + qivisimulationglobalobject.cpp include(queryparser/queryparser.pri) diff --git a/src/ivicore/qiviqmlconversion_helper.cpp b/src/ivicore/qiviqmlconversion_helper.cpp index 66381b9..0372b6b 100644 --- a/src/ivicore/qiviqmlconversion_helper.cpp +++ b/src/ivicore/qiviqmlconversion_helper.cpp @@ -49,6 +49,13 @@ QT_BEGIN_NAMESPACE +namespace qtivi_helper { + static const QString valueLiteral = QStringLiteral("value"); + static const QString typeLiteral = QStringLiteral("type"); +} + +using namespace qtivi_helper; + void qtivi_qmlOrCppWarning(const QObject *obj, const char *errorString) { qtivi_qmlOrCppWarning(obj, QLatin1String(errorString)); @@ -84,4 +91,67 @@ void qtivi_qmlOrCppWarning(const QObject *obj, const QString &errorString) v4->throwError(errorString); } +QVariant convertFromJSON(const QVariant &val) +{ + QVariant value = val; + // First try to convert the values to a Map or a List + // This is needed as it could also store a QStringList or a Hash + if (value.canConvert(QVariant::Map)) + value.convert(QVariant::Map); + if (value.canConvert(QVariant::List)) + value.convert(QVariant::List); + + if (value.type() == QVariant::Map) { + const QVariantMap map = value.toMap(); + if (map.contains(typeLiteral) && map.contains(valueLiteral)) { + const QString type = map.value(typeLiteral).toString(); + const QVariant value = map.value(valueLiteral); + + if (type == QStringLiteral("enum")) { + QString enumValue = value.toString(); + const int lastIndex = enumValue.lastIndexOf(QStringLiteral("::")); + const QString className = enumValue.left(lastIndex - 1 ); + enumValue = enumValue.right(enumValue.count() - lastIndex - 2); + const QMetaObject *mo = QMetaType::metaObjectForType(QMetaType::type(className.toLatin1())); + if (!mo) + return QVariant(); + + for (int i = mo->enumeratorOffset(); i < mo->enumeratorCount(); ++i) { + QMetaEnum me = mo->enumerator(i); + bool ok = false; + int value = me.keysToValue(enumValue.toLatin1(), &ok); + if (ok) + return value; + } + qWarning() << "Couldn't parse the enum definition" << map; + return QVariant(); + } else { + int typeId = QMetaType::type(type.toLatin1()); + const QMetaObject *mo = QMetaType::metaObjectForType(typeId); + if (!mo) + return QVariant(); + + QVariantList values = value.toList(); + for (auto i = values.begin(); i != values.end(); ++i) + *i = convertFromJSON(*i); + + void *gadget = mo->newInstance(Q_ARG(QVariant, QVariant(values))); + return QVariant(typeId, gadget); + } + } + + QVariantMap convertedValues; + for (auto i = map.constBegin(); i != map.constEnd(); ++i) + convertedValues.insert(i.key(), convertFromJSON(i.value())); + return convertedValues; + } else if (value.type() == QVariant::List) { + QVariantList values = value.toList(); + for (auto i = values.begin(); i != values.end(); ++i) + *i = convertFromJSON(*i); + return values; + } + + return value; +} + QT_END_NAMESPACE diff --git a/src/ivicore/qiviqmlconversion_helper.h b/src/ivicore/qiviqmlconversion_helper.h index d6685ee..2c30772 100644 --- a/src/ivicore/qiviqmlconversion_helper.h +++ b/src/ivicore/qiviqmlconversion_helper.h @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE Q_QTIVICORE_EXPORT void qtivi_qmlOrCppWarning(const QObject *obj, const char *errorString); Q_QTIVICORE_EXPORT void qtivi_qmlOrCppWarning(const QObject *obj, const QString& errorString); +Q_QTIVICORE_EXPORT QVariant convertFromJSON(const QVariant &val); + template <typename T> QVariant qtivi_convertValue(const T &val) { QVariant var; diff --git a/src/ivicore/qivisimulationengine.cpp b/src/ivicore/qivisimulationengine.cpp index fa10d3b..69a0ddb 100644 --- a/src/ivicore/qivisimulationengine.cpp +++ b/src/ivicore/qivisimulationengine.cpp @@ -40,8 +40,13 @@ ****************************************************************************/ #include "qivisimulationengine.h" +#include <qivisimulationglobalobject_p.h> +#include <QDir> #include <QFile> +#include <QJsonDocument> +#include <QDebug> +#include <QQmlContext> QT_BEGIN_NAMESPACE @@ -216,7 +221,24 @@ QT_BEGIN_NAMESPACE QIviSimulationEngine::QIviSimulationEngine(QObject *parent) : QQmlApplicationEngine (parent) + , m_globalObject(new QIviSimulationGlobalObject) { + rootContext()->setContextProperty(QStringLiteral("IviSimulator"), m_globalObject); +} + +void QIviSimulationEngine::loadSimulationData(const QString &dataFile) +{ + if (!QFile::exists(dataFile)) + return; + + QFile file(QDir::current().absoluteFilePath(dataFile)); + if (file.open(QFile::ReadOnly)) { + QJsonParseError pe; + QJsonDocument document = QJsonDocument::fromJson(file.readAll(), &pe); + if (pe.error != QJsonParseError::NoError) + qCritical() << "Error parsing the provided simulation data: " << pe.errorString(); + m_globalObject->setSimulationData(document.toVariant()); + } } /*! diff --git a/src/ivicore/qivisimulationengine.h b/src/ivicore/qivisimulationengine.h index 9e23a4b..a79d269 100644 --- a/src/ivicore/qivisimulationengine.h +++ b/src/ivicore/qivisimulationengine.h @@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE +class QIviSimulationGlobalObject; + class Q_QTIVICORE_EXPORT QIviSimulationEngine : public QQmlApplicationEngine { Q_OBJECT @@ -59,11 +61,14 @@ public: { //pass engine here to check that it's only used in this engine qtivi_private::QIviSimulationProxy<T>::registerInstance(this, instance); - //@uri BridgetTest qmlRegisterType< qtivi_private::QIviSimulationProxy<T> >(uri, versionMajor, versionMinor, qmlName); } + void loadSimulationData(const QString &dataFile); void loadSimulation(const QUrl &file); + +private: + QIviSimulationGlobalObject *m_globalObject; }; QT_END_NAMESPACE diff --git a/src/ivicore/qivisimulationglobalobject.cpp b/src/ivicore/qivisimulationglobalobject.cpp new file mode 100644 index 0000000..c1b2161 --- /dev/null +++ b/src/ivicore/qivisimulationglobalobject.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtIvi module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite 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 The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: LGPL-3.0 +** +****************************************************************************/ + +#include "qivisimulationglobalobject_p.h" +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +namespace qtivi_helper { + static const QString unsupportedLiteral = QStringLiteral("unsupported"); + static const QString minLiteral = QStringLiteral("min"); + static const QString maxLiteral = QStringLiteral("max"); + static const QString domainLiteral = QStringLiteral("domain"); +} + +using namespace qtivi_helper; + +QIviSimulationGlobalObject::QIviSimulationGlobalObject(QObject *parent) + : QObject(parent) +{ +} + +QVariant QIviSimulationGlobalObject::simulationData() const +{ + return m_simulationData; +} + +void QIviSimulationGlobalObject::setSimulationData(const QVariant &simulationData) +{ + m_simulationData = simulationData; +} + +QVariantMap QIviSimulationGlobalObject::findData(const QVariantMap &data, const QString &interface) +{ + QString key = interface; + forever { + if (data.contains(key)) + return data.value(key).toMap(); + + int index = key.indexOf('.'); + if (index == -1) + break; + key = key.right(key.count() - index); + } + + return QVariantMap(); +} + +void QIviSimulationGlobalObject::initializeDefault(const QVariantMap &data, QObject *object) +{ + for (auto i = data.constBegin(); i != data.constEnd(); ++i) { + const QVariant defVal = defaultValue(i.value().toMap()); + if (defVal.isValid()) { + QVariant currentValue = object->property(i.key().toLatin1()); + if (QIviPagingModelInterface *model = currentValue.value<QIviPagingModelInterface*>()) { + QVariantList list = defVal.toList(); + for (auto i = list.crbegin(); i != list.crend(); ++i) + QMetaObject::invokeMethod(model, "insert", Q_ARG(int, 0), createArgument(*i)); + } else { + object->setProperty(i.key().toLatin1(), defVal); + } + } + + QVariant currentValue = object->property("zones"); + QQmlPropertyMap *map = currentValue.value<QQmlPropertyMap*>(); + if (!map) + continue; + const QStringList zones = data.value(QStringLiteral("zones")).toStringList(); + for (const QString &zone : zones) { + const QVariant defVal = defaultValue(i.value().toMap(), zone); + if (defVal.isValid()) { + QObject *zoneObject = map->value(zone).value<QObject*>(); + if (zoneObject) + zoneObject->setProperty(i.key().toLatin1(), defVal); + } + } + } +} + +QVariant QIviSimulationGlobalObject::defaultValue(const QVariantMap &data, const QString &zone) +{ + return parseDomainValue(data, QStringLiteral("default"), zone); +} + +QString QIviSimulationGlobalObject::constraint(const QVariantMap &data, const QString &zone) +{ + const QVariant unsupportedDomain = parseDomainValue(data, unsupportedLiteral, zone); + const QVariant minDomain = parseDomainValue(data, minLiteral, zone); + const QVariant maxDomain = parseDomainValue(data, maxLiteral, zone); + const QVariant domainDomain = parseDomainValue(data, domainLiteral, zone); + + if (unsupportedDomain.isValid()) + return unsupportedLiteral; + if (minDomain.isValid() && maxDomain.isValid()) + return QStringLiteral("[") + minDomain.toString() + QStringLiteral("-") + maxDomain.toString() + QStringLiteral("]") ; + if (minDomain.isValid()) + return QStringLiteral(">= ") + minDomain.toString(); + if (maxDomain.isValid()) + return QStringLiteral("<= ") + maxDomain.toString(); + if (domainDomain.isValid()) + return domainDomain.toString(); + + return QString(); +} + +bool QIviSimulationGlobalObject::checkSettings(const QVariantMap &data, const QVariant &value, const QString &zone) +{ + const QVariant unsupportedDomain = parseDomainValue(data, unsupportedLiteral, zone); + const QVariant minDomain = parseDomainValue(data, minLiteral, zone); + const QVariant maxDomain = parseDomainValue(data, maxLiteral, zone); + const QVariant domainDomain = parseDomainValue(data, domainLiteral, zone); + + if (unsupportedDomain.isValid()) + return unsupportedDomain.toBool(); + if (minDomain.isValid() && maxDomain.isValid()) + return !(value < minDomain || value > maxDomain); + if (minDomain.isValid()) + return value >= minDomain; + if (maxDomain.isValid()) + return value <= maxDomain; + if (domainDomain.isValid()) + return domainDomain.toList().contains(value); + + return true; +} + +QVariant QIviSimulationGlobalObject::parseDomainValue(const QVariantMap &data, const QString &domain, const QString &zone) +{ + if (!data.contains(domain)) + return QVariant(); + + const QVariant domainData = data.value(domain); + if (domainData.type() == QVariant::Map) { + const QVariantMap domainMap = domainData.toMap(); + QString z = zone; + if (zone.isEmpty()) + z = QStringLiteral("="); + + if (domainMap.contains(zone)) + return convertFromJSON(domainMap.value(zone)); + } + + return convertFromJSON(domainData); +} + +QGenericArgument QIviSimulationGlobalObject::createArgument(const QVariant &variant) +{ + return QGenericArgument(variant.typeName(), variant.data()); +} + +QT_END_NAMESPACE diff --git a/src/ivicore/qivisimulationglobalobject_p.h b/src/ivicore/qivisimulationglobalobject_p.h new file mode 100644 index 0000000..3ba9807 --- /dev/null +++ b/src/ivicore/qivisimulationglobalobject_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtIvi module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-QTAS$ +** Commercial License Usage +** Licensees holding valid commercial Qt Automotive Suite 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 The Qt Company. For +** licensing terms and conditions see https://www.qt.io/terms-conditions. +** For further information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: LGPL-3.0 +** +****************************************************************************/ + +#ifndef QIVISIMULATIONGLOBALOBJECT_P_H +#define QIVISIMULATIONGLOBALOBJECT_P_H + +#include <qiviqmlconversion_helper.h> +#include <QIviPagingModelInterface> + +#include <QtCore/QObject> +#include <QtCore/QVariantMap> +#include <QtCore/QMetaType> +#include <QtCore/QMetaObject> +#include <QtCore/QMetaEnum> +#include <QJSValue> +#include <QQmlPropertyMap> + +#include <QDebug> + +QT_BEGIN_NAMESPACE + +class QIviSimulationGlobalObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QVariant simulationData READ simulationData CONSTANT) + +public: + explicit QIviSimulationGlobalObject(QObject *parent = nullptr); + + QVariant simulationData() const; + void setSimulationData(const QVariant &simulationData); + + Q_INVOKABLE QVariantMap findData(const QVariantMap &data, const QString &interface); + Q_INVOKABLE void initializeDefault(const QVariantMap &data, QObject *object); + Q_INVOKABLE QVariant defaultValue(const QVariantMap &data, const QString &zone = QString()); + Q_INVOKABLE QString constraint(const QVariantMap &data, const QString &zone = QString()); + Q_INVOKABLE bool checkSettings(const QVariantMap &data, const QVariant &value, const QString &zone = QString()); + Q_INVOKABLE QVariant parseDomainValue(const QVariantMap &data, const QString &domain, const QString &zone = QString()); + +private: + QGenericArgument createArgument(const QVariant &variant); + QVariant m_simulationData; +}; + +QT_END_NAMESPACE + +#endif // QIVISIMULATIONGLOBALOBJECT_P_H diff --git a/src/tools/ivigenerator/templates_frontend/struct.cpp.tpl b/src/tools/ivigenerator/templates_frontend/struct.cpp.tpl index 43ec933..488f1a9 100644 --- a/src/tools/ivigenerator/templates_frontend/struct.cpp.tpl +++ b/src/tools/ivigenerator/templates_frontend/struct.cpp.tpl @@ -43,6 +43,8 @@ #include "{{class|lower}}.h" +#include <qiviqmlconversion_helper.h> + QT_BEGIN_NAMESPACE class {{class}}Private : public QSharedData @@ -105,6 +107,31 @@ public: { } +{{class}}::{{class}}(const QVariant &variant) + : {{class}}() +{ + QVariant value = convertFromJSON(variant); + // First try to convert the values to a Map or a List + // This is needed as it could also store a QStringList or a Hash + if (value.canConvert(QVariant::Map)) + value.convert(QVariant::Map); + if (value.canConvert(QVariant::List)) + value.convert(QVariant::List); + + if (value.type() == QVariant::Map) { + QVariantMap map = value.toMap(); +{% for field in struct.fields %} + if (map.contains(QStringLiteral("{{field}}"))) + d->m_{{field}} = map.value(QStringLiteral("{{field}}")).value<{{field|return_type}}>(); +{% endfor %} + } else if (value.type() == QVariant::List) { + QVariantList values = value.toList(); +{% for field in struct.fields %} + d->m_{{field}} = values.value({{loop.index0}}).value<{{field|return_type}}>(); +{% endfor %} + } +} + /*! \internal */ {{class}}::~{{class}}() { diff --git a/src/tools/ivigenerator/templates_frontend/struct.h.tpl b/src/tools/ivigenerator/templates_frontend/struct.h.tpl index ed85fef..da67518 100644 --- a/src/tools/ivigenerator/templates_frontend/struct.h.tpl +++ b/src/tools/ivigenerator/templates_frontend/struct.h.tpl @@ -71,10 +71,11 @@ class {{exportsymbol}} {{class}} : public QIviStandardItem {% endfor %} Q_CLASSINFO("IviPropertyDomains", "{{ struct.fields|json_domain|replace("\"", "\\\"") }}") public: - {{class}}(); - {{class}}(const {{class}} &rhs); + Q_INVOKABLE {{class}}(); + Q_INVOKABLE {{class}}(const {{class}} &rhs); {{class}} &operator=(const {{class}} &); - {{class}}({% for field in struct.fields %}{% if not loop.first %}, {% endif %}{{field|return_type}} {{field}}{% endfor %}); + Q_INVOKABLE {{class}}({% for field in struct.fields %}{% if not loop.first %}, {% endif %}{{field|return_type}} {{field}}{% endfor %}); + Q_INVOKABLE {{class}}(const QVariant &variant); ~{{class}}(); QString type() const override; |