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 "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();
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user