QmlDesigner: Remove dependency of ModelNode on AbstractView

* Moved AbstractView::hasId() and AbstractView::generateNewId
  to Model. I kept a convenience function AbstractView::hasId(),
  so we do not have to change too much code.
* hasId() and generateNewId() do not mutate the model and therefore
  belong to the model.
* This also allows to remove the dependency on AbstractView in ModelNode
* Adjusting the usage of generateNewId() throughout the code base.

Change-Id: I0b8bab995c48fd52760b509cbe53f0854230b4c8
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Thomas Hartmann
2022-03-10 10:36:08 +01:00
parent 413c73b781
commit bec41a7a55
12 changed files with 76 additions and 65 deletions

View File

@@ -419,7 +419,7 @@ void LayoutInGridLayout::fillEmptyCells()
newItemNode.setVariantProperty("y", yPos);
newItemNode.setVariantProperty("width", 14);
newItemNode.setVariantProperty("height", 14);
newItemNode.setId(m_selectionContext.view()->generateNewId("spacer"));
newItemNode.setId(m_selectionContext.view()->model()->generateNewId("spacer"));
}
m_layoutedNodes.append(m_spacerNodes);
}

View File

@@ -241,7 +241,7 @@ void BackendModel::addNewBackend()
if (!model->hasImport(import))
model->changeImports({import}, {});
QString propertyName = m_connectionView->generateNewId(typeName);
QString propertyName = m_connectionView->model()->generateNewId(typeName);
NodeMetaInfo metaInfo = model->metaInfo(typeName.toUtf8());

View File

@@ -141,7 +141,7 @@ QString NodeListView::setNodeId(int internalId, const QString &id)
{
ModelNode node = modelNodeForInternalId(internalId);
if (node.isValid()) {
QString newId = generateNewId(id);
QString newId = model()->generateNewId(id);
node.setIdWithRefactoring(newId);
return newId;
}

View File

@@ -910,8 +910,8 @@ ModelNode NavigatorTreeModel::handleItemLibraryShaderDrop(const QString &shaderP
// Rename the node based on shader source
QFileInfo fi(relPath);
newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(),
"shader"));
newModelNode.setIdWithoutRefactoring(
m_view->model()->generateNewId(fi.baseName(), "shader"));
// Passes can't have children, so move shader node under parent
if (targetProperty.parentModelNode().isSubclassOf("QtQuick3D.Pass")) {
BindingProperty listProp = targetNode.bindingProperty("shaders");
@@ -956,9 +956,9 @@ ModelNode NavigatorTreeModel::handleItemLibrarySoundDrop(const QString &soundPat
// Rename the node based on source
QFileInfo fi(relPath);
newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(),
"soundEffect"));
}
newModelNode.setIdWithoutRefactoring(
m_view->model()->generateNewId(fi.baseName(), "soundEffect"));
}
return newModelNode;
}
@@ -1073,7 +1073,8 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ
// Rename the node based on source image
QFileInfo fi(imagePath);
newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), "textureImage"));
newModelNode.setIdWithoutRefactoring(
m_view->model()->generateNewId(fi.baseName(), "textureImage"));
return newModelNode;
}
return {};

View File

@@ -131,7 +131,7 @@ void AddTabDesignerAction::addNewTab()
tabViewModelNode.majorVersion(),
tabViewModelNode.minorVersion(),
propertyList);
newTabModelNode.setIdWithRefactoring(newTabModelNode.view()->generateNewId(tabName));
newTabModelNode.setIdWithRefactoring(newTabModelNode.model()->generateNewId(tabName));
tabViewModelNode.defaultNodeAbstractProperty().reparentHere(newTabModelNode);
}
}

View File

@@ -161,8 +161,6 @@ public:
ModelNode modelNodeForId(const QString &id);
bool hasId(const QString &id) const;
QString generateNewId(const QString &prefixName) const;
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
ModelNode modelNodeForInternalId(qint32 internalId) const;
bool hasModelNodeForInternalId(qint32 internalId) const;

View File

@@ -124,6 +124,11 @@ public:
void clearMetaInfoCache();
bool hasId(const QString &id) const;
QString generateNewId(const QString &prefixName) const;
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
protected:
Model();

View File

