diff options
author | Ali Kianian <ali.kianian@qt.io> | 2024-02-09 14:14:19 +0200 |
---|---|---|
committer | Ali Kianian <ali.kianian@qt.io> | 2024-02-20 11:02:17 +0000 |
commit | bb63198f8ada23c9c1e0ba20555077d332185cc6 (patch) | |
tree | 011e05b3419d7c03d4ddf276c4a0cc55d97be3e7 | |
parent | 0f9782070ab33897815e1fcaff3718de86cd9e9d (diff) |
QmlDesigner: Open collection editor for dropped ListView
* A default color model will be created and assigned to the ListView
when a ListView is dropped to the view.
* The user can edit the assigned collection of the list model by having
access to an action in the context menu of the form editor.
Task-number: QDS-11671
Fixes: QDS-11792
Change-Id: I70252f6e34ccbc95d8b700459f45a11a76c81c50
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
20 files changed, 318 insertions, 55 deletions
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/Colors.json.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/Colors.json.tpl new file mode 100644 index 0000000000..052b7abd01 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/Colors.json.tpl @@ -0,0 +1,18 @@ +[ + { + "colorCode": "#ff0000", + "name": "Red" + }, + { + "colorCode": "#00ff00", + "name": "Green" + }, + { + "colorCode": "#0000ff", + "name": "Blue" + }, + { + "colorCode": "#ffffff", + "name": "White" + } +] diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 7fc6eec379..fc92512635 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -381,6 +381,29 @@ QJsonObject defaultCollection() return collectionObject; } +QJsonObject defaultColorCollection() +{ + using Utils::FilePath; + using Utils::FileReader; + const FilePath templatePath = findFile(Core::ICore::resourcePath(), "Colors.json.tpl"); + + FileReader fileReader; + if (!fileReader.fetch(templatePath)) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the file" << templatePath; + return {}; + } + + QJsonParseError parseError; + const CollectionDetails collection = CollectionDetails::fromImportedJson(fileReader.data(), + &parseError); + if (parseError.error != QJsonParseError::NoError) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Error in template file" << parseError.errorString(); + return {}; + } + + return collection.toLocalJson(); +} + QString dataTypeToString(CollectionDetails::DataType dataType) { static const QHash<DataType, QString> typeStringHash = CollectionDataTypeHelper::typeToStringHash(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 35a036c4e3..bd9e24d23c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -43,6 +43,8 @@ bool hasTextRoleProperty(const ModelNode &node); QJsonObject defaultCollection(); +QJsonObject defaultColorCollection(); + QString dataTypeToString(CollectionDetails::DataType dataType); CollectionDetails::DataType dataTypeFromString(const QString &dataType); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp index 214ece078a..323f0e767f 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp @@ -3,9 +3,7 @@ #include "collectionlistmodel.h" -#include "collectioneditorconstants.h" #include "collectioneditorutils.h" -#include "variantproperty.h" #include <utils/algorithm.h> #include <utils/qtcassert.h> @@ -27,7 +25,7 @@ bool containsItem(const std::initializer_list<ValueType> &container, const Value namespace QmlDesigner { CollectionListModel::CollectionListModel(const ModelNode &sourceModel) - : QStringListModel() + : QAbstractListModel() , m_sourceNode(sourceModel) , m_sourceType(CollectionEditorUtils::getSourceCollectionType(sourceModel)) { @@ -50,6 +48,11 @@ QHash<int, QByteArray> CollectionListModel::roleNames() const return roles; } +int CollectionListModel::rowCount([[maybe_unused]] const QModelIndex &parent) const +{ + return m_data.count(); +} + bool CollectionListModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) @@ -60,9 +63,11 @@ bool CollectionListModel::setData(const QModelIndex &index, const QVariant &valu return false; QString oldName = collectionNameAt(index.row()); - bool nameChanged = Super::setData(index, value); + bool nameChanged = value != data(index); if (nameChanged) { - QString newName = collectionNameAt(index.row()); + QString newName = value.toString(); + m_data.replace(index.row(), newName); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); emit this->collectionNameChanged(oldName, newName); } return nameChanged; @@ -78,22 +83,26 @@ bool CollectionListModel::setData(const QModelIndex &index, const QVariant &valu bool CollectionListModel::removeRows(int row, int count, const QModelIndex &parent) { const int rows = rowCount(parent); - if (count < 1 || row >= rows) + if (row >= rows) return false; row = qBound(0, row, rows - 1); - count = qBound(1, count, rows - row); + count = qBound(0, count, rows - row); - QStringList removedCollections = stringList().mid(row, count); + if (count < 1) + return false; - bool itemsRemoved = Super::removeRows(row, count, parent); - if (itemsRemoved) { - emit collectionsRemoved(removedCollections); - if (m_selectedIndex >= row) - selectCollectionIndex(m_selectedIndex - count, true); - } + QStringList removedCollections = m_data.mid(row, count); - return itemsRemoved; + beginRemoveRows(parent, row, row + count - 1); + m_data.remove(row, count); + endRemoveRows(); + + emit collectionsRemoved(removedCollections); + if (m_selectedIndex >= row) + selectCollectionIndex(m_selectedIndex - count, true); + + return true; } QVariant CollectionListModel::data(const QModelIndex &index, int role) const @@ -103,13 +112,21 @@ QVariant CollectionListModel::data(const QModelIndex &index, int role) const switch (role) { case IdRole: return index.row(); - case NameRole: - return Super::data(index); case SelectedRole: return index.row() == m_selectedIndex; + case NameRole: + default: + return m_data.at(index.row()); } +} - return Super::data(index, role); +void CollectionListModel::resetModelData(const QStringList &collectionsList) +{ + QString prevSelectedCollection = selectedIndex() > -1 ? m_data.at(selectedIndex()) : QString(); + beginResetModel(); + m_data = collectionsList; + endResetModel(); + selectCollectionName(prevSelectedCollection); } int CollectionListModel::selectedIndex() const @@ -129,12 +146,17 @@ QString CollectionListModel::sourceAddress() const bool CollectionListModel::contains(const QString &collectionName) const { - return stringList().contains(collectionName); + return m_data.contains(collectionName); +} + +QStringList CollectionListModel::collections() const +{ + return m_data; } void CollectionListModel::selectCollectionIndex(int idx, bool selectAtLeastOne) { - int collectionCount = stringList().size(); + int collectionCount = m_data.size(); int preferredIndex = -1; if (collectionCount) { if (selectAtLeastOne) @@ -148,7 +170,7 @@ void CollectionListModel::selectCollectionIndex(int idx, bool selectAtLeastOne) void CollectionListModel::selectCollectionName(const QString &collectionName) { - int idx = stringList().indexOf(collectionName); + int idx = m_data.indexOf(collectionName); if (idx > -1) selectCollectionIndex(idx); } @@ -158,6 +180,19 @@ QString CollectionListModel::collectionNameAt(int idx) const return index(idx).data(NameRole).toString(); } +void CollectionListModel::addCollection(const QString &collectionName) +{ + if (m_data.contains(collectionName)) + return; + + int row = rowCount(); + beginInsertRows({}, row, row); + m_data.append(collectionName); + endInsertRows(); + + emit collectionAdded(collectionName); +} + void CollectionListModel::setSelectedIndex(int idx) { idx = (idx > -1 && idx < rowCount()) ? idx : -1; @@ -180,7 +215,7 @@ void CollectionListModel::setSelectedIndex(int idx) void CollectionListModel::updateEmpty() { - bool isEmptyNow = stringList().isEmpty(); + bool isEmptyNow = m_data.isEmpty(); if (m_isEmpty != isEmptyNow) { m_isEmpty = isEmptyNow; emit isEmptyChanged(m_isEmpty); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h index c65af750d8..092dd1d6dc 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h @@ -3,14 +3,14 @@ #pragma once +#include <QAbstractListModel> #include <QHash> -#include <QStringListModel> #include "modelnode.h" namespace QmlDesigner { -class CollectionListModel : public QStringListModel +class CollectionListModel : public QAbstractListModel { Q_OBJECT @@ -22,37 +22,44 @@ public: enum Roles { IdRole = Qt::UserRole + 1, NameRole, SourceRole, SelectedRole, CollectionsRole }; explicit CollectionListModel(const ModelNode &sourceModel); - virtual QHash<int, QByteArray> roleNames() const override; + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; bool removeRows(int row, int count, const QModelIndex &parent = {}) override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + void resetModelData(const QStringList &collectionsList); Q_INVOKABLE int selectedIndex() const; Q_INVOKABLE ModelNode sourceNode() const; Q_INVOKABLE QString sourceAddress() const; Q_INVOKABLE bool contains(const QString &collectionName) const; + Q_INVOKABLE QStringList collections() const; void selectCollectionIndex(int idx, bool selectAtLeastOne = false); void selectCollectionName(const QString &collectionName); QString collectionNameAt(int idx) const; + void addCollection(const QString &collectionName); signals: void selectedIndexChanged(int idx); void isEmptyChanged(bool); void collectionNameChanged(const QString &oldName, const QString &newName); void collectionsRemoved(const QStringList &names); + void collectionAdded(const QString &name); private: void setSelectedIndex(int idx); void updateEmpty(); - using Super = QStringListModel; + using Super = QAbstractListModel; int m_selectedIndex = -1; bool m_isEmpty = false; const ModelNode m_sourceNode; const QString m_sourceType; + + QStringList m_data; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index a76d4a0b24..13accfba0e 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -56,13 +56,13 @@ QSharedPointer<QmlDesigner::CollectionListModel> loadCollection( if (document.isObject()) { const QJsonObject sourceObject = document.object(); - collectionsList->setStringList(sourceObject.toVariantMap().keys()); + collectionsList->resetModelData(sourceObject.toVariantMap().keys()); } } else if (sourceNode.type() == CSVCOLLECTIONMODEL_TYPENAME) { QmlDesigner::VariantProperty collectionNameProperty = sourceNode.variantProperty( "objectName"); setupCollectionList(); - collectionsList->setStringList({collectionNameProperty.value().toString()}); + collectionsList->resetModelData({collectionNameProperty.value().toString()}); } return collectionsList; } @@ -209,7 +209,7 @@ void CollectionSourceModel::setSources(const ModelNodes &sources) auto loadedCollection = loadCollection(collectionSource); m_collectionList.append(loadedCollection); - registerCollection(loadedCollection); + registerCollectionList(loadedCollection); } updateEmpty(); @@ -242,7 +242,7 @@ void CollectionSourceModel::addSource(const ModelNode &node) auto loadedCollection = loadCollection(node); m_collectionList.append(loadedCollection); - registerCollection(loadedCollection); + registerCollectionList(loadedCollection); updateEmpty(); endInsertRows(); @@ -353,6 +353,26 @@ CollectionListModel *CollectionSourceModel::selectedCollectionList() return idx.data(CollectionsRole).value<CollectionListModel *>(); } +QString CollectionSourceModel::generateCollectionName(const ModelNode &node, + const QString &baseCollectionName) const +{ + int idx = sourceIndex(node); + if (idx < 0) + return {}; + + auto collections = m_collectionList.at(idx); + if (collections.isNull()) + return {}; + + const int maxNumber = std::numeric_limits<int>::max(); + for (int i = 1; i < maxNumber; ++i) { + const QString name = QLatin1String("%1_%2").arg(baseCollectionName).arg(i); + if (!collections->contains(name)) + return name; + } + return {}; +} + void CollectionSourceModel::selectSourceIndex(int idx, bool selectAtLeastOne) { int collectionCount = m_collectionSources.size(); @@ -367,6 +387,21 @@ void CollectionSourceModel::selectSourceIndex(int idx, bool selectAtLeastOne) setSelectedIndex(preferredIndex); } +void CollectionSourceModel::selectCollection(const QVariant &node, const QString &collectionName) +{ + const ModelNode sourceNode = node.value<ModelNode>(); + const QModelIndex index = indexOfNode(sourceNode); + if (!index.isValid()) + return; + + selectSource(sourceNode); + auto collections = m_collectionList.at(index.row()); + if (collections.isNull()) + return; + + collections->selectCollectionName(collectionName); +} + void CollectionSourceModel::deselect() { setSelectedIndex(-1); @@ -416,7 +451,8 @@ void CollectionSourceModel::onSelectedCollectionChanged(CollectionListModel *col } void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collectionList, - const QString &oldName, const QString &newName) + const QString &oldName, + const QString &newName) { using Utils::FilePath; using Utils::FileReader; @@ -657,13 +693,14 @@ void CollectionSourceModel::updateCollectionList(QModelIndex index) if (oldList != newList) { m_collectionList.replace(index.row(), newList); emit dataChanged(index, index, {CollectionsRole}); - registerCollection(newList); + registerCollectionList(newList); } } -void CollectionSourceModel::registerCollection(const QSharedPointer<CollectionListModel> &collection) +void CollectionSourceModel::registerCollectionList( + const QSharedPointer<CollectionListModel> &sharedCollectionList) { - CollectionListModel *collectionList = collection.data(); + CollectionListModel *collectionList = sharedCollectionList.data(); if (collectionList == nullptr) return; @@ -688,10 +725,14 @@ void CollectionSourceModel::registerCollection(const QSharedPointer<CollectionLi [this, collectionList](const QStringList &removedCollections) { onCollectionsRemoved(collectionList, removedCollections); }); + + connect(collectionList, &CollectionListModel::modelReset, this, [this, collectionList]() { + emit collectionNamesInitialized(collectionList->collections()); + }); } if (collectionList->sourceNode().isValid()) - emit collectionNamesInitialized(collection->stringList()); + emit collectionNamesInitialized(collectionList->collections()); } QModelIndex CollectionSourceModel::indexOfNode(const ModelNode &node) const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index ac01c0de22..1909b77c9a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -59,8 +59,10 @@ public: ModelNode sourceNodeAt(int idx); CollectionListModel *selectedCollectionList(); + QString generateCollectionName(const ModelNode &node, const QString &baseCollectionName) const; Q_INVOKABLE void selectSourceIndex(int idx, bool selectAtLeastOne = false); + Q_INVOKABLE void selectCollection(const QVariant &node, const QString &collectionName); Q_INVOKABLE void deselect(); Q_INVOKABLE void updateSelectedSource(bool selectAtLeastOne = false); Q_INVOKABLE bool collectionExists(const QVariant &node, const QString &collectionName) const; @@ -90,7 +92,7 @@ private: void setSelectedCollectionName(const QString &collectionName); void updateEmpty(); void updateCollectionList(QModelIndex index); - void registerCollection(const QSharedPointer<CollectionListModel> &collection); + void registerCollectionList(const QSharedPointer<CollectionListModel> &collectionList); QModelIndex indexOfNode(const ModelNode &node) const; using Super = QAbstractListModel; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index 9933ac3817..9e9405be3d 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -12,6 +12,7 @@ #include "designmodecontext.h" #include "nodeabstractproperty.h" #include "nodemetainfo.h" +#include "nodeproperty.h" #include "qmldesignerplugin.h" #include "variantproperty.h" @@ -192,6 +193,17 @@ void CollectionView::selectedNodesChanged(const QList<ModelNode> &selectedNodeLi } } +void CollectionView::customNotification(const AbstractView *, + const QString &identifier, + const QList<ModelNode> &nodeList, + const QList<QVariant> &data) +{ + if (identifier == QLatin1String("item_library_created_by_drop") && !nodeList.isEmpty()) + onItemLibraryNodeCreated(nodeList.first()); + else if (identifier == QLatin1String("open_collection_by_id") && !data.isEmpty()) + m_widget->openCollection(collectionNameFromDataStoreChildren(data.first().toByteArray())); +} + void CollectionView::addResource(const QUrl &url, const QString &name, const QString &type) { executeInTransaction(Q_FUNC_INFO, [this, &url, &name, &type]() { @@ -221,12 +233,11 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt }); } -void CollectionView::assignCollectionToSelectedNode(const QString &collectionName) +void CollectionView::assignCollectionToNode(const QString &collectionName, const ModelNode &node) { - QTC_ASSERT(dataStoreNode() && hasSingleSelectedModelNode(), return); m_dataStore->assignCollectionToNode( this, - singleSelectedModelNode(), + node, collectionName, [&](const QString &collectionName, const QString &columnName) -> bool { const CollectionReference reference{dataStoreNode(), collectionName}; @@ -238,6 +249,12 @@ void CollectionView::assignCollectionToSelectedNode(const QString &collectionNam }); } +void CollectionView::assignCollectionToSelectedNode(const QString &collectionName) +{ + QTC_ASSERT(dataStoreNode() && hasSingleSelectedModelNode(), return); + assignCollectionToNode(collectionName, singleSelectedModelNode()); +} + void CollectionView::registerDeclarativeType() { CollectionDetails::registerDeclarativeType(); @@ -255,6 +272,25 @@ ModelNode CollectionView::dataStoreNode() const return m_dataStore->modelNode(); } +void CollectionView::ensureDataStoreExists() +{ + bool filesJustCreated = false; + bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated); + if (filesExist && filesJustCreated) + resetDataStoreNode(); +} + +QString CollectionView::collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const +{ + return dataStoreNode() + .nodeProperty(childPropertyName) + .modelNode() + .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY) + .toVariantProperty() + .value() + .toString(); +} + void CollectionView::refreshModel() { if (!model()) @@ -292,4 +328,20 @@ void CollectionView::ensureStudioModelImport() }); } +void CollectionView::onItemLibraryNodeCreated(const ModelNode &node) +{ + ensureDataStoreExists(); + CollectionSourceModel *sourceModel = m_widget->sourceModel(); + + if (node.metaInfo().isQtQuickListView()) { + const QString newCollectionName = sourceModel->generateCollectionName(dataStoreNode(), + "ListModel"); + sourceModel->addCollectionToSource(dataStoreNode(), + newCollectionName, + CollectionEditorUtils::defaultColorCollection()); + assignCollectionToNode(newCollectionName, node); + m_widget->openCollection(newCollectionName); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index c08368b0c3..db3964726b 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -41,20 +41,29 @@ public: void selectedNodesChanged(const QList<ModelNode> &selectedNodeList, const QList<ModelNode> &lastSelectedNodeList) override; + void customNotification(const AbstractView *view, + const QString &identifier, + const QList<ModelNode> &nodeList, + const QList<QVariant> &data) override; + void addResource(const QUrl &url, const QString &name, const QString &type); + void assignCollectionToNode(const QString &collectionName, const ModelNode &node); void assignCollectionToSelectedNode(const QString &collectionName); static void registerDeclarativeType(); void resetDataStoreNode(); ModelNode dataStoreNode() const; + void ensureDataStoreExists(); + QString collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const; private: void refreshModel(); NodeMetaInfo jsonCollectionMetaInfo() const; NodeMetaInfo csvCollectionMetaInfo() const; void ensureStudioModelImport(); + void onItemLibraryNodeCreated(const ModelNode &node); QPointer<CollectionWidget> m_widget; std::unique_ptr<DataStoreModelNode> m_dataStore; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 79d3d563a2..d17cbb5bfd 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -9,6 +9,7 @@ #include "collectioneditorutils.h" #include "collectionsourcemodel.h" #include "collectionview.h" +#include "designmodewidget.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include "theme.h" @@ -204,7 +205,7 @@ bool CollectionWidget::isValidUrlToImport(const QUrl &url) const bool CollectionWidget::importFile(const QString &collectionName, const QUrl &url) { using Utils::FilePath; - ensureDataStoreExists(); + m_view->ensureDataStoreExists(); const ModelNode node = dataStoreNode(); if (!node.isValid()) { @@ -264,7 +265,7 @@ bool CollectionWidget::importFile(const QString &collectionName, const QUrl &url bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) { - ensureDataStoreExists(); + m_view->ensureDataStoreExists(); const ModelNode node = dataStoreNode(); if (!node.isValid()) { warn(tr("Can not import to the main model"), tr("The default model node is not available.")); @@ -288,12 +289,10 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa m_view->assignCollectionToSelectedNode(collectionName); } -void CollectionWidget::ensureDataStoreExists() +void CollectionWidget::openCollection(const QString &collectionName) { - bool filesJustCreated = false; - bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated); - if (filesExist && filesJustCreated) - m_view->resetDataStoreNode(); + m_sourceModel->selectCollection(QVariant::fromValue(m_view->dataStoreNode()), collectionName); + QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("CollectionEditor", true); } ModelNode CollectionWidget::dataStoreNode() const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 23f4ad8dbf..b4a6578580 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -43,7 +43,7 @@ public: Q_INVOKABLE bool importFile(const QString &collectionName, const QUrl &url); Q_INVOKABLE bool addCollectionToDataStore(const QString &collectionName); Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName); - Q_INVOKABLE void ensureDataStoreExists(); + Q_INVOKABLE void openCollection(const QString &collectionName); Q_INVOKABLE ModelNode dataStoreNode() const; void warn(const QString &title, const QString &body); diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h index 17ba5aa970..6a8833ef29 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h +++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h @@ -69,6 +69,7 @@ const char mergeTemplateCommandId[] = "MergeTemplate"; const char goToImplementationCommandId[] = "GoToImplementation"; const char makeComponentCommandId[] = "MakeComponent"; const char editMaterialCommandId[] = "EditMaterial"; +const char editCollectionCommandId[] = "EditCollection"; const char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer"; const char addTabBarToStackedContainerCommandId[] = "AddTabBarToStackedContainer"; const char increaseIndexOfStackedContainerCommandId[] = "IncreaseIndexOfStackedContainer"; @@ -126,6 +127,7 @@ const char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMen const char goToImplementationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go to Implementation"); const char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Component"); const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material"); +const char editCollectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Model"); const char editAnnotationsDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotations"); const char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Mouse Area"); @@ -209,6 +211,8 @@ enum PrioritiesEnum : int { SelectionCategory, ArrangeCategory, EditCategory, + EditListModel, + EditCollection, /******** Section *****************************/ PositionSection = 2000, SnappingCategory, diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 6e4b1a1efd..6441d11b73 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -840,16 +840,22 @@ public: {}, ComponentCoreConstants::rootCategory, QKeySequence("Alt+e"), - 1001, + ComponentCoreConstants::Priorities::EditListModel, &openDialog, - &isListViewInBaseState, - &isListViewInBaseState) + &isListViewInBaseStateAndHasListModel, + &isListViewInBaseStateAndHasListModel) {} - static bool isListViewInBaseState(const SelectionContext &selectionState) + static bool isListViewInBaseStateAndHasListModel(const SelectionContext &selectionState) { - return selectionState.isInBaseState() && selectionState.singleNodeIsSelected() - && selectionState.currentSingleSelectedNode().metaInfo().isListOrGridView(); + if (!selectionState.isInBaseState() || !selectionState.singleNodeIsSelected()) + return false; + + const ModelNode singleSelectedNode = selectionState.currentSingleSelectedNode(); + + return singleSelectedNode.metaInfo().isListOrGridView() + && singleSelectedNode.property("model").toNodeProperty().modelNode().type() + == "QtQml.Models.ListModel"; } bool isEnabled(const SelectionContext &) const override { return true; } @@ -1977,6 +1983,16 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new EditListModelAction); + addDesignerAction(new ModelNodeContextMenuAction(editCollectionCommandId, + editCollectionDisplayName, + contextIcon(DesignerIcons::EditIcon), + rootCategory, + QKeySequence("Alt+e"), + ComponentCoreConstants::Priorities::EditCollection, + &editCollection, + &hasCollectionAsModel, + &hasCollectionAsModel)); + addDesignerAction(new ModelNodeContextMenuAction(openSignalDialogCommandId, openSignalDialogDisplayName, {}, diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h index 6bc9c703bc..e7224f9edd 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h @@ -69,6 +69,18 @@ inline bool modelHasMaterial(const SelectionContext &selectionState) return prop.exists() && (!prop.expression().isEmpty() || !prop.resolveToModelNodeList().empty()); } +inline bool hasCollectionAsModel(const SelectionContext &selectionState) +{ + if (!selectionState.isInBaseState() || !selectionState.singleNodeIsSelected()) + return false; + + const ModelNode singleSelectedNode = selectionState.currentSingleSelectedNode(); + + return singleSelectedNode.metaInfo().isQtQuickListView() + && singleSelectedNode.property("model").toBindingProperty().expression().startsWith( + "DataStore."); +} + inline bool selectionEnabled(const SelectionContext &selectionState) { return selectionState.showSelectionTools(); diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index ae8f879017..98e0e4aef5 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -833,6 +833,30 @@ void editMaterial(const SelectionContext &selectionContext) } } +// Open a collection in the collection editor +void editCollection(const SelectionContext &selectionContext) +{ + ModelNode modelNode = selectionContext.targetNode(); + + if (!modelNode) + modelNode = selectionContext.currentSingleSelectedNode(); + + if (!modelNode) + return; + + const QString dataStoreExpression = "DataStore."; + + BindingProperty prop = modelNode.bindingProperty("model"); + if (!prop.exists() || !prop.expression().startsWith(dataStoreExpression)) + return; + + AbstractView *view = selectionContext.view(); + const QString collectionId = prop.expression().mid(dataStoreExpression.size()); + + // to CollectionEditor... + view->emitCustomNotification("open_collection_by_id", {}, {collectionId}); +} + void addItemToStackedContainer(const SelectionContext &selectionContext) { AbstractView *view = selectionContext.view(); diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 196dd4922c..4556462f30 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -92,6 +92,7 @@ void layoutGridLayout(const SelectionContext &selectionState); void goImplementation(const SelectionContext &selectionState); void addNewSignalHandler(const SelectionContext &selectionState); void editMaterial(const SelectionContext &selectionContext); +void editCollection(const SelectionContext &selectionContext); void addSignalHandlerOrGotoImplementation(const SelectionContext &selectionState, bool addAlwaysNewSlot); void removeLayout(const SelectionContext &selectionContext); void removePositioner(const SelectionContext &selectionContext); diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index e363e9bb11..0b7d199b50 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -274,6 +274,11 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneD nodeList.append(node); } view()->setSelectedModelNodes(nodeList); + + bool itemLibraryJustCreated = hasItemLibraryInfo(event->mimeData()) + && nodeList.size() == 1; + if (itemLibraryJustCreated) + view()->emitCustomNotification("item_library_created_by_drop", nodeList); } m_dragNodes.clear(); } @@ -382,7 +387,7 @@ void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSc } } -void DragTool::end() +void DragTool::end() { m_moveManipulator.end(); clear(); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 7cf02c7259..5ae3d5d720 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -796,8 +796,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in moveNodesInteractive(targetProperty, newModelNodeList, targetRowNumber); } - if (newQmlObjectNode.isValid()) + if (newQmlObjectNode.isValid()) { m_view->setSelectedModelNode(newQmlObjectNode.modelNode()); + m_view->emitCustomNotification("item_library_created_by_drop", {newQmlObjectNode}); + } } } } diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h index 58cdeba228..7e171c5445 100644 --- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h @@ -166,6 +166,7 @@ public: bool isQtQuick3DLight() const; bool isQtQuickListElement() const; bool isQtQuickListModel() const; + bool isQtQuickListView() const; bool isQtQuick3DMaterial() const; bool isQtQuick3DModel() const; bool isQtQuick3DNode() const; diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index c695f488b1..975b12ddd1 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -2766,6 +2766,16 @@ bool NodeMetaInfo::isQtQuickListModel() const } } +bool NodeMetaInfo::isQtQuickListView() const +{ + if constexpr (useProjectStorage()) { + using namespace Storage::Info; + return isBasedOnCommonType<QtQuick, ListView>(m_projectStorage, m_typeId); + } else { + return isValid() && (isSubclassOf("QtQuick.ListView")); + } +} + bool NodeMetaInfo::isQtQuick3DInstanceList() const { if constexpr (useProjectStorage()) { |