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>
This commit is contained in:
Ali Kianian
2024-02-09 14:14:19 +02:00
parent 0f9782070a
commit bb63198f8a
20 changed files with 318 additions and 55 deletions

View File

@@ -0,0 +1,18 @@
[
{
"colorCode": "#ff0000",
"name": "Red"
},
{
"colorCode": "#00ff00",
"name": "Green"
},
{
"colorCode": "#0000ff",
"name": "Blue"
},
{
"colorCode": "#ffffff",
"name": "White"
}
]

View File

@@ -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();

View File

@@ -43,6 +43,8 @@ bool hasTextRoleProperty(const ModelNode &node);
QJsonObject defaultCollection();
QJsonObject defaultColorCollection();
QString dataTypeToString(CollectionDetails::DataType dataType);
CollectionDetails::DataType dataTypeFromString(const QString &dataType);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,
{},

View File

@@ -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();

View File

@@ -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();

View File

@@ -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);

View File

@@ -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();

View File

@@ -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});
}
}
}
}

View File

@@ -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;

View File

@@ -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()) {