forked from qt-creator/qt-creator
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:
@@ -7,6 +7,10 @@
|
||||
#include "collectioneditorconstants.h"
|
||||
#include "collectioneditorutils.h"
|
||||
#include "model/qmltextgenerator.h"
|
||||
#include "plaintexteditmodifier.h"
|
||||
#include "qmldesignerbase/qmldesignerbaseplugin.h"
|
||||
#include "qmldesignerexternaldependencies.h"
|
||||
#include "rewriterview.h"
|
||||
|
||||
#include <model.h>
|
||||
#include <nodemetainfo.h>
|
||||
@@ -23,11 +27,15 @@
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QScopedPointer>
|
||||
|
||||
namespace {
|
||||
|
||||
inline constexpr char CHILDLISTMODEL_TYPENAME[] = "ChildListModel";
|
||||
|
||||
QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
|
||||
{
|
||||
using QmlDesigner::AbstractProperty;
|
||||
@@ -59,6 +67,57 @@ bool isValidCollectionPropertyName(const QString &collectionId)
|
||||
&& !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 QmlDesigner {
|
||||
@@ -102,8 +161,10 @@ void DataStoreModelNode::reloadModel()
|
||||
|
||||
m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString();
|
||||
|
||||
if (forceUpdate)
|
||||
if (forceUpdate) {
|
||||
preloadFile();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList DataStoreModelNode::collectionNames() const
|
||||
@@ -143,6 +204,25 @@ void DataStoreModelNode::reset()
|
||||
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()
|
||||
{
|
||||
QTC_ASSERT(model(), return);
|
||||
@@ -150,8 +230,6 @@ void DataStoreModelNode::updateDataStoreProperties()
|
||||
ModelNode rootNode = modelNode();
|
||||
QTC_ASSERT(rootNode.isValid(), return);
|
||||
|
||||
static TypeName childNodeTypename = "ChildListModel";
|
||||
|
||||
QSet<QString> collectionNamesToBeAdded;
|
||||
const QStringList allCollectionNames = m_collectionPropertyNames.keys();
|
||||
for (const QString &collectionName : allCollectionNames)
|
||||
@@ -165,7 +243,7 @@ void DataStoreModelNode::updateDataStoreProperties()
|
||||
continue;
|
||||
|
||||
NodeProperty nodeProprty = property.toNodeProperty();
|
||||
if (!nodeProprty.hasDynamicTypeName(childNodeTypename))
|
||||
if (!nodeProprty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
|
||||
continue;
|
||||
|
||||
ModelNode childNode = nodeProprty.modelNode();
|
||||
@@ -189,24 +267,8 @@ void DataStoreModelNode::updateDataStoreProperties()
|
||||
|
||||
QStringList collectionNamesLeft = collectionNamesToBeAdded.values();
|
||||
Utils::sort(collectionNamesLeft);
|
||||
for (const QString &collectionName : std::as_const(collectionNamesLeft)) {
|
||||
PropertyName newPropertyName = 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);
|
||||
}
|
||||
for (const QString &collectionName : std::as_const(collectionNamesLeft))
|
||||
addCollectionNameToTheModel(collectionName, getUniquePropertyName(collectionName));
|
||||
|
||||
// Backend Property
|
||||
ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME);
|
||||
@@ -231,19 +293,50 @@ void DataStoreModelNode::updateSingletonFile()
|
||||
imports += QStringLiteral("import %1\n").arg(import.toString(true));
|
||||
|
||||
QString content = pragmaSingleTone + imports + getModelQmlText();
|
||||
QUrl modelUrl = m_model->fileUrl();
|
||||
FileSaver file(FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
|
||||
: modelUrl.toString()));
|
||||
FileSaver file(dataStoreQmlFilePath());
|
||||
file.write(content.toLatin1());
|
||||
file.finalize();
|
||||
}
|
||||
|
||||
void DataStoreModelNode::update()
|
||||
{
|
||||
if (!m_model.get())
|
||||
return;
|
||||
|
||||
updateDataStoreProperties();
|
||||
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)
|
||||
{
|
||||
ModelNode dataStoreNode = modelNode();
|
||||
|
@@ -7,6 +7,10 @@
|
||||
|
||||
#include <QMap>
|
||||
|
||||
namespace Utils {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class Model;
|
||||
@@ -34,9 +38,14 @@ private:
|
||||
QString getModelQmlText();
|
||||
|
||||
void reset();
|
||||
void preloadFile();
|
||||
void updateDataStoreProperties();
|
||||
void updateSingletonFile();
|
||||
void update();
|
||||
void addCollectionNameToTheModel(const QString &collectionName,
|
||||
const PropertyName &dataStorePropertyName);
|
||||
Utils::FilePath dataStoreQmlFilePath() const;
|
||||
|
||||
PropertyName getUniquePropertyName(const QString &collectionName);
|
||||
|
||||
ModelPointer m_model;
|
||||
|
Reference in New Issue
Block a user