diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml index 18dbd3b1945..eb599fa0c3b 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml @@ -23,7 +23,7 @@ TextInput { selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor // allow only alphanumeric characters, underscores, no space at start, and 1 space between words - validator: RegExpValidator { regExp: /^(\w+\s)*\w+$/ } + validator: RegularExpressionValidator { regularExpression: /^(\w+\s)*\w+$/ } signal renamed(string newName) signal clicked() diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml index 58a8f7418a9..19f656e51e5 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml @@ -16,7 +16,7 @@ Item { signal showContextMenu() function forceFinishEditing() { - txtId.commitRename() + txtName.commitRename() } MouseArea { @@ -76,16 +76,14 @@ Item { } MaterialBrowserItemName { - id: txtId + id: txtName - text: textureId + text: textureName width: img.width anchors.horizontalCenter: parent.horizontalCenter - validator: RegularExpressionValidator { regularExpression: /(^$|^[a-z_]\w*$)/ } - - onRenamed: (newId) => { - MaterialBrowserBackend.materialBrowserTexturesModel.setTextureId(index, newId); + onRenamed: (newName) => { + MaterialBrowserBackend.materialBrowserTexturesModel.setTextureName(index, newName); mouseArea.forceActiveFocus() } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp index 9137e14b14f..5903160a479 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp @@ -34,30 +34,30 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role) QTC_ASSERT(index.isValid() && index.row() < m_textureList.size(), return {}); QTC_ASSERT(roleNames().contains(role), return {}); - if (role == RoleTexSource) { + switch (role) { + case RoleTexVisible: + return isVisible(index.row()); + case RoleTexHasDynamicProps: + return !m_textureList.at(index.row()).dynamicProperties().isEmpty(); + case RoleTexInternalId: + return m_textureList.at(index.row()).internalId(); + case RoleTexName: + return m_textureList.at(index.row()).variantProperty("objectName").value(); + case RoleTexSource: { QString source = QmlObjectNode(m_textureList.at(index.row())).modelValue("source").toString(); if (source.isEmpty()) return {}; if (Utils::FilePath::fromString(source).isAbsolutePath()) return QVariant(source); - return QVariant(QmlDesignerPlugin::instance()->documentManager().currentDesignDocument() - ->fileName().absolutePath().pathAppended(source).cleanPath().toString()); - } - - if (role == RoleTexVisible) - return isVisible(index.row()); - - if (role == RoleTexHasDynamicProps) - return !m_textureList.at(index.row()).dynamicProperties().isEmpty(); - - if (role == RoleTexInternalId) - return m_textureList.at(index.row()).internalId(); - - if (role == RoleTexId) { - return m_textureList.at(index.row()).id(); - } - - if (role == RoleTexToolTip) { + return QVariant(QmlDesignerPlugin::instance() + ->documentManager() + .currentDesignDocument() + ->fileName() + .absolutePath() + .pathAppended(source) + .toFSPathString()); + }; + case RoleTexToolTip: { QString source = data(index, RoleTexSource).toString(); // absolute path if (source.isEmpty()) return tr("Texture has no source image."); @@ -68,11 +68,13 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role) if (info.isEmpty()) return tr("Texture has no data."); + QString textName = data(index, RoleTexName).toString(); QString sourceRelative = QmlObjectNode(texNode).modelValue("source").toString(); - return QLatin1String("%1\n%2\n%3").arg(texNode.id(), sourceRelative, info); + return QLatin1String("%1 (%2)\n%3\n%4").arg(textName, texNode.id(), sourceRelative, info); + }; + default: + return {}; } - - return {}; } bool MaterialBrowserTexturesModel::isVisible(int idx) const @@ -91,13 +93,13 @@ bool MaterialBrowserTexturesModel::isValidIndex(int idx) const QHash MaterialBrowserTexturesModel::roleNames() const { - static const QHash roles { + static const QHash roles{ {RoleTexHasDynamicProps, "hasDynamicProperties"}, - {RoleTexInternalId, "textureInternalId"}, - {RoleTexId, "textureId"}, - {RoleTexSource, "textureSource"}, - {RoleTexToolTip, "textureToolTip"}, - {RoleTexVisible, "textureVisible"} + {RoleTexInternalId, "textureInternalId"}, + {RoleTexName, "textureName"}, + {RoleTexSource, "textureSource"}, + {RoleTexToolTip, "textureToolTip"}, + {RoleTexVisible, "textureVisible"}, }; return roles; } @@ -210,7 +212,14 @@ void MaterialBrowserTexturesModel::updateTextureId(const ModelNode &texture) { int idx = textureIndex(texture); if (idx != -1) - emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexId, RoleTexSource, RoleTexToolTip}); + emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexToolTip}); +} + +void MaterialBrowserTexturesModel::updateTextureName(const ModelNode &texture) +{ + int idx = textureIndex(texture); + if (idx != -1) + emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexName, RoleTexToolTip}); } void MaterialBrowserTexturesModel::updateAllTexturesSources() @@ -311,7 +320,7 @@ void MaterialBrowserTexturesModel::deleteTexture(int idx) } } -void MaterialBrowserTexturesModel::setTextureId(int idx, const QString &newId) +void MaterialBrowserTexturesModel::setTextureName(int idx, const QString &newName) { if (!isValidIndex(idx)) return; @@ -320,14 +329,17 @@ void MaterialBrowserTexturesModel::setTextureId(int idx, const QString &newId) if (!node.isValid()) return; - if (node.id() != newId) { - QString nodeId; - if (!newId.isEmpty()) { - const auto model = m_view->model(); - QTC_ASSERT(model, return); - nodeId = model->generateNewId(newId); - } - node.setIdWithRefactoring(nodeId); + VariantProperty objectNameProperty = node.variantProperty("objectName"); + QString oldName = objectNameProperty.value().toString(); + + if (oldName != newName) { + const Model *model = m_view->model(); + QTC_ASSERT(model, return); + + m_view->executeInTransaction(__FUNCTION__, [&] { + node.setIdWithRefactoring(model->generateNewId(newName, "texture")); + objectNameProperty.setValue(newName); + }); } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h index 728a20f64af..5625cc7d578 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h @@ -39,6 +39,7 @@ public: void updateSelectedTexture(); void updateTextureSource(const ModelNode &texture); void updateTextureId(const ModelNode &texture); + void updateTextureName(const ModelNode &texture); void updateAllTexturesSources(); int textureIndex(const ModelNode &texture) const; ModelNode textureAt(int idx) const; @@ -58,7 +59,7 @@ public: Q_INVOKABLE void addNewTexture(); Q_INVOKABLE void duplicateTexture(int idx); Q_INVOKABLE void deleteTexture(int idx); - Q_INVOKABLE void setTextureId(int idx, const QString &newId); + Q_INVOKABLE void setTextureName(int idx, const QString &newName); Q_INVOKABLE void applyToSelectedMaterial(qint64 internalId); Q_INVOKABLE void applyToSelectedModel(qint64 internalId); Q_INVOKABLE void openTextureEditor(); @@ -97,7 +98,7 @@ private: enum { RoleTexHasDynamicProps = Qt::UserRole + 1, RoleTexInternalId, - RoleTexId, + RoleTexName, RoleTexSource, RoleTexToolTip, RoleTexVisible diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 516e1f777a2..c4503781b03 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -290,11 +290,15 @@ void MaterialBrowserView::updatePropertyList(const QList &propertyList) m_widget->materialBrowserModel()->updateMaterialName(node); else m_previewRequests << node; - } else if (property.name() == "source") { + } else if (isTexture(node)) { QmlObjectNode selectedTex = m_widget->materialBrowserTexturesModel()->selectedTexture(); - if (isTexture(node)) + if (property.name() == "source") m_widget->materialBrowserTexturesModel()->updateTextureSource(node); - else if (selectedTex.propertyChangeForCurrentState() == node) + else if (property.name() == "objectName") + m_widget->materialBrowserTexturesModel()->updateTextureName(node); + } else { + QmlObjectNode selectedTex = m_widget->materialBrowserTexturesModel()->selectedTexture(); + if (property.name() == "source" && selectedTex.propertyChangeForCurrentState() == node) m_widget->materialBrowserTexturesModel()->updateTextureSource(selectedTex); } } diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp index f43cd135a36..05e53d8c9f6 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp @@ -48,6 +48,43 @@ #include #include +using namespace Qt::StringLiterals; + +namespace { + +QString nameFromId(const QString &id, const QString &defaultName) +{ + if (id.isEmpty()) + return defaultName; + + QString newName = id; + static const QRegularExpression sideUnderscores{R"((?:^_+)|(?:_+$))"}; + static const QRegularExpression underscores{R"((?:_+))"}; + static const QRegularExpression camelCases{R"((?:[A-Z](?=[a-z]))|(?:(?<=[a-z])[A-Z]))"}; + + newName.remove(sideUnderscores); + + // Insert underscore to camel case edges + QRegularExpressionMatchIterator caseMatch = camelCases.globalMatch(newName); + QStack camelCaseIndexes; + while (caseMatch.hasNext()) + camelCaseIndexes.push(caseMatch.next().capturedStart()); + while (!camelCaseIndexes.isEmpty()) + newName.insert(camelCaseIndexes.pop(), '_'); + + // Replace underscored joints with space + newName.replace(underscores, " "); + newName = newName.trimmed(); + + if (newName.isEmpty()) + return defaultName; + + newName[0] = newName[0].toUpper(); + return newName; +} + +} // namespace + namespace QmlDesigner { TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache, @@ -389,6 +426,8 @@ void TextureEditorView::handleToolBarAction(int action) metaInfo.minorVersion()); #endif newTextureNode.ensureIdExists(); + VariantProperty textureName = newTextureNode.variantProperty("objectName"); + textureName.setValue(nameFromId(newTextureNode.id(), "Texture"_L1)); matLib.defaultNodeListProperty().reparentHere(newTextureNode); }); break;