Unverified Commit 2803796c authored by Don Gagne's avatar Don Gagne Committed by GitHub

Add support for new FactMetaData json values/bitmask formats. (#9148)

parent fd10ea55
......@@ -42,6 +42,16 @@ const char* FactMetaData::kDefaultGroup = QT_TRANSLATE_NOOP("FactMetaData", "
const char* FactMetaData::qgcFileType = "FactMetaData";
const char* FactMetaData::_jsonMetaDataDefinesName = "QGC.MetaData.Defines";
const char* FactMetaData::_jsonMetaDataFactsName = "QGC.MetaData.Facts";
const char* FactMetaData::_enumStringsJsonKey = "enumStrings";
const char* FactMetaData::_enumValuesJsonKey = "enumValues";
// This is the newer json format for enums and bitmasks. They are used by the new COMPONENT_INFORMATION parameter metadata for example.
const char* FactMetaData::_enumValuesArrayJsonKey = "values";
const char* FactMetaData::_enumBitmaskArrayJsonKey = "bitmask";
const char* FactMetaData::_enumValuesArrayValueJsonKey = "value";
const char* FactMetaData::_enumValuesArrayDescriptionJsonKey = "description";
const char* FactMetaData::_enumBitmaskArrayIndexJsonKey = "index";
const char* FactMetaData::_enumBitmaskArrayDescriptionJsonKey = "description";
// Built in translations for all Facts
const FactMetaData::BuiltInTranslation_s FactMetaData::_rgBuiltInTranslations[] = {
......@@ -707,7 +717,7 @@ void FactMetaData::setTranslators(Translator rawTranslator, Translator cookedTra
void FactMetaData::setBuiltInTranslator(void)
{
if (_enumStrings.count()) {
if (_enumStrings.count() || _bitmaskStrings.count()) {
// No translation if enum
setTranslators(_defaultTranslator, _defaultTranslator);
_cookedUnits = _rawUnits;
......@@ -1249,6 +1259,10 @@ FactMetaData* FactMetaData::createFromJsonObject(const QJsonObject& json, QMap<Q
{ _categoryJsonKey, QJsonValue::String, false },
{ _groupJsonKey, QJsonValue::String, false },
{ _volatileJsonKey, QJsonValue::Bool, false },
{ _enumBitmaskArrayJsonKey, QJsonValue::Array, false },
{ _enumValuesArrayJsonKey, QJsonValue::Array, false },
{ _enumValuesJsonKey, QJsonValue::String, false },
{ _enumStringsJsonKey, QJsonValue::String, false },
};
if (!JsonHelper::validateKeys(json, keyInfoList, errorString)) {
qWarning() << errorString;
......@@ -1266,23 +1280,45 @@ FactMetaData* FactMetaData::createFromJsonObject(const QJsonObject& json, QMap<Q
metaData->_name = json[_nameJsonKey].toString();
QStringList enumValues, enumStrings;
if (JsonHelper::parseEnum(json, defineMap, enumStrings, enumValues, errorString, metaData->name())) {
for (int i=0; i<enumValues.count(); i++) {
QVariant enumVariant;
QStringList rgDescriptions;
QList<double> rgDoubleValues;
QStringList rgStringValues;
bool foundBitmask = false;
if (!_parseValuesArray(json, rgDescriptions, rgDoubleValues, errorString)) {
qWarning() << QStringLiteral("FactMetaData::createFromJsonObject _parseValueDescriptionArray for %1 failed. %2").arg(metaData->_name).arg(errorString);
}
if (rgDescriptions.isEmpty()) {
if (!_parseBitmaskArray(json, rgDescriptions, rgDoubleValues, errorString)) {
qWarning() << QStringLiteral("FactMetaData::createFromJsonObject _parseBitmaskArray for %1 failed. %2").arg(metaData->_name).arg(errorString);
}
foundBitmask = rgDescriptions.count() != 0;
}
if (rgDescriptions.isEmpty()) {
if (!_parseEnum(json, defineMap, rgDescriptions, rgStringValues, errorString)) {
qWarning() << QStringLiteral("FactMetaData::createFromJsonObject _parseEnum for %1 failed. %2").arg(metaData->_name).arg(errorString);
}
}
if (errorString.isEmpty() && rgDescriptions.count()) {
for (int i=0; i<rgDescriptions.count(); i++) {
QVariant rawValueVariant = rgDoubleValues.count() ? QVariant(rgDoubleValues[i]) : QVariant(rgStringValues[i]);
QVariant convertedValueVariant;
QString errorString;
if (metaData->convertAndValidateRaw(enumValues[i], false /* validate */, enumVariant, errorString)) {
metaData->addEnumInfo(enumStrings[i], enumVariant);
if (foundBitmask) {
metaData->addBitmaskInfo(rgDescriptions[i], rawValueVariant);
} else {
if (metaData->convertAndValidateRaw(rawValueVariant, false /* validate */, convertedValueVariant, errorString)) {
metaData->addEnumInfo(rgDescriptions[i], convertedValueVariant);
} else {
qWarning() << "Invalid enum value, name:" << metaData->name()
qWarning() << QStringLiteral("FactMetaData::createFromJsonObject convertAndValidateRaw on enum value for %1 failed.").arg(metaData->_name)
<< " type:" << metaData->type()
<< " value:" << enumValues[i]
<< " value:" << rawValueVariant
<< " error:" << errorString;
}
}
} else {
qWarning() << errorString;
}
}
metaData->setDecimalPlaces(json[_decimalPlacesJsonKey].toInt(0));
......@@ -1470,3 +1506,105 @@ void FactMetaData::setVolatileValue(bool bValue)
_readOnly = true;
}
}
bool FactMetaData::_parseEnum(const QJsonObject& jsonObject, DefineMap_t defineMap, QStringList& rgDescriptions, QStringList& rgValues, QString& errorString)
{
rgDescriptions.clear();
rgValues.clear();
errorString.clear();
if (!jsonObject.contains(_enumStringsJsonKey)) {
return true;
}
QString strings = jsonObject.value(_enumStringsJsonKey).toString();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
rgDescriptions = defineMap.value(strings, strings).split(",", QString::SkipEmptyParts);
#else
rgDescriptions = defineMap.value(strings, strings).split(",", Qt::SkipEmptyParts);
#endif
QString values = jsonObject.value(_enumValuesJsonKey).toString();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
rgValues = defineMap.value(values, values).split(",", QString::SkipEmptyParts);
#else
rgValues = defineMap.value(values, values).split(",", Qt::SkipEmptyParts);
#endif
if (rgDescriptions.count() != rgValues.count()) {
errorString = QStringLiteral("Enum strings/values count mismatch - strings:values %1:%2").arg(rgDescriptions.count()).arg(rgValues.count());
return false;
}
return true;
}
bool FactMetaData::_parseValuesArray(const QJsonObject& jsonObject, QStringList& rgDescriptions, QList<double>& rgValues, QString& errorString)
{
rgDescriptions.clear();
rgValues.clear();
errorString.clear();
if (!jsonObject.contains(_enumValuesArrayJsonKey)) {
return true;
}
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ _enumValuesArrayDescriptionJsonKey, QJsonValue::String, true },
{ _enumValuesArrayValueJsonKey, QJsonValue::Double, true },
};
const QJsonArray& rgValueDescription = jsonObject[_enumValuesArrayJsonKey].toArray();
for (int i=0; i<rgValueDescription.count(); i++) {
if (rgValueDescription[i].type() != QJsonValue::Object) {
errorString = QStringLiteral("Value at index %1 in \"values\" array is not an object.").arg(i);
return false;
}
const QJsonObject& valueDescriptionObject = rgValueDescription[i].toObject();
if (!JsonHelper::validateKeys(valueDescriptionObject, keyInfoList, errorString)) {
errorString = QStringLiteral("Object at index %1 in \"values\" array failed validation '%2'.").arg(i).arg(errorString);
return false;
}
rgDescriptions.append(valueDescriptionObject[_enumValuesArrayDescriptionJsonKey].toString());
rgValues.append(valueDescriptionObject[_enumValuesArrayValueJsonKey].toDouble());
}
return true;
}
bool FactMetaData::_parseBitmaskArray(const QJsonObject& jsonObject, QStringList& rgDescriptions, QList<double>& rgValues, QString& errorString)
{
rgDescriptions.clear();
rgValues.clear();
errorString.clear();
if (!jsonObject.contains(_enumBitmaskArrayJsonKey)) {
return true;
}
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ _enumBitmaskArrayDescriptionJsonKey, QJsonValue::String, true },
{ _enumBitmaskArrayIndexJsonKey, QJsonValue::Double, true },
};
const QJsonArray& rgValueDescription = jsonObject[_enumBitmaskArrayJsonKey].toArray();
for (int i=0; i<rgValueDescription.count(); i++) {
if (rgValueDescription[i].type() != QJsonValue::Object) {
errorString = QStringLiteral("Value at index %1 in \"values\" array is not an object.").arg(i);
return false;
}
const QJsonObject& valueDescriptionObject = rgValueDescription[i].toObject();
if (!JsonHelper::validateKeys(valueDescriptionObject, keyInfoList, errorString)) {
errorString = QStringLiteral("Object at index %1 in \"values\" array failed validation '%2'.").arg(i).arg(errorString);
return false;
}
rgDescriptions.append(valueDescriptionObject[_enumBitmaskArrayDescriptionJsonKey].toString());
rgValues.append(valueDescriptionObject[_enumBitmaskArrayIndexJsonKey].toDouble());
}
return true;
}
......@@ -54,8 +54,10 @@ public:
FactMetaData(ValueType_t type, const QString name, QObject* parent = nullptr);
FactMetaData(const FactMetaData& other, QObject* parent = nullptr);
typedef QMap<QString, QString> DefineMap_t;
static QMap<QString, FactMetaData*> createMapFromJsonFile(const QString& jsonFilename, QObject* metaDataParent);
static QMap<QString, FactMetaData*> createMapFromJsonArray(const QJsonArray jsonArray, QMap<QString, QString>& defineMap, QObject* metaDataParent);
static QMap<QString, FactMetaData*> createMapFromJsonArray(const QJsonArray jsonArray, DefineMap_t& defineMap, QObject* metaDataParent);
static FactMetaData* createFromJsonObject(const QJsonObject& json, QMap<QString, QString>& defineMap, QObject* metaDataParent);
......@@ -204,10 +206,9 @@ public:
static const char* qgcFileType;
private:
QVariant _minForType(void) const;
QVariant _maxForType(void) const;
void _setAppSettingsTranslators(void);
QVariant _minForType (void) const;
QVariant _maxForType (void) const;
void _setAppSettingsTranslators (void);
/// Clamp a value to be within cookedMin and cookedMax
template<class T>
......@@ -232,6 +233,10 @@ private:
bool isInRawMinLimit(const QVariant& variantValue) const;
bool isInRawMaxLimit(const QVariant& variantValue) const;
static bool _parseEnum (const QJsonObject& jsonObject, DefineMap_t defineMap, QStringList& rgDescriptions, QStringList& rgValues, QString& errorString);
static bool _parseValuesArray (const QJsonObject& jsonObject, QStringList& rgDescriptions, QList<double>& rgValues, QString& errorString);
static bool _parseBitmaskArray (const QJsonObject& jsonObject, QStringList& rgDescriptions, QList<double>& rgValues, QString& errorString);
// Built in translators
static QVariant _defaultTranslator(const QVariant& from) { return from; }
static QVariant _degreesToRadians(const QVariant& degrees);
......@@ -366,6 +371,14 @@ private:
static const char* _categoryJsonKey;
static const char* _groupJsonKey;
static const char* _volatileJsonKey;
static const char* _enumStringsJsonKey;
static const char* _enumValuesJsonKey;
static const char* _enumValuesArrayJsonKey;
static const char* _enumBitmaskArrayJsonKey;
static const char* _enumValuesArrayValueJsonKey;
static const char* _enumValuesArrayDescriptionJsonKey;
static const char* _enumBitmaskArrayIndexJsonKey;
static const char* _enumBitmaskArrayDescriptionJsonKey;
static const char* _jsonMetaDataDefinesName;
static const char* _jsonMetaDataFactsName;
......
......@@ -22,8 +22,6 @@
#include <QFile>
#include <QTranslator>
const char* JsonHelper::_enumStringsJsonKey = "enumStrings";
const char* JsonHelper::_enumValuesJsonKey = "enumValues";
const char* JsonHelper::jsonVersionKey = "version";
const char* JsonHelper::jsonGroundStationKey = "groundStation";
const char* JsonHelper::jsonGroundStationValue = "QGroundControl";
......@@ -159,63 +157,6 @@ bool JsonHelper::validateKeyTypes(const QJsonObject& jsonObject, const QStringLi
return true;
}
bool JsonHelper::_parseEnumWorker(const QJsonObject& jsonObject, QMap<QString, QString>& defineMap, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName)
{
if(jsonObject.value(_enumStringsJsonKey).isArray()) {
// "enumStrings": ["Auto" , "Manual", "Shutter Priority", "Aperture Priority"],
QJsonArray jArray = jsonObject.value(_enumStringsJsonKey).toArray();
for(int i = 0; i < jArray.count(); ++i) {
enumStrings << jArray.at(i).toString();
}
} else {
// "enumStrings": "Auto,Manual,Shutter Priority,Aperture Priority",
QString value = jsonObject.value(_enumStringsJsonKey).toString();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
enumStrings = defineMap.value(value, value).split(",", QString::SkipEmptyParts);
#else
enumStrings = defineMap.value(value, value).split(",", Qt::SkipEmptyParts);
#endif
}
if(jsonObject.value(_enumValuesJsonKey).isArray()) {
// "enumValues": [0, 1, 2, 3, 4, 5],
QJsonArray jArray = jsonObject.value(_enumValuesJsonKey).toArray();
// This should probably be a variant list and not a string list.
for(int i = 0; i < jArray.count(); ++i) {
if(jArray.at(i).isString())
enumValues << jArray.at(i).toString();
else
enumValues << QString::number(jArray.at(i).toDouble());
}
} else {
// "enumValues": "0,1,2,3,4,5",
QString value = jsonObject.value(_enumValuesJsonKey).toString();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
enumValues = defineMap.value(value, value).split(",", QString::SkipEmptyParts);
#else
enumValues = defineMap.value(value, value).split(",", Qt::SkipEmptyParts);
#endif
}
if (enumStrings.count() != enumValues.count()) {
errorString = QObject::tr("enum strings/values count mismatch in %3 strings:values %1:%2").arg(enumStrings.count()).arg(enumValues.count()).arg(valueName);
return false;
}
return true;
}
bool JsonHelper::parseEnum(const QJsonObject& jsonObject, QMap<QString, QString>& defineMap, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName)
{
return _parseEnumWorker(jsonObject, defineMap, enumStrings, enumValues, errorString, valueName);
}
bool JsonHelper::parseEnum(const QJsonObject& jsonObject, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName)
{
QMap<QString, QString> defineMap;
return _parseEnumWorker(jsonObject, defineMap, enumStrings, enumValues, errorString, valueName);
}
bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QString& errorString)
{
QJsonParseError parseError;
......
......@@ -155,9 +155,6 @@ public:
static void savePolygon(QmlObjectListModel& list, ///< List which contains vertices
QJsonArray& polygonArray); ///< Array to save into
static bool parseEnum(const QJsonObject& jsonObject, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName = QString());
static bool parseEnum(const QJsonObject& jsonObject, QMap<QString, QString>& defineMap, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName = QString());
/// Returns NaN if the value is null, or if not, the double value
static double possibleNaNJsonValue(const QJsonValue& value);
......@@ -177,14 +174,11 @@ private:
bool writeAltitude,
QJsonValue& jsonValue,
bool geoJsonFormat);
static bool _parseEnumWorker(const QJsonObject& jsonObject, QMap<QString, QString>& defineMap, QStringList& enumStrings, QStringList& enumValues, QString& errorString, QString valueName);
static QStringList _addDefaultLocKeys(QJsonObject& jsonObject);
static QJsonObject _translateRoot(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys);
static QJsonObject _translateObject(QJsonObject& jsonObject, const QString& translateContext, const QStringList& translateKeys);
static QJsonArray _translateArray(QJsonArray& jsonArray, const QString& translateContext, const QStringList& translateKeys);
static const char* _enumStringsJsonKey;
static const char* _enumValuesJsonKey;
static const char* _translateKeysKey;
static const char* _arrayIDKeysKey;
};
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment