QmlDesigner: Show and edit texture name instead of ID in MaterialBrowser

Task-number: QDS-13024
Change-Id: I7cb223caf1577942fc273004f0e08df5569c2af0
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2024-06-25 12:49:52 +03:00
parent 576e3b7acd
commit da1c00ca64
6 changed files with 105 additions and 51 deletions

View File

@@ -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()

View File

@@ -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()
}

View File

@@ -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<int, QByteArray> MaterialBrowserTexturesModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
static const QHash<int, QByteArray> 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);
});
}
}

View File

@@ -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

View File

@@ -290,11 +290,15 @@ void MaterialBrowserView::updatePropertyList(const QList<T> &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);
}
}

View File

@@ -48,6 +48,43 @@
#include <QTimer>
#include <QColorDialog>
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<int> 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;