2023-08-25 11:28:29 +03:00
|
|
|
// Copyright (C) 2023 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
|
|
|
|
|
|
#include "collectionview.h"
|
2023-09-22 10:50:06 +03:00
|
|
|
|
2023-10-12 16:34:06 +03:00
|
|
|
#include "collectiondetailsmodel.h"
|
2023-09-22 10:50:06 +03:00
|
|
|
#include "collectioneditorconstants.h"
|
2023-09-26 17:08:20 +03:00
|
|
|
#include "collectionsourcemodel.h"
|
2023-08-25 11:28:29 +03:00
|
|
|
#include "collectionwidget.h"
|
|
|
|
|
#include "designmodecontext.h"
|
2023-09-22 10:50:06 +03:00
|
|
|
#include "nodeabstractproperty.h"
|
2023-08-25 11:28:29 +03:00
|
|
|
#include "nodemetainfo.h"
|
|
|
|
|
#include "qmldesignerplugin.h"
|
|
|
|
|
#include "variantproperty.h"
|
|
|
|
|
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QJsonObject>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
namespace {
|
2023-09-22 10:50:06 +03:00
|
|
|
inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
|
2023-08-25 11:28:29 +03:00
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
using namespace QmlDesigner::CollectionEditor;
|
|
|
|
|
return node.metaInfo().typeName() == JSONCOLLECTIONMODEL_TYPENAME
|
|
|
|
|
|| node.metaInfo().typeName() == CSVCOLLECTIONMODEL_TYPENAME;
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
|
|
|
|
CollectionView::CollectionView(ExternalDependenciesInterface &externalDependencies)
|
|
|
|
|
: AbstractView(externalDependencies)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
bool CollectionView::hasWidget() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QmlDesigner::WidgetInfo CollectionView::widgetInfo()
|
|
|
|
|
{
|
|
|
|
|
if (m_widget.isNull()) {
|
|
|
|
|
m_widget = new CollectionWidget(this);
|
|
|
|
|
|
|
|
|
|
auto collectionEditorContext = new Internal::CollectionEditorContext(m_widget.data());
|
|
|
|
|
Core::ICore::addContextObject(collectionEditorContext);
|
2023-09-26 17:08:20 +03:00
|
|
|
CollectionSourceModel *sourceModel = m_widget->sourceModel().data();
|
2023-09-08 15:14:42 +03:00
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
connect(sourceModel,
|
|
|
|
|
&CollectionSourceModel::collectionSelected,
|
|
|
|
|
this,
|
|
|
|
|
[this](const ModelNode &sourceNode, const QString &collection) {
|
2023-10-12 16:34:06 +03:00
|
|
|
m_widget->collectionDetailsModel()->loadCollection(sourceNode, collection);
|
2023-09-22 10:50:06 +03:00
|
|
|
});
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return createWidgetInfo(m_widget.data(),
|
|
|
|
|
"CollectionEditor",
|
|
|
|
|
WidgetInfo::LeftPane,
|
|
|
|
|
0,
|
|
|
|
|
tr("Collection Editor"),
|
|
|
|
|
tr("Collection Editor view"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectionView::modelAttached(Model *model)
|
|
|
|
|
{
|
|
|
|
|
AbstractView::modelAttached(model);
|
|
|
|
|
refreshModel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectionView::nodeReparented(const ModelNode &node,
|
2023-09-22 10:50:06 +03:00
|
|
|
[[maybe_unused]] const NodeAbstractProperty &newPropertyParent,
|
|
|
|
|
[[maybe_unused]] const NodeAbstractProperty &oldPropertyParent,
|
2023-08-25 11:28:29 +03:00
|
|
|
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
|
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
if (!isStudioCollectionModel(node))
|
2023-08-25 11:28:29 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
refreshModel();
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
m_widget->sourceModel()->selectSource(node);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectionView::nodeAboutToBeRemoved(const ModelNode &removedNode)
|
|
|
|
|
{
|
|
|
|
|
// removing the collections lib node
|
2023-09-22 10:50:06 +03:00
|
|
|
if (isStudioCollectionModel(removedNode))
|
|
|
|
|
m_widget->sourceModel()->removeSource(removedNode);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
void CollectionView::nodeRemoved(const ModelNode &removedNode,
|
|
|
|
|
[[maybe_unused]] const NodeAbstractProperty &parentProperty,
|
2023-08-25 11:28:29 +03:00
|
|
|
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
|
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
if (isStudioCollectionModel(removedNode))
|
|
|
|
|
m_widget->sourceModel()->updateSelectedSource(true);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectionView::variantPropertiesChanged(const QList<VariantProperty> &propertyList,
|
|
|
|
|
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
|
|
|
|
{
|
|
|
|
|
for (const VariantProperty &property : propertyList) {
|
|
|
|
|
ModelNode node(property.parentModelNode());
|
2023-09-22 10:50:06 +03:00
|
|
|
if (isStudioCollectionModel(node)) {
|
2023-08-25 11:28:29 +03:00
|
|
|
if (property.name() == "objectName")
|
2023-09-26 17:08:20 +03:00
|
|
|
m_widget->sourceModel()->updateNodeName(node);
|
2023-09-22 10:50:06 +03:00
|
|
|
else if (property.name() == CollectionEditor::SOURCEFILE_PROPERTY)
|
|
|
|
|
m_widget->sourceModel()->updateNodeSource(node);
|
2023-08-25 11:28:29 +03:00
|
|
|
else if (property.name() == "id")
|
2023-09-26 17:08:20 +03:00
|
|
|
m_widget->sourceModel()->updateNodeId(node);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectionView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
|
|
|
|
[[maybe_unused]] const QList<ModelNode> &lastSelectedNodeList)
|
|
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
QList<ModelNode> selectedJsonCollections = Utils::filtered(selectedNodeList,
|
|
|
|
|
&isStudioCollectionModel);
|
2023-08-25 11:28:29 +03:00
|
|
|
|
|
|
|
|
// More than one collections are selected. So ignore them
|
2023-09-22 10:50:06 +03:00
|
|
|
if (selectedJsonCollections.size() > 1)
|
2023-08-25 11:28:29 +03:00
|
|
|
return;
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
if (selectedJsonCollections.size() == 1) { // If exactly one collection is selected
|
|
|
|
|
m_widget->sourceModel()->selectSource(selectedJsonCollections.first());
|
2023-08-25 11:28:29 +03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
void CollectionView::addResource(const QUrl &url, const QString &name, const QString &type)
|
|
|
|
|
{
|
|
|
|
|
executeInTransaction(Q_FUNC_INFO, [this, &url, &name, &type]() {
|
|
|
|
|
ensureStudioModelImport();
|
|
|
|
|
QString sourceAddress = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
|
|
|
|
const NodeMetaInfo resourceMetaInfo = type.compare("json", Qt::CaseInsensitive) == 0
|
|
|
|
|
? jsonCollectionMetaInfo()
|
|
|
|
|
: csvCollectionMetaInfo();
|
|
|
|
|
ModelNode resourceNode = createModelNode(resourceMetaInfo.typeName(),
|
|
|
|
|
resourceMetaInfo.majorVersion(),
|
|
|
|
|
resourceMetaInfo.minorVersion());
|
|
|
|
|
VariantProperty sourceProperty = resourceNode.variantProperty(
|
|
|
|
|
CollectionEditor::SOURCEFILE_PROPERTY);
|
|
|
|
|
VariantProperty nameProperty = resourceNode.variantProperty("objectName");
|
|
|
|
|
sourceProperty.setValue(sourceAddress);
|
|
|
|
|
nameProperty.setValue(name);
|
|
|
|
|
rootModelNode().defaultNodeAbstractProperty().reparentHere(resourceNode);
|
2023-08-25 11:28:29 +03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-18 11:41:18 +03:00
|
|
|
void CollectionView::registerDeclarativeType()
|
|
|
|
|
{
|
|
|
|
|
CollectionDetails::registerDeclarativeType();
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 11:28:29 +03:00
|
|
|
void CollectionView::refreshModel()
|
|
|
|
|
{
|
|
|
|
|
if (!model())
|
|
|
|
|
return;
|
|
|
|
|
|
2023-10-06 12:39:33 +03:00
|
|
|
// Load Collections
|
|
|
|
|
const ModelNodes collectionSourceNodes = rootModelNode().subModelNodesOfType(
|
|
|
|
|
jsonCollectionMetaInfo())
|
|
|
|
|
+ rootModelNode().subModelNodesOfType(
|
|
|
|
|
csvCollectionMetaInfo());
|
|
|
|
|
m_widget->sourceModel()->setSources(collectionSourceNodes);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
NodeMetaInfo CollectionView::jsonCollectionMetaInfo() const
|
2023-08-25 11:28:29 +03:00
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
return model()->metaInfo(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
NodeMetaInfo CollectionView::csvCollectionMetaInfo() const
|
2023-08-25 11:28:29 +03:00
|
|
|
{
|
2023-09-22 10:50:06 +03:00
|
|
|
return model()->metaInfo(CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME);
|
2023-08-25 11:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 10:50:06 +03:00
|
|
|
void CollectionView::ensureStudioModelImport()
|
2023-08-25 11:28:29 +03:00
|
|
|
{
|
|
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2023-09-22 10:50:06 +03:00
|
|
|
Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT);
|
|
|
|
|
try {
|
|
|
|
|
if (!model()->hasImport(import, true, true))
|
|
|
|
|
model()->changeImports({import}, {});
|
|
|
|
|
} catch (const Exception &) {
|
|
|
|
|
QTC_ASSERT(false, return);
|
|
|
|
|
}
|
2023-08-25 11:28:29 +03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace QmlDesigner
|