QmlDesigner: Detect literal types from string values in ModelEditor

Fixes: QDS-12213
Change-Id: I58d56c42b94be99309a344e084c68703b0b25b82
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2024-03-13 13:10:10 +02:00
parent fbb8bd89f9
commit d90828b055
3 changed files with 61 additions and 54 deletions

View File

@@ -15,6 +15,7 @@
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QRegularExpression>
#include <QTextStream> #include <QTextStream>
#include <QUrl> #include <QUrl>
#include <QVariant> #include <QVariant>
@@ -52,13 +53,6 @@ public:
bool isValidRowId(int row) const { return row > -1 && row < dataRecords.size(); } bool isValidRowId(int row) const { return row > -1 && row < dataRecords.size(); }
}; };
inline static bool isValidColorName(const QString &colorName)
{
static const QRegularExpression colorRegex{
"(?<color>^(?:#(?:(?:[0-9a-fA-F]{2}){3,4}|(?:[0-9a-fA-F]){3,4}))$)"};
return colorRegex.match(colorName).hasMatch();
}
/** /**
* @brief getCustomUrl * @brief getCustomUrl
* MimeType = <MainType/SubType> * MimeType = <MainType/SubType>
@@ -73,7 +67,7 @@ inline static bool isValidColorName(const QString &colorName)
* will be stored in this parameter, otherwise it will be empty. * will be stored in this parameter, otherwise it will be empty.
* @return true if the result is either url or image * @return true if the result is either url or image
*/ */
inline static bool getCustomUrl(const QString &value, static bool getCustomUrl(const QString &value,
CollectionDetails::DataType &dataType, CollectionDetails::DataType &dataType,
QUrl *urlResult = nullptr, QUrl *urlResult = nullptr,
QString *subType = nullptr) QString *subType = nullptr)
@@ -120,6 +114,60 @@ inline static bool getCustomUrl(const QString &value,
return false; return false;
} }
/**
* @brief dataTypeFromString
* @param value The string value to be evaluated
* @return Unknown if the string is empty, But returns Bool, Color, Integer,
* Real, Url, Image if these types are detected within the non-empty string,
* Otherwise it returns String.
* If the value is integer, but it's out of the int range, it will be
* considered as a Real.
*/
static CollectionDetails::DataType dataTypeFromString(const QString &value)
{
using DataType = CollectionDetails::DataType;
static const QRegularExpression validator{
"(?<boolean>^(?:true|false)$)|"
"(?<color>^(?:#(?:(?:[0-9a-fA-F]{2}){3,4}|(?:[0-9a-fA-F]){3,4}))$)|"
"(?<integer>^\\d+$)|"
"(?<real>^(?:-?(?:0|[1-9]\\d*)?(?:\\.\\d*)?(?<=\\d|\\.)"
"(?:e-?(?:0|[1-9]\\d*))?|0x[0-9a-f]+)$)"};
static const int boolIndex = validator.namedCaptureGroups().indexOf("boolean");
static const int colorIndex = validator.namedCaptureGroups().indexOf("color");
static const int integerIndex = validator.namedCaptureGroups().indexOf("integer");
static const int realIndex = validator.namedCaptureGroups().indexOf("real");
[[maybe_unused]] static const bool allIndexesFound =
[](const std::initializer_list<int> &captureIndexes) {
QTC_ASSERT(Utils::allOf(captureIndexes, [](int val) { return val > -1; }), return false);
return true;
}({boolIndex, colorIndex, integerIndex, realIndex});
if (value.isEmpty())
return DataType::Unknown;
const QString trimmedValue = value.trimmed();
QRegularExpressionMatch match = validator.match(trimmedValue);
if (match.hasCaptured(boolIndex))
return DataType::Boolean;
if (match.hasCaptured(colorIndex))
return DataType::Color;
if (match.hasCaptured(integerIndex)) {
bool isInt = false;
trimmedValue.toInt(&isInt);
return isInt ? DataType::Integer : DataType::Real;
}
if (match.hasCaptured(realIndex))
return DataType::Real;
DataType urlType;
if (getCustomUrl(value, urlType))
return urlType;
return DataType::String;
}
static CollectionProperty::DataType dataTypeFromJsonValue(const QJsonValue &value) static CollectionProperty::DataType dataTypeFromJsonValue(const QJsonValue &value)
{ {
using DataType = CollectionDetails::DataType; using DataType = CollectionDetails::DataType;
@@ -136,21 +184,8 @@ static CollectionProperty::DataType dataTypeFromJsonValue(const QJsonValue &valu
return DataType::Integer; return DataType::Integer;
return DataType::Real; return DataType::Real;
} }
case JsonType::String: { case JsonType::String:
const QString stringValue = value.toString(); return dataTypeFromString(value.toString());
if (stringValue.isEmpty())
return DataType::Unknown;
if (isValidColorName(stringValue))
return DataType::Color;
DataType urlType;
if (getCustomUrl(stringValue, urlType))
return urlType;
return DataType::String;
} break;
default: default:
return DataType::Unknown; return DataType::Unknown;
} }

View File

@@ -584,33 +584,6 @@ void CollectionDetailsModel::ensureSingleCell()
updateEmpty(); updateEmpty();
} }
QVariant CollectionDetailsModel::variantFromString(const QString &value)
{
constexpr QStringView typesPattern{u"(?<boolean>^(?:true|false)$)|"
u"(?<number>^(?:-?(?:0|[1-9]\\d*)?(?:\\.\\d*)?(?<=\\d|\\.)"
u"(?:e-?(?:0|[1-9]\\d*))?|0x[0-9a-f]+)$)|"
u"(?<color>^(?:#(?:(?:[0-9a-fA-F]{2}){3,4}|"
u"(?:[0-9a-fA-F]){3,4}))$)|"
u"(?<string>[A-Za-z][A-Za-z0-9_ -]*)"};
static QRegularExpression validator(typesPattern.toString());
const QString trimmedValue = value.trimmed();
QRegularExpressionMatch match = validator.match(trimmedValue);
QVariant variantValue = value;
if (value.isEmpty())
return QVariant();
if (!match.captured(u"boolean").isEmpty())
return variantValue.toBool();
if (!match.captured(u"number").isEmpty())
return variantValue.toDouble();
if (!match.captured(u"color").isEmpty())
return variantValue.value<QColor>();
if (!match.captured(u"string").isEmpty())
return variantValue.toString();
return QVariant::fromValue(value);
}
QJsonDocument CollectionDetailsModel::readJsonFile(const QUrl &url) QJsonDocument CollectionDetailsModel::readJsonFile(const QUrl &url)
{ {
using Utils::FilePath; using Utils::FilePath;

View File

@@ -88,7 +88,6 @@ private:
void setCollectionName(const QString &newCollectionName); void setCollectionName(const QString &newCollectionName);
void loadJsonCollection(const QString &filePath, const QString &collection); void loadJsonCollection(const QString &filePath, const QString &collection);
void ensureSingleCell(); void ensureSingleCell();
QVariant variantFromString(const QString &value);
QJsonDocument readJsonFile(const QUrl &url); QJsonDocument readJsonFile(const QUrl &url);
QHash<CollectionReference, CollectionDetails> m_openedCollections; QHash<CollectionReference, CollectionDetails> m_openedCollections;