QmlDesigner: Read DataStore.qml before writing properties

The properties of DataStore.qml are read, So the property-name for
a collection name will not be changed if it's not like the
Collection-name.
* Unique names will be created only when a user adds a collection.
* Renaming a collection shouldn't affect the related property-name
of DataStore.

Fixes: QDS-11540
Change-Id: I797a29c116051f79cfa6680360e5b086154a1df6
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Ali Kianian
2023-12-14 16:40:34 +02:00
parent 6fcb853b19
commit 63f8ecd003
2 changed files with 127 additions and 25 deletions

View File

@@ -7,6 +7,10 @@
#include "collectioneditorconstants.h" #include "collectioneditorconstants.h"
#include "collectioneditorutils.h" #include "collectioneditorutils.h"
#include "model/qmltextgenerator.h" #include "model/qmltextgenerator.h"
#include "plaintexteditmodifier.h"
#include "qmldesignerbase/qmldesignerbaseplugin.h"
#include "qmldesignerexternaldependencies.h"
#include "rewriterview.h"
#include <model.h> #include <model.h>
#include <nodemetainfo.h> #include <nodemetainfo.h>
@@ -23,11 +27,15 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QPlainTextEdit>
#include <QRegularExpression> #include <QRegularExpression>
#include <QRegularExpressionMatch> #include <QRegularExpressionMatch>
#include <QScopedPointer>
namespace { namespace {
inline constexpr char CHILDLISTMODEL_TYPENAME[] = "ChildListModel";
QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
{ {
using QmlDesigner::AbstractProperty; using QmlDesigner::AbstractProperty;
@@ -59,6 +67,57 @@ bool isValidCollectionPropertyName(const QString &collectionId)
&& !reservedKeywords.contains(collectionId.toLatin1()); && !reservedKeywords.contains(collectionId.toLatin1());
} }
QMap<QString, QmlDesigner::PropertyName> getModelIdMap(const QmlDesigner::ModelNode &rootNode)
{
using namespace QmlDesigner;
QMap<QString, PropertyName> modelNameForId;
const QList<AbstractProperty> propertyNames = rootNode.dynamicProperties();
for (const AbstractProperty &property : std::as_const(propertyNames)) {
if (!property.isNodeProperty())
continue;
NodeProperty nodeProperty = property.toNodeProperty();
if (!nodeProperty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
continue;
ModelNode childNode = nodeProperty.modelNode();
if (childNode.hasProperty(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)) {
QString modelName = childNode.property(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)
.toVariantProperty()
.value()
.toString();
if (!modelName.isEmpty())
modelNameForId.insert(modelName, property.name());
}
}
return modelNameForId;
}
void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext)
{
using namespace QmlDesigner;
Q_ASSERT(model);
QScopedPointer<QPlainTextEdit> textEdit(new QPlainTextEdit);
QScopedPointer<NotIndentingTextEditModifier> modifier(
new NotIndentingTextEditModifier(textEdit.data()));
textEdit->hide();
textEdit->setPlainText(qmlContext);
QmlDesigner::ExternalDependencies externalDependencies{QmlDesignerBasePlugin::settings()};
QScopedPointer<RewriterView> rewriter(
new RewriterView(externalDependencies, QmlDesigner::RewriterView::Validate));
rewriter->setParent(model);
rewriter->setTextModifier(modifier.get());
rewriter->setCheckSemanticErrors(false);
model->attachView(rewriter.get());
model->detachView(rewriter.get());
}
} // namespace } // namespace
namespace QmlDesigner { namespace QmlDesigner {
@@ -102,8 +161,10 @@ void DataStoreModelNode::reloadModel()
m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString(); m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString();
if (forceUpdate) if (forceUpdate) {
preloadFile();
update(); update();
}
} }
QStringList DataStoreModelNode::collectionNames() const QStringList DataStoreModelNode::collectionNames() const
@@ -143,6 +204,25 @@ void DataStoreModelNode::reset()
setCollectionNames({}); setCollectionNames({});
} }
void DataStoreModelNode::preloadFile()
{
using Utils::FilePath;
using Utils::FileReader;
if (!m_model)
return;
const FilePath dataStoreQmlPath = dataStoreQmlFilePath();
FileReader dataStoreQmlFile;
QString sourceQmlContext;
if (dataStoreQmlFile.fetch(dataStoreQmlPath))
sourceQmlContext = QString::fromLatin1(dataStoreQmlFile.data());
setQmlContextToModel(m_model.get(), sourceQmlContext);
m_collectionPropertyNames = getModelIdMap(m_model->rootModelNode());
}
void DataStoreModelNode::updateDataStoreProperties() void DataStoreModelNode::updateDataStoreProperties()
{ {
QTC_ASSERT(model(), return); QTC_ASSERT(model(), return);
@@ -150,8 +230,6 @@ void DataStoreModelNode::updateDataStoreProperties()
ModelNode rootNode = modelNode(); ModelNode rootNode = modelNode();
QTC_ASSERT(rootNode.isValid(), return); QTC_ASSERT(rootNode.isValid(), return);
static TypeName childNodeTypename = "ChildListModel";
QSet<QString> collectionNamesToBeAdded; QSet<QString> collectionNamesToBeAdded;
const QStringList allCollectionNames = m_collectionPropertyNames.keys(); const QStringList allCollectionNames = m_collectionPropertyNames.keys();
for (const QString &collectionName : allCollectionNames) for (const QString &collectionName : allCollectionNames)
@@ -165,7 +243,7 @@ void DataStoreModelNode::updateDataStoreProperties()
continue; continue;
NodeProperty nodeProprty = property.toNodeProperty(); NodeProperty nodeProprty = property.toNodeProperty();
if (!nodeProprty.hasDynamicTypeName(childNodeTypename)) if (!nodeProprty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
continue; continue;
ModelNode childNode = nodeProprty.modelNode(); ModelNode childNode = nodeProprty.modelNode();
@@ -189,24 +267,8 @@ void DataStoreModelNode::updateDataStoreProperties()
QStringList collectionNamesLeft = collectionNamesToBeAdded.values(); QStringList collectionNamesLeft = collectionNamesToBeAdded.values();
Utils::sort(collectionNamesLeft); Utils::sort(collectionNamesLeft);
for (const QString &collectionName : std::as_const(collectionNamesLeft)) { for (const QString &collectionName : std::as_const(collectionNamesLeft))
PropertyName newPropertyName = getUniquePropertyName(collectionName); addCollectionNameToTheModel(collectionName, getUniquePropertyName(collectionName));
if (newPropertyName.isEmpty()) {
qWarning() << __FUNCTION__ << __LINE__
<< QString("The property name cannot be generated from \"%1\"").arg(collectionName);
continue;
}
ModelNode collectionNode = model()->createModelNode(childNodeTypename);
VariantProperty modelNameProperty = collectionNode.variantProperty(
CollectionEditor::JSONCHILDMODELNAME_PROPERTY);
modelNameProperty.setValue(collectionName);
NodeProperty nodeProp = rootNode.nodeProperty(newPropertyName);
nodeProp.setDynamicTypeNameAndsetModelNode(childNodeTypename, collectionNode);
m_collectionPropertyNames.insert(collectionName, newPropertyName);
}
// Backend Property // Backend Property
ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME); ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME);
@@ -231,19 +293,50 @@ void DataStoreModelNode::updateSingletonFile()
imports += QStringLiteral("import %1\n").arg(import.toString(true)); imports += QStringLiteral("import %1\n").arg(import.toString(true));
QString content = pragmaSingleTone + imports + getModelQmlText(); QString content = pragmaSingleTone + imports + getModelQmlText();
QUrl modelUrl = m_model->fileUrl(); FileSaver file(dataStoreQmlFilePath());
FileSaver file(FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
: modelUrl.toString()));
file.write(content.toLatin1()); file.write(content.toLatin1());
file.finalize(); file.finalize();
} }
void DataStoreModelNode::update() void DataStoreModelNode::update()
{ {
if (!m_model.get())
return;
updateDataStoreProperties(); updateDataStoreProperties();
updateSingletonFile(); updateSingletonFile();
} }
void DataStoreModelNode::addCollectionNameToTheModel(const QString &collectionName,
const PropertyName &dataStorePropertyName)
{
ModelNode rootNode = modelNode();
QTC_ASSERT(rootNode.isValid(), return);
if (dataStorePropertyName.isEmpty()) {
qWarning() << __FUNCTION__ << __LINE__
<< QString("The property name cannot be generated from \"%1\"").arg(collectionName);
return;
}
ModelNode collectionNode = model()->createModelNode(CHILDLISTMODEL_TYPENAME);
VariantProperty modelNameProperty = collectionNode.variantProperty(
CollectionEditor::JSONCHILDMODELNAME_PROPERTY);
modelNameProperty.setValue(collectionName);
NodeProperty nodeProp = rootNode.nodeProperty(dataStorePropertyName);
nodeProp.setDynamicTypeNameAndsetModelNode(CHILDLISTMODEL_TYPENAME, collectionNode);
m_collectionPropertyNames.insert(collectionName, dataStorePropertyName);
}
Utils::FilePath DataStoreModelNode::dataStoreQmlFilePath() const
{
QUrl modelUrl = m_model->fileUrl();
return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
: modelUrl.toString());
}
PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName) PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName)
{ {
ModelNode dataStoreNode = modelNode(); ModelNode dataStoreNode = modelNode();

View File

@@ -7,6 +7,10 @@
#include <QMap> #include <QMap>
namespace Utils {
class FilePath;
}
namespace QmlDesigner { namespace QmlDesigner {
class Model; class Model;
@@ -34,9 +38,14 @@ private:
QString getModelQmlText(); QString getModelQmlText();
void reset(); void reset();
void preloadFile();
void updateDataStoreProperties(); void updateDataStoreProperties();
void updateSingletonFile(); void updateSingletonFile();
void update(); void update();
void addCollectionNameToTheModel(const QString &collectionName,
const PropertyName &dataStorePropertyName);
Utils::FilePath dataStoreQmlFilePath() const;
PropertyName getUniquePropertyName(const QString &collectionName); PropertyName getUniquePropertyName(const QString &collectionName);
ModelPointer m_model; ModelPointer m_model;