forked from qt-creator/qt-creator
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:
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"colorCode": "#ff0000",
|
||||
"name": "Red"
|
||||
},
|
||||
{
|
||||
"colorCode": "#00ff00",
|
||||
"name": "Green"
|
||||
},
|
||||
{
|
||||
"colorCode": "#0000ff",
|
||||
"name": "Blue"
|
||||
},
|
||||
{
|
||||
"colorCode": "#ffffff",
|
||||
"name": "White"
|
||||
}
|
||||
]
|
@@ -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();
|
||||
|
@@ -43,6 +43,8 @@ bool hasTextRoleProperty(const ModelNode &node);
|
||||
|
||||
QJsonObject defaultCollection();
|
||||
|
||||
QJsonObject defaultColorCollection();
|
||||
|
||||
QString dataTypeToString(CollectionDetails::DataType dataType);
|
||||
|
||||
CollectionDetails::DataType dataTypeFromString(const QString &dataType);
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
{},
|
||||
|
@@ -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();
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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()) {
|
||||
|
Reference in New Issue
Block a user