QmlDesigner: Use FileSaver instead of file in Model Editor

* Also the warning is removed for internal changes on local files

Fixes: QDS-11903
Change-Id: Ic35966888433a2bd9b1cc10a47bb7ed51280ffb1
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Shrief Gabr <shrief.gabr@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2024-02-14 15:39:33 +02:00
parent 4c79e1b8d8
commit efe114872c
7 changed files with 65 additions and 131 deletions

View File

@@ -414,7 +414,6 @@ bool CollectionDetailsModel::saveDataStoreCollections()
const ModelNode node = m_currentCollection.reference().node;
const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath();
Utils::FileReader fileData;
Utils::FileSaver sourceFile(path);
if (!fileData.fetch(path)) {
qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString();
@@ -437,10 +436,8 @@ bool CollectionDetailsModel::saveDataStoreCollections()
}
document.setObject(obj);
bool saved = sourceFile.write(document.toJson());
saved &= sourceFile.finalize();
if (saved) {
if (CollectionEditorUtils::writeToJsonDocument(path, document)) {
const CollectionReference currentReference = m_currentCollection.reference();
for (CollectionDetails &collection : collectionsToBeSaved) {
collection.markSaved();

View File

@@ -7,6 +7,7 @@
#include "nodemetainfo.h"
#include "propertymetainfo.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
@@ -393,4 +394,16 @@ QStringList dataTypesStringList()
return typesList;
}
bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString)
{
Core::FileChangeBlocker fileBlocker(path);
Utils::FileSaver jsonFile(path);
if (jsonFile.write(document.toJson()))
jsonFile.finalize();
if (errorString)
*errorString = jsonFile.errorString();
return !jsonFile.hasError();
}
} // namespace QmlDesigner::CollectionEditorUtils

View File

@@ -29,6 +29,10 @@ Utils::FilePath dataStoreJsonFilePath();
Utils::FilePath dataStoreQmlFilePath();
bool writeToJsonDocument(const Utils::FilePath &path,
const QJsonDocument &document,
QString *errorString = nullptr);
bool isDataStoreNode(const ModelNode &dataStoreNode);
bool ensureDataStoreExists(bool &justCreated);

View File

@@ -9,6 +9,7 @@
#include "collectionlistmodel.h"
#include "variantproperty.h"
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <qqml.h>
@@ -27,6 +28,8 @@ QSharedPointer<QmlDesigner::CollectionListModel> loadCollection(
{
using namespace QmlDesigner::CollectionEditorConstants;
using namespace QmlDesigner::CollectionEditorUtils;
using Utils::FilePath;
using Utils::FileReader;
QString sourceFileAddress = getSourceCollectionPath(sourceNode);
QSharedPointer<QmlDesigner::CollectionListModel> collectionsList;
@@ -40,12 +43,12 @@ QSharedPointer<QmlDesigner::CollectionListModel> loadCollection(
};
if (sourceNode.type() == JSONCOLLECTIONMODEL_TYPENAME) {
QFile sourceFile(sourceFileAddress);
if (!sourceFile.open(QFile::ReadOnly))
FileReader sourceFile;
if (!sourceFile.fetch(FilePath::fromUserInput(sourceFileAddress)))
return {};
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(sourceFile.readAll(), &parseError);
QJsonDocument document = QJsonDocument::fromJson(sourceFile.data(), &parseError);
if (parseError.error != QJsonParseError::NoError)
return {};
@@ -273,6 +276,8 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node,
const QJsonObject &newCollection,
QString *errorString)
{
using Utils::FilePath;
using Utils::FileReader;
auto returnError = [errorString](const QString &msg) -> bool {
if (errorString)
*errorString = msg;
@@ -295,13 +300,15 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node,
if (!sourceFileInfo.isFile())
return returnError(tr("Selected node must have a valid source file address"));
QFile jsonFile(sourceFileAddress);
if (!jsonFile.open(QFile::ReadWrite))
return returnError(tr("Can't read or write \"%1\".\n%2")
.arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
FileReader jsonFile;
if (!jsonFile.fetch(jsonPath)) {
return returnError(
tr("Can't read \"%1\".\n%2").arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
}
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(jsonFile.readAll(), &parseError);
QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
if (parseError.error != QJsonParseError::NoError)
return returnError(tr("\"%1\" is corrupted.\n%2")
.arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
@@ -310,14 +317,8 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node,
QJsonObject sourceObject = document.object();
sourceObject.insert(collectionName, newCollection);
document.setObject(sourceObject);
if (!jsonFile.resize(0))
return returnError(tr("Can't clean \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
QByteArray jsonData = document.toJson();
auto writtenBytes = jsonFile.write(jsonData);
jsonFile.close();
if (writtenBytes != jsonData.size())
if (!CollectionEditorUtils::writeToJsonDocument(jsonPath, document))
return returnError(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
updateCollectionList(index(idx));
@@ -417,6 +418,10 @@ void CollectionSourceModel::onSelectedCollectionChanged(CollectionListModel *col
void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collectionList,
const QString &oldName, const QString &newName)
{
using Utils::FilePath;
using Utils::FileReader;
using Utils::FileSaver;
auto emitRenameWarning = [this](const QString &msg) -> void {
emit warning(tr("Rename Model"), msg);
};
@@ -446,15 +451,16 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
return;
}
QFile jsonFile(sourceFileAddress);
if (!jsonFile.open(QFile::ReadWrite)) {
emitRenameWarning(tr("Can't read or write \"%1\".\n%2")
.arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
FileReader jsonFile;
if (!jsonFile.fetch(jsonPath)) {
emitRenameWarning(
tr("Can't read \"%1\".\n%2").arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
return;
}
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(jsonFile.readAll(), &parseError);
QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
if (parseError.error != QJsonParseError::NoError) {
emitRenameWarning(tr("\"%1\" is corrupted.\n%2")
.arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
@@ -484,16 +490,8 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
rootObject.remove(oldName);
document.setObject(rootObject);
if (!jsonFile.resize(0)) {
emitRenameWarning(tr("Can't clean \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
return;
}
QByteArray jsonData = document.toJson();
auto writtenBytes = jsonFile.write(jsonData);
jsonFile.close();
if (writtenBytes != jsonData.size()) {
if (!CollectionEditorUtils::writeToJsonDocument(jsonPath, document)) {
emitRenameWarning(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
return;
}
@@ -519,6 +517,8 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collectionList,
const QStringList &removedCollections)
{
using Utils::FilePath;
using Utils::FileReader;
auto emitDeleteWarning = [this](const QString &msg) -> void {
emit warning(tr("Delete Model"), msg);
};
@@ -547,15 +547,16 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection
return;
}
QFile jsonFile(sourceFileAddress);
if (!jsonFile.open(QFile::ReadWrite)) {
FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
FileReader jsonFile;
if (!jsonFile.fetch(jsonPath)) {
emitDeleteWarning(tr("Can't read or write \"%1\".\n%2")
.arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
return;
}
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(jsonFile.readAll(), &parseError);
QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
if (parseError.error != QJsonParseError::NoError) {
emitDeleteWarning(tr("\"%1\" is corrupted.\n%2")
.arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
@@ -578,16 +579,8 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection
}
document.setObject(rootObject);
if (!jsonFile.resize(0)) {
emitDeleteWarning(tr("Can't clean \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
return;
}
QByteArray jsonData = document.toJson();
auto writtenBytes = jsonFile.write(jsonData);
jsonFile.close();
if (writtenBytes != jsonData.size()) {
if (!CollectionEditorUtils::writeToJsonDocument(jsonPath, document)) {
emitDeleteWarning(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
return;
}

View File

@@ -17,7 +17,6 @@
#include <coreplugin/messagebox.h>
#include <studioquickwidget.h>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
@@ -167,14 +166,14 @@ bool CollectionWidget::loadCsvFile(const QUrl &url, const QString &collectionNam
bool CollectionWidget::isJsonFile(const QUrl &url) const
{
QString filePath = url.isLocalFile() ? url.toLocalFile() : url.toString();
QFile file(filePath);
if (!file.exists() || !file.open(QFile::ReadOnly))
Utils::FilePath filePath = Utils::FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
: url.toString());
Utils::FileReader file;
if (!file.fetch(filePath))
return false;
QJsonParseError error;
QJsonDocument::fromJson(file.readAll(), &error);
QJsonDocument::fromJson(file.data(), &error);
if (error.error)
return false;
@@ -184,9 +183,8 @@ bool CollectionWidget::isJsonFile(const QUrl &url) const
bool CollectionWidget::isCsvFile(const QUrl &url) const
{
QString filePath = url.isLocalFile() ? url.toLocalFile() : url.toString();
QFile file(filePath);
return file.exists() && file.fileName().endsWith(".csv");
QFileInfo fileInfo(filePath);
return fileInfo.exists() && !fileInfo.suffix().compare("csv", Qt::CaseInsensitive);
}
bool CollectionWidget::isValidUrlToImport(const QUrl &url) const
@@ -203,73 +201,6 @@ bool CollectionWidget::isValidUrlToImport(const QUrl &url) const
return false;
}
bool CollectionWidget::addCollection(const QString &collectionName,
const QString &collectionType,
const QUrl &sourceUrl,
const QVariant &sourceNode)
{
const ModelNode node = sourceNode.value<ModelNode>();
bool isNewCollection = !node.isValid();
if (isNewCollection) {
QString sourcePath = sourceUrl.isLocalFile() ? sourceUrl.toLocalFile() : sourceUrl.toString();
if (collectionType == "json") {
QJsonObject jsonObject;
jsonObject.insert(collectionName, CollectionEditorUtils::defaultCollection());
QFile sourceFile(sourcePath);
if (!sourceFile.open(QFile::WriteOnly)) {
warn(tr("File error"),
tr("Can not open the file to write.\n") + sourceFile.errorString());
return false;
}
sourceFile.write(QJsonDocument(jsonObject).toJson());
sourceFile.close();
bool loaded = loadJsonFile(sourcePath, collectionName);
if (!loaded)
sourceFile.remove();
return loaded;
} else if (collectionType == "csv") {
QFile sourceFile(sourcePath);
if (!sourceFile.open(QFile::WriteOnly)) {
warn(tr("File error"),
tr("Can not open the file to write.\n") + sourceFile.errorString());
return false;
}
sourceFile.write("Column1\n\n");
sourceFile.close();
bool loaded = loadCsvFile(sourcePath, collectionName);
if (!loaded)
sourceFile.remove();
return loaded;
} else if (collectionType == "existing") {
QFileInfo fileInfo(sourcePath);
if (fileInfo.suffix() == "json")
return loadJsonFile(sourcePath, collectionName);
else if (fileInfo.suffix() == "csv")
return loadCsvFile(sourcePath, collectionName);
}
} else if (collectionType == "json") {
QString errorMsg;
bool added = m_sourceModel->addCollectionToSource(node,
collectionName,
CollectionEditorUtils::defaultCollection(),
&errorMsg);
if (!added)
warn(tr("Can not add a model to the JSON file"), errorMsg);
return added;
}
return false;
}
bool CollectionWidget::importFile(const QString &collectionName, const QUrl &url)
{
using Utils::FilePath;
@@ -289,15 +220,13 @@ bool CollectionWidget::importFile(const QString &collectionName, const QUrl &url
QByteArray fileContent;
auto loadUrlContent = [&]() -> bool {
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
if (file.open(QFile::ReadOnly)) {
fileContent = file.readAll();
file.close();
Utils::FileReader file;
if (file.fetch(fileInfo)) {
fileContent = file.data();
return true;
}
warn(tr("Import from file"), tr("Cannot import from file \"%1\"").arg(file.fileName()));
warn(tr("Import from file"), tr("Cannot import from file \"%1\"").arg(fileInfo.fileName()));
return false;
};

View File

@@ -39,10 +39,6 @@ public:
Q_INVOKABLE bool isJsonFile(const QUrl &url) const;
Q_INVOKABLE bool isCsvFile(const QUrl &url) const;
Q_INVOKABLE bool isValidUrlToImport(const QUrl &url) const;
Q_INVOKABLE bool addCollection(const QString &collectionName,
const QString &collectionType,
const QUrl &sourceUrl,
const QVariant &sourceNode);
Q_INVOKABLE bool importFile(const QString &collectionName, const QUrl &url);
Q_INVOKABLE bool addCollectionToDataStore(const QString &collectionName);

View File

@@ -20,6 +20,7 @@
#include <qmljstools/qmljscodestylepreferences.h>
#include <qmljstools/qmljstoolssettings.h>
#include <coreplugin/documentmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectmanager.h>
@@ -301,6 +302,7 @@ void DataStoreModelNode::updateSingletonFile()
imports += QStringLiteral("import %1\n").arg(import.toString(true));
QString content = pragmaSingleTone + imports + getModelQmlText();
Core::DocumentManager::expectFileChange(dataStoreQmlFilePath());
FileSaver file(dataStoreQmlFilePath());
file.write(content.toLatin1());
file.finalize();