QmlDesigner: Keep the order of columns for imported jsons

Fixes: QDS-11670
Change-Id: Ia068bbb864065b648cffcab2c3477d3cec7f25f8
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Ali Kianian
2024-02-12 12:26:17 +02:00
parent dccd828f1f
commit 1f9e41ac9a
3 changed files with 77 additions and 9 deletions

View File

@@ -6,6 +6,9 @@
#include "collectioneditorutils.h"
#include <utils/span.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/qmljsdocument.h>
#include <qqml.h>
#include <QJsonArray>
@@ -261,6 +264,47 @@ inline static bool isEmptyJsonValue(const QJsonValue &value)
return value.isNull() || value.isUndefined() || (value.isString() && value.toString().isEmpty());
}
class PropertyOrderFinder : public QmlJS::AST::Visitor
{
public:
static QStringList parse(const QString &jsonContent)
{
PropertyOrderFinder finder;
QmlJS::Document::MutablePtr jsonDoc = QmlJS::Document::create(Utils::FilePath::fromString(
"<expression>"),
QmlJS::Dialect::Json);
jsonDoc->setSource(jsonContent);
jsonDoc->parseJavaScript();
if (!jsonDoc->isParsedCorrectly())
return {};
jsonDoc->ast()->accept(&finder);
return finder.m_orderedList;
}
protected:
bool visit(QmlJS::AST::PatternProperty *patternProperty) override
{
const QString propertyName = patternProperty->name->asString();
if (!m_propertySet.contains(propertyName)) {
m_propertySet.insert(propertyName);
m_orderedList.append(propertyName);
}
return true;
}
void throwRecursionDepthError() override
{
qWarning() << Q_FUNC_INFO << __LINE__ << "Recursion depth error";
};
private:
QSet<QString> m_propertySet;
QStringList m_orderedList;
};
QString CollectionParseError::errorString() const
{
switch (errorNo) {
@@ -690,7 +734,7 @@ CollectionDetails CollectionDetails::fromImportedCsv(const QByteArray &document)
return fromImportedJson(importedArray);
}
CollectionDetails CollectionDetails::fromImportedJson(const QJsonDocument &document)
CollectionDetails CollectionDetails::fromImportedJson(const QByteArray &json, QJsonParseError *error)
{
QJsonArray importedCollection;
auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray {
@@ -710,6 +754,14 @@ CollectionDetails CollectionDetails::fromImportedJson(const QJsonDocument &docum
return resultArray;
};
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(json, &parseError);
if (error)
*error = parseError;
if (parseError.error != QJsonParseError::NoError)
return CollectionDetails{};
if (document.isArray()) {
importedCollection = refineJsonArray(document.array());
} else if (document.isObject()) {
@@ -738,7 +790,7 @@ CollectionDetails CollectionDetails::fromImportedJson(const QJsonDocument &docum
}
}
return fromImportedJson(importedCollection);
return fromImportedJson(importedCollection, PropertyOrderFinder::parse(QLatin1String(json)));
}
CollectionDetails CollectionDetails::fromLocalJson(const QJsonDocument &document,
@@ -803,9 +855,24 @@ void CollectionDetails::insertRecords(const QJsonArray &record, int idx, int cou
d->dataRecords.insert(idx, count, localRecord);
}
CollectionDetails CollectionDetails::fromImportedJson(const QJsonArray &importedArray)
CollectionDetails CollectionDetails::fromImportedJson(const QJsonArray &importedArray,
const QStringList &propertyPriority)
{
const QList<CollectionProperty> columnData = getColumnsFromImportedJsonArray(importedArray);
QList<CollectionProperty> columnData = getColumnsFromImportedJsonArray(importedArray);
if (!propertyPriority.isEmpty()) {
QMap<QString, int> priorityMap;
for (const QString &propertyName : propertyPriority) {
if (!priorityMap.contains(propertyName))
priorityMap.insert(propertyName, priorityMap.size());
}
const int lowestPriority = priorityMap.size();
Utils::sort(columnData, [&](const CollectionProperty &a, const CollectionProperty &b) {
return priorityMap.value(a.name, lowestPriority)
< priorityMap.value(b.name, lowestPriority);
});
}
QList<QJsonArray> localJsonArray;
for (const QJsonValue &importedRowValue : importedArray) {
QJsonObject importedRowObject = importedRowValue.toObject();

View File

@@ -9,6 +9,7 @@
QT_BEGIN_NAMESPACE
class QJsonObject;
struct QJsonParseError;
class QVariant;
QT_END_NAMESPACE
@@ -125,7 +126,8 @@ public:
static void registerDeclarativeType();
static CollectionDetails fromImportedCsv(const QByteArray &document);
static CollectionDetails fromImportedJson(const QJsonDocument &document);
static CollectionDetails fromImportedJson(const QByteArray &json,
QJsonParseError *error = nullptr);
static CollectionDetails fromLocalJson(const QJsonDocument &document,
const QString &collectionName,
CollectionParseError *error = nullptr);
@@ -136,7 +138,8 @@ private:
void markChanged();
void insertRecords(const QJsonArray &record, int idx = -1, int count = 1);
static CollectionDetails fromImportedJson(const QJsonArray &importedArray);
static CollectionDetails fromImportedJson(const QJsonArray &importedArray,
const QStringList &propertyPriority = {});
static CollectionDetails fromLocalCollection(const QJsonObject &localCollection,
CollectionParseError *error = nullptr);

View File

@@ -306,13 +306,11 @@ bool CollectionWidget::importFile(const QString &collectionName, const QUrl &url
return false;
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(fileContent, &parseError);
loadedCollection = CollectionDetails::fromImportedJson(fileContent, &parseError);
if (parseError.error != QJsonParseError::NoError) {
warn(tr("Json file Import error"),
tr("Cannot parse json content\n%1").arg(parseError.errorString()));
}
loadedCollection = CollectionDetails::fromImportedJson(document);
} else if (fileInfo.suffix() == "csv") {
if (!loadUrlContent())
return false;