forked from qt-creator/qt-creator
QmlDesigner: Improve node creation with project storage
The file url was missing, so no valid source id could be created. That lead to invalid imports. The qualified path for the node instances is now created in the node instance view. Change-Id: I2685ab2fdbdb0fa8a5f89793be52c8fae2b8db8c Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
@@ -64,13 +64,14 @@ namespace QmlDesigner {
|
||||
DesignDocument acts as a facade to a model representing a qml document,
|
||||
and the different views/widgets accessing it.
|
||||
*/
|
||||
DesignDocument::DesignDocument(ProjectStorageDependencies projectStorageDependencies,
|
||||
DesignDocument::DesignDocument([[maybe_unused]] const QUrl &filePath,
|
||||
ProjectStorageDependencies projectStorageDependencies,
|
||||
ExternalDependenciesInterface &externalDependencies)
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
: m_documentModel(Model::create(projectStorageDependencies,
|
||||
"Item",
|
||||
{Import::createLibraryImport("QtQuick")},
|
||||
{},
|
||||
filePath,
|
||||
std::make_unique<ModelResourceManagement>()))
|
||||
#else
|
||||
: m_documentModel(
|
||||
|
@@ -41,7 +41,8 @@ class QMLDESIGNERCOMPONENTS_EXPORT DesignDocument : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DesignDocument(ProjectStorageDependencies projectStorageDependencies,
|
||||
DesignDocument(const QUrl &filePath,
|
||||
ProjectStorageDependencies projectStorageDependencies,
|
||||
ExternalDependenciesInterface &externalDependencies);
|
||||
~DesignDocument() override;
|
||||
|
||||
|
@@ -166,6 +166,7 @@ public:
|
||||
NodeMetaInfo qtQmlConnectionsMetaInfo() const;
|
||||
NodeMetaInfo qtQmlModelsListModelMetaInfo() const;
|
||||
NodeMetaInfo qtQmlModelsListElementMetaInfo() const;
|
||||
NodeMetaInfo qtQmlXmlListModelXmlListModelRoleMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const;
|
||||
|
@@ -167,6 +167,7 @@ public:
|
||||
bool isQtMultimediaSoundEffect() const;
|
||||
bool isQtObject() const;
|
||||
bool isQtQmlConnections() const;
|
||||
bool isQtQmlModelsListElement() const;
|
||||
bool isQtQuick3DBakedLightmap() const;
|
||||
bool isQtQuick3DBuffer() const;
|
||||
bool isQtQuick3DCamera() const;
|
||||
@@ -176,7 +177,6 @@ public:
|
||||
bool isQtQuick3DInstanceList() const;
|
||||
bool isQtQuick3DInstanceListEntry() const;
|
||||
bool isQtQuick3DLight() const;
|
||||
bool isQtQuickListElement() const;
|
||||
bool isQtQuickListModel() const;
|
||||
bool isQtQuickListView() const;
|
||||
bool isQtQuick3DMaterial() const;
|
||||
|
@@ -64,6 +64,8 @@
|
||||
#include <qmlitemnode.h>
|
||||
#include <rewriterview.h>
|
||||
|
||||
#include <projectstorage/projectstorage.h>
|
||||
|
||||
#include <utils/hdrimage.h>
|
||||
|
||||
#include <coreplugin/messagemanager.h>
|
||||
@@ -205,22 +207,17 @@ NodeInstanceView::~NodeInstanceView()
|
||||
|
||||
static bool isSkippedRootNode(const ModelNode &node)
|
||||
{
|
||||
static const PropertyNameList skipList({"Qt.ListModel", "QtQuick.ListModel", "Qt.ListModel", "QtQuick.ListModel"});
|
||||
|
||||
if (skipList.contains(node.type()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return node.metaInfo().isQtQuickListModel();
|
||||
}
|
||||
|
||||
static bool isSkippedNode(const ModelNode &node)
|
||||
{
|
||||
static const PropertyNameList skipList({"QtQuick.XmlRole", "Qt.XmlRole", "QtQuick.ListElement", "Qt.ListElement"});
|
||||
auto model = node.model();
|
||||
|
||||
if (skipList.contains(node.type()))
|
||||
return true;
|
||||
auto listElement = model->qtQmlModelsListElementMetaInfo();
|
||||
auto xmlRole = model->qtQmlXmlListModelXmlListModelRoleMetaInfo();
|
||||
|
||||
return false;
|
||||
return node.metaInfo().isBasedOn(listElement, xmlRole);
|
||||
}
|
||||
|
||||
static bool parentTakesOverRendering(const ModelNode &modelNode)
|
||||
@@ -644,7 +641,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
|
||||
TypeName(),
|
||||
key.type};
|
||||
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case AuxiliaryDataType::NodeInstanceAuxiliary:
|
||||
@@ -656,7 +653,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
|
||||
TypeName(),
|
||||
key.type};
|
||||
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case AuxiliaryDataType::NodeInstancePropertyOverwrite:
|
||||
@@ -991,6 +988,8 @@ QRectF NodeInstanceView::sceneRect() const
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
|
||||
{
|
||||
QList<ModelNode> filteredNodeList;
|
||||
@@ -1003,14 +1002,12 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
|
||||
|
||||
return filteredNodeList;
|
||||
}
|
||||
namespace {
|
||||
bool shouldSendAuxiliary(const AuxiliaryDataKey &key)
|
||||
{
|
||||
return key.type == AuxiliaryDataType::NodeInstancePropertyOverwrite
|
||||
|| key.type == AuxiliaryDataType::NodeInstanceAuxiliary || key == invisibleProperty
|
||||
|| key == lockedProperty;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool parentIsBehavior(ModelNode node)
|
||||
{
|
||||
@@ -1024,6 +1021,31 @@ bool parentIsBehavior(ModelNode node)
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeName createQualifiedTypeName(const ModelNode &node)
|
||||
{
|
||||
if (!node)
|
||||
return {};
|
||||
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
auto model = node.model();
|
||||
auto exportedTypes = node.metaInfo().exportedTypeNamesForSourceId(model->fileUrlSourceId());
|
||||
if (exportedTypes.size()) {
|
||||
const auto &exportedType = exportedTypes.front();
|
||||
Utils::PathString typeName = model->projectStorage()->moduleName(exportedType.moduleId);
|
||||
typeName += '/';
|
||||
typeName += exportedType.name;
|
||||
|
||||
return typeName.toQByteArray();
|
||||
}
|
||||
|
||||
return {};
|
||||
#else
|
||||
return node.type();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
|
||||
{
|
||||
QList<ModelNode> nodeList = allModelNodes();
|
||||
@@ -1079,8 +1101,9 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
|
||||
nodeFlags |= InstanceContainer::ParentTakesOverRendering;
|
||||
|
||||
const auto modelNode = instance.modelNode();
|
||||
|
||||
InstanceContainer container(instance.instanceId(),
|
||||
modelNode.type(),
|
||||
createQualifiedTypeName(modelNode),
|
||||
modelNode.majorVersion(),
|
||||
modelNode.minorVersion(),
|
||||
ModelUtils::componentFilePath(modelNode),
|
||||
@@ -1243,7 +1266,7 @@ CreateInstancesCommand NodeInstanceView::createCreateInstancesCommand(const QLis
|
||||
|
||||
const auto modelNode = instance.modelNode();
|
||||
InstanceContainer container(instance.instanceId(),
|
||||
modelNode.type(),
|
||||
createQualifiedTypeName(modelNode),
|
||||
modelNode.majorVersion(),
|
||||
modelNode.minorVersion(),
|
||||
ModelUtils::componentFilePath(modelNode),
|
||||
@@ -1850,7 +1873,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo
|
||||
|
||||
ModelNodePreviewImageData imageData;
|
||||
imageData.id = modelNode.id();
|
||||
imageData.type = QString::fromLatin1(modelNode.type());
|
||||
imageData.type = QString::fromUtf8(createQualifiedTypeName(modelNode));
|
||||
const double ratio = m_externalDependencies.formEditorDevicePixelRatio();
|
||||
|
||||
if (imageSource.isEmpty() && modelNode.metaInfo().isQtQuick3DTexture()) {
|
||||
@@ -1958,7 +1981,7 @@ QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &model
|
||||
if (m_imageDataMap.contains(id)) {
|
||||
imageData = m_imageDataMap[id];
|
||||
} else {
|
||||
imageData.type = QString::fromLatin1(modelNode.type());
|
||||
imageData.type = QString::fromLatin1(createQualifiedTypeName(modelNode));
|
||||
imageData.id = id;
|
||||
m_imageDataMap.insert(id, imageData);
|
||||
}
|
||||
|
@@ -2766,7 +2766,7 @@ bool NodeMetaInfo::isQtQuick3DLight() const
|
||||
}
|
||||
}
|
||||
|
||||
bool NodeMetaInfo::isQtQuickListElement() const
|
||||
bool NodeMetaInfo::isQtQmlModelsListElement() const
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
using namespace Storage::Info;
|
||||
|
@@ -2210,6 +2210,16 @@ NodeMetaInfo Model::qtQmlModelsListElementMetaInfo() const
|
||||
}
|
||||
}
|
||||
|
||||
NodeMetaInfo Model::qtQmlXmlListModelXmlListModelRoleMetaInfo() const
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
using namespace Storage::Info;
|
||||
return createNodeMetaInfo<QtQml_XmlListModel, XmlListModelRole>();
|
||||
} else {
|
||||
return metaInfo("QtQml.XmlListModel.XmlListModelRole");
|
||||
}
|
||||
}
|
||||
|
||||
NodeMetaInfo Model::qmlQtObjectMetaInfo() const
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
|
@@ -501,7 +501,7 @@ public:
|
||||
if (!propertyMetaInfo.isValid()) {
|
||||
const bool isAttached = !propertyName.isEmpty() && propertyName[0].isUpper();
|
||||
// Only list elements might have unknown properties.
|
||||
if (!node.metaInfo().isQtQuickListElement() && !isAttached) {
|
||||
if (!node.metaInfo().isQtQmlModelsListElement() && !isAttached) {
|
||||
qCInfo(texttomodelMergerLog)
|
||||
<< Q_FUNC_INFO << "\nUnknown property"
|
||||
<< propertyPrefix + QLatin1Char('.') + toString(propertyId) << "on line"
|
||||
|
@@ -91,6 +91,7 @@ inline constexpr char QtMultimedia[] = "QtMultimedia";
|
||||
inline constexpr char QtObject[] = "QtObject";
|
||||
inline constexpr char QtQml[] = "QtQml";
|
||||
inline constexpr char QtQml_Models[] = "QtQml.Models";
|
||||
inline constexpr char QtQml_XmlListModel[] = "QtQml.XmlListModel";
|
||||
inline constexpr char QtQuick3D[] = "QtQuick3D";
|
||||
inline constexpr char QtQuick3D_Particles3D[] = "QtQuick3D.Particles3D";
|
||||
inline constexpr char QtQuick3D_Particles3D_cppnative[] = "QtQuick3D.Particles3D-cppnative";
|
||||
@@ -131,6 +132,7 @@ inline constexpr char Transition[] = "Transition";
|
||||
inline constexpr char UIntType[] = "uint";
|
||||
inline constexpr char View3D[] = "View3D";
|
||||
inline constexpr char Window[] = "Window";
|
||||
inline constexpr char XmlListModelRole[] = "XmlListModelRole";
|
||||
inline constexpr char color[] = "color";
|
||||
inline constexpr char date[] = "date";
|
||||
inline constexpr char font[] = "font";
|
||||
@@ -176,6 +178,7 @@ class CommonTypeCache
|
||||
CacheType<QtMultimedia, SoundEffect>,
|
||||
CacheType<QtQml_Models, ListElement>,
|
||||
CacheType<QtQml_Models, ListModel>,
|
||||
CacheType<QtQml_XmlListModel, XmlListModelRole>,
|
||||
CacheType<QtQuick, BorderImage>,
|
||||
CacheType<QtQuick, GridView>,
|
||||
CacheType<QtQuick, Image>,
|
||||
|
@@ -168,7 +168,7 @@ public:
|
||||
return moduleId;
|
||||
}
|
||||
|
||||
Utils::SmallString moduleName(ModuleId moduleId) const
|
||||
Utils::SmallString moduleName(ModuleId moduleId) const override
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"get module name"_t,
|
||||
@@ -3278,8 +3278,9 @@ private:
|
||||
auto update = [&](const TypeWithDefaultPropertyView &view,
|
||||
const Storage::Synchronization::Type &value) {
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"reset default properties by update"_t,
|
||||
NanotraceHR::Tracer tracer{"synchronize default properties by update"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("type id", value.typeId),
|
||||
keyValue("value", value),
|
||||
keyValue("view", view)};
|
||||
|
||||
@@ -3294,7 +3295,8 @@ private:
|
||||
|
||||
updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId);
|
||||
|
||||
tracer.end(keyValue("updated", "yes"));
|
||||
tracer.end(keyValue("updated", "yes"),
|
||||
keyValue("default property id", valueDefaultPropertyId));
|
||||
|
||||
return Sqlite::UpdateChange::Update;
|
||||
};
|
||||
@@ -3324,6 +3326,7 @@ private:
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"reset changed default properties by update"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("type id", value.typeId),
|
||||
keyValue("value", value),
|
||||
keyValue("view", view)};
|
||||
|
||||
|
@@ -32,6 +32,7 @@ public:
|
||||
virtual void removeObserver(ProjectStorageObserver *observer) = 0;
|
||||
|
||||
virtual ModuleId moduleId(::Utils::SmallStringView name) const = 0;
|
||||
virtual Utils::SmallString moduleName(ModuleId moduleId) const = 0;
|
||||
virtual std::optional<Storage::Info::PropertyDeclaration>
|
||||
propertyDeclaration(PropertyDeclarationId propertyDeclarationId) const = 0;
|
||||
virtual TypeId typeId(ModuleId moduleId,
|
||||
|
@@ -230,7 +230,9 @@ void DocumentManager::setCurrentDesignDocument(Core::IEditor *editor)
|
||||
auto found = m_designDocuments.find(editor);
|
||||
if (found == m_designDocuments.end()) {
|
||||
auto &inserted = m_designDocuments[editor] = std::make_unique<DesignDocument>(
|
||||
m_projectManager.projectStorageDependencies(), m_externalDependencies);
|
||||
editor->document()->filePath().toString(),
|
||||
m_projectManager.projectStorageDependencies(),
|
||||
m_externalDependencies);
|
||||
m_currentDesignDocument = inserted.get();
|
||||
m_currentDesignDocument->setEditor(editor);
|
||||
} else {
|
||||
|
@@ -51,6 +51,7 @@ ModuleId ProjectStorageMock::createModule(Utils::SmallStringView moduleName)
|
||||
incrementBasicId(moduleId);
|
||||
|
||||
ON_CALL(*this, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId));
|
||||
ON_CALL(*this, moduleName(Eq(moduleId))).WillByDefault(Return(moduleName));
|
||||
ON_CALL(*this, fetchModuleIdUnguarded(Eq(moduleName))).WillByDefault(Return(moduleId));
|
||||
|
||||
return moduleId;
|
||||
@@ -122,6 +123,14 @@ void ProjectStorageMock::addExportedTypeName(QmlDesigner::TypeId typeId,
|
||||
exportedTypeName[typeId].emplace_back(moduleId, typeName);
|
||||
}
|
||||
|
||||
void ProjectStorageMock::addExportedTypeNameBySourceId(QmlDesigner::TypeId typeId,
|
||||
QmlDesigner::ModuleId moduleId,
|
||||
Utils::SmallStringView typeName,
|
||||
QmlDesigner::SourceId sourceId)
|
||||
{
|
||||
exportedTypeNameBySourceId[{typeId, sourceId}].emplace_back(moduleId, typeName);
|
||||
}
|
||||
|
||||
void ProjectStorageMock::removeExportedTypeName(QmlDesigner::TypeId typeId,
|
||||
QmlDesigner::ModuleId moduleId,
|
||||
Utils::SmallStringView typeName)
|
||||
@@ -364,6 +373,10 @@ ProjectStorageMock::ProjectStorageMock()
|
||||
ON_CALL(*this, exportedTypeNames(_)).WillByDefault([&](TypeId id) {
|
||||
return exportedTypeName[id];
|
||||
});
|
||||
|
||||
ON_CALL(*this, exportedTypeNames(_, _)).WillByDefault([&](TypeId typeId, SourceId sourceId) {
|
||||
return exportedTypeNameBySourceId[{typeId, sourceId}];
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectStorageMock::setupQtQuick()
|
||||
|
@@ -46,6 +46,11 @@ public:
|
||||
QmlDesigner::ModuleId moduleId,
|
||||
Utils::SmallStringView typeName);
|
||||
|
||||
void addExportedTypeNameBySourceId(QmlDesigner::TypeId typeId,
|
||||
QmlDesigner::ModuleId moduleId,
|
||||
Utils::SmallStringView typeName,
|
||||
QmlDesigner::SourceId sourceId);
|
||||
|
||||
void removeExportedTypeName(QmlDesigner::TypeId typeId,
|
||||
QmlDesigner::ModuleId moduleId,
|
||||
Utils::SmallStringView typeName);
|
||||
@@ -122,6 +127,7 @@ public:
|
||||
MOCK_METHOD(void, removeObserver, (QmlDesigner::ProjectStorageObserver *), (override));
|
||||
|
||||
MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (::Utils::SmallStringView), (const, override));
|
||||
MOCK_METHOD(Utils::SmallString, moduleName, (QmlDesigner::ModuleId), (const, override));
|
||||
|
||||
MOCK_METHOD(std::optional<QmlDesigner::Storage::Info::PropertyDeclaration>,
|
||||
propertyDeclaration,
|
||||
@@ -331,6 +337,8 @@ public:
|
||||
|
||||
QmlDesigner::Storage::Info::CommonTypeCache<QmlDesigner::ProjectStorageInterface> typeCache{*this};
|
||||
std::map<QmlDesigner::TypeId, QmlDesigner::Storage::Info::ExportedTypeNames> exportedTypeName;
|
||||
std::map<std::pair<QmlDesigner::TypeId, QmlDesigner::SourceId>, QmlDesigner::Storage::Info::ExportedTypeNames>
|
||||
exportedTypeNameBySourceId;
|
||||
};
|
||||
|
||||
class ProjectStorageMockWithQtQtuick : public ProjectStorageMock
|
||||
|
@@ -141,7 +141,7 @@ TEST_F(ModelUtils, find_lowest_common_ancestor_when_one_of_the_nodes_is_parent)
|
||||
ASSERT_THAT(commonAncestor, parentNode);
|
||||
}
|
||||
|
||||
TEST_F(ModelUtils, lowest_common_ancestor_for_uncle_and_nephew_should_return_the_grandFather)
|
||||
TEST_F(ModelUtils, lowest_common_ancestor_for_uncle_and_nephew_should_return_the_grandfather)
|
||||
{
|
||||
auto grandFatherNode = model.createModelNode("Item");
|
||||
auto fatherNode = model.createModelNode("Item");
|
||||
|
Reference in New Issue
Block a user