@@ -42,7 +42,6 @@
#include <utils/qtcassert.h>
#include <utils/algorithm.h>
#include <QRegularExpression>
#include <QWidget>
#include <QtGui/qimage.h>
@@ -519,52 +518,7 @@ ModelNode AbstractView::modelNodeForId(const QString &id)
bool AbstractView::hasId(const QString &id) const
{
return model()->d->hasId(id);
}
QString firstCharToLower(const QString &string)
{
QString resultString = string;
if (!resultString.isEmpty())
resultString[0] = resultString.at(0).toLower();
return resultString;
}
QString AbstractView::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const
{
// First try just the prefixName without number as postfix, then continue with 2 and further
// as postfix until id does not already exist.
// Properties of the root node are not allowed for ids, because they are available in the
// complete context without qualification.
int counter = 0;
QString newBaseId = QString(QStringLiteral("%1")).arg(firstCharToLower(prefixName));
newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]")));
if (!newBaseId.isEmpty()) {
QChar firstChar = newBaseId.at(0);
if (firstChar.isDigit())
newBaseId.prepend('_');
} else {
newBaseId = fallbackPrefix;
}
QString newId = newBaseId;
while (!ModelNode::isValidId(newId) || hasId(newId) || rootModelNode().hasProperty(newId.toUtf8())) {
++counter;
newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(newBaseId)).arg(counter);
}
return newId;
}
QString AbstractView::generateNewId(const QString &prefixName) const
{
return generateNewId(prefixName, QStringLiteral("element"));
return model()->hasId(id);
}
ModelNode AbstractView::modelNodeForInternalId(qint32 internalId) const

View File

@@ -67,6 +67,8 @@
#include <utils/algorithm.h>
#include <QRegularExpression>
/*!
\defgroup CoreModel
*/
@@ -1444,6 +1446,57 @@ bool Model::hasImport(const Import &import, bool ignoreAlias, bool allowHigherVe
return false;
}
bool Model::hasId(const QString &id) const
{
return d->hasId(id);
}
static QString firstCharToLower(const QString &string)
{
QString resultString = string;
if (!resultString.isEmpty())
resultString[0] = resultString.at(0).toLower();
return resultString;
}
QString Model::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const
{
// First try just the prefixName without number as postfix, then continue with 2 and further
// as postfix until id does not already exist.
// Properties of the root node are not allowed for ids, because they are available in the
// complete context without qualification.
int counter = 0;
QString newBaseId = QString(QStringLiteral("%1")).arg(firstCharToLower(prefixName));
newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]")));
if (!newBaseId.isEmpty()) {
QChar firstChar = newBaseId.at(0);
if (firstChar.isDigit())
newBaseId.prepend('_');
} else {
newBaseId = fallbackPrefix;
}
QString newId = newBaseId;
while (!ModelNode::isValidId(newId) || hasId(newId)
|| d->rootNode()->hasProperty(newId.toUtf8())) {
++counter;
newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(newBaseId)).arg(counter);
}
return newId;
}
QString Model::generateNewId(const QString &prefixName) const
{
return generateNewId(prefixName, QStringLiteral("element"));
}
bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowHigherVersion) const
{
if (imports().contains(import))

View File

@@ -25,7 +25,6 @@
#include "modelnode.h"
#include <abstractproperty.h>
#include <abstractview.h>
#include <model.h>
#include <nodemetainfo.h>
#include "internalnode_p.h"
@@ -144,7 +143,7 @@ QString ModelNode::id() const
QString ModelNode::validId()
{
if (id().isEmpty())
setIdWithRefactoring(view()->generateNewId(simplifiedTypeName()));
setIdWithRefactoring(model()->generateNewId(simplifiedTypeName()));
return id();
}
@@ -270,7 +269,8 @@ void ModelNode::setIdWithoutRefactoring(const QString &id)
if (id == m_internalNode->id())
return;
if (view()->hasId(id))
if (model()->hasId(id))
throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id.toUtf8(), InvalidIdException::DuplicateId);
m_model.data()->d->changeNodeId(internalNode(), id);

View File

@@ -117,7 +117,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromImage(AbstractView *view, const QS
parentproperty.reparentHere(newQmlItemNode);
QFileInfo fi(relativeImageName);
newQmlItemNode.setId(view->generateNewId(fi.baseName(), "image"));
newQmlItemNode.setId(view->model()->generateNewId(fi.baseName(), "image"));
newQmlItemNode.modelNode().variantProperty("fillMode").setEnumeration("Image.PreserveAspectFit");
@@ -168,7 +168,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
metaInfo.minorVersion(), propertyPairList));
parentproperty.reparentHere(newQmlItemNode);
newQmlItemNode.setId(view->generateNewId("text", "text"));
newQmlItemNode.setId(view->model()->generateNewId("text", "text"));
Q_ASSERT(newQmlItemNode.isValid());
};

View File

@@ -335,7 +335,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
if (!newQmlObjectNode.isValid())
return;
newQmlObjectNode.setId(view->generateNewId(itemLibraryEntry.name()));
newQmlObjectNode.setId(view->model()->generateNewId(itemLibraryEntry.name()));
for (const auto &propertyBindingEntry : propertyBindingList)
newQmlObjectNode.modelNode().bindingProperty(propertyBindingEntry.first).setExpression(propertyBindingEntry.second);