From 6eb522f0cab48e9107c5c15bced80bd5c1c7193d Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Tue, 31 Oct 2023 10:28:03 +0200 Subject: [PATCH] QmlDesigner: Apply collection renames to the sources Task-number: QDS-11071 Change-Id: Ia03c11d3f61e12c1f71aba147d7686787dffb4a1 Reviewed-by: Mats Honkamaa --- .../collectioneditor/collectionlistmodel.cpp | 14 +- .../collectionsourcemodel.cpp | 131 ++++++++++++++++-- .../collectioneditor/collectionsourcemodel.h | 3 + .../collectioneditor/collectionwidget.cpp | 2 + 4 files changed, 133 insertions(+), 17 deletions(-) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp index 2d7952c1021..3745fef6983 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp @@ -20,6 +20,7 @@ bool containsItem(const std::initializer_list &container, const Value auto it = std::find(begin, end, value); return it != end; } + } // namespace namespace QmlDesigner { @@ -52,8 +53,17 @@ bool CollectionListModel::setData(const QModelIndex &index, const QVariant &valu if (!index.isValid()) return false; - if (containsItem({IdRole, Qt::EditRole, Qt::DisplayRole}, role)) { - return Super::setData(index, value); + if (containsItem({Qt::EditRole, Qt::DisplayRole, NameRole}, role)) { + if (contains(value.toString())) + return false; + + QString oldName = collectionNameAt(index.row()); + bool nameChanged = Super::setData(index, value); + if (nameChanged) { + QString newName = collectionNameAt(index.row()); + emit this->collectionNameChanged(oldName, newName); + } + return nameChanged; } else if (role == SelectedRole) { if (value.toBool() != index.data(SelectedRole).toBool()) { setSelectedIndex(value.toBool() ? index.row() : -1); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index a33aff95787..3dfec1829b6 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -232,11 +232,7 @@ void CollectionSourceModel::setSources(const ModelNodes &sources) auto loadedCollection = loadCollection(collectionSource); m_collectionList.append(loadedCollection); - connect(loadedCollection.data(), - &CollectionListModel::selectedIndexChanged, - this, - &CollectionSourceModel::onSelectedCollectionChanged, - Qt::UniqueConnection); + registerCollection(loadedCollection); } updateEmpty(); @@ -269,11 +265,7 @@ void CollectionSourceModel::addSource(const ModelNode &node) auto loadedCollection = loadCollection(node); m_collectionList.append(loadedCollection); - connect(loadedCollection.data(), - &CollectionListModel::selectedIndexChanged, - this, - &CollectionSourceModel::onSelectedCollectionChanged, - Qt::UniqueConnection); + registerCollection(loadedCollection); updateEmpty(); endInsertRows(); @@ -328,30 +320,32 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) - return returnError(tr("Selected node should have a valid source file address")); + 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 open the file to read.\n") + jsonFile.errorString()); + return returnError(tr("Can't read or write \"%1\".\n%2") + .arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString())); QJsonParseError parseError; QJsonDocument document = QJsonDocument::fromJson(jsonFile.readAll(), &parseError); if (parseError.error != QJsonParseError::NoError) - return returnError(tr("Saved json file is messy.\n") + parseError.errorString()); + return returnError(tr("\"%1\" is corrupted.\n%2") + .arg(sourceFileInfo.absoluteFilePath(), parseError.errorString())); if (document.isObject()) { QJsonObject sourceObject = document.object(); sourceObject.insert(collectionName, QJsonArray{}); document.setObject(sourceObject); if (!jsonFile.resize(0)) - return returnError(tr("Can't clean the json file.")); + 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()) - return returnError(tr("Can't write to the json file.")); + return returnError(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath())); updateCollectionList(index(idx)); @@ -456,6 +450,98 @@ void CollectionSourceModel::onSelectedCollectionChanged(int collectionIndex) } } +void CollectionSourceModel::onCollectionNameChanged(const QString &oldName, const QString &newName) +{ + CollectionListModel *collectionList = qobject_cast(sender()); + QTC_ASSERT(collectionList, return); + + auto emitRenameWarning = [this](const QString &msg) -> void { + emit this->warning(tr("Rename Collection"), msg); + }; + + const ModelNode node = collectionList->sourceNode(); + const QModelIndex nodeIndex = indexOfNode(node); + + if (!nodeIndex.isValid()) { + emitRenameWarning(tr("Invalid node")); + return; + } + + if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) { + if (!setData(nodeIndex, newName, NameRole)) + emitRenameWarning(tr("Can't rename the node")); + return; + } else if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) { + emitRenameWarning(tr("Invalid node type")); + return; + } + + QString sourceFileAddress = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY) + .value() + .toString(); + + QFileInfo sourceFileInfo(sourceFileAddress); + if (!sourceFileInfo.isFile()) { + emitRenameWarning(tr("Selected node must have a valid source file address")); + return; + } + + QFile jsonFile(sourceFileAddress); + if (!jsonFile.open(QFile::ReadWrite)) { + return emitRenameWarning(tr("Can't read or write \"%1\".\n%2") + .arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString())); + return; + } + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(jsonFile.readAll(), &parseError); + if (parseError.error != QJsonParseError::NoError) { + emitRenameWarning(tr("\"%1\" is corrupted.\n%2") + .arg(sourceFileInfo.absoluteFilePath(), parseError.errorString())); + return; + } + + if (document.isObject()) { + QJsonObject rootObject = document.object(); + + bool collectionContainsOldName = rootObject.contains(oldName); + bool collectionContainsNewName = rootObject.contains(newName); + + if (!collectionContainsOldName) { + emitRenameWarning( + tr("Collection doesn't contain the old collection name (%1).").arg(oldName)); + return; + } + + if (collectionContainsNewName) { + emitRenameWarning( + tr("The collection name \"%1\" already exists in the source file.").arg(newName)); + return; + } + + QJsonValue oldValue = rootObject.value(oldName); + rootObject.insert(newName, oldValue); + 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()) { + emitRenameWarning(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath())); + return; + } + + updateCollectionList(nodeIndex); + } +} + void CollectionSourceModel::setSelectedIndex(int idx) { idx = (idx > -1 && idx < m_collectionSources.count()) ? idx : -1; @@ -514,6 +600,21 @@ void CollectionSourceModel::updateCollectionList(QModelIndex index) } } +void CollectionSourceModel::registerCollection(const QSharedPointer &collection) +{ + connect(collection.data(), + &CollectionListModel::selectedIndexChanged, + this, + &CollectionSourceModel::onSelectedCollectionChanged, + Qt::UniqueConnection); + + connect(collection.data(), + &CollectionListModel::collectionNameChanged, + this, + &CollectionSourceModel::onCollectionNameChanged, + Qt::UniqueConnection); +} + QModelIndex CollectionSourceModel::indexOfNode(const ModelNode &node) const { return index(m_sourceIndexHash.value(node.internalId(), -1)); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index 447df5d5dea..2da625502c2 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -75,14 +75,17 @@ signals: void selectedIndexChanged(int idx); void collectionSelected(const ModelNode &sourceNode, const QString &collectionName); void isEmptyChanged(bool); + void warning(const QString &title, const QString &body); private slots: void onSelectedCollectionChanged(int collectionIndex); + void onCollectionNameChanged(const QString &oldName, const QString &newName); private: void setSelectedIndex(int idx); void updateEmpty(); void updateCollectionList(QModelIndex index); + void registerCollection(const QSharedPointer &collection); QModelIndex indexOfNode(const ModelNode &node) const; using Super = QAbstractListModel; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 2cb09044be1..e956f5a2932 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -71,6 +71,8 @@ CollectionWidget::CollectionWidget(CollectionView *view) icontext->setContext(context); icontext->setWidget(this); + connect(m_sourceModel, &CollectionSourceModel::warning, this, &CollectionWidget::warn); + m_collectionDetailsSortFilterModel->setSourceModel(m_collectionDetailsModel); m_quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_COLLECTION_EDITOR);