forked from qt-creator/qt-creator
QmlDesigner: Create menu for Effects creation in the Asset Library
- Add menu item for effect creation instead of new file dialog - New effect dialog with validating qml file name with qml naming conventions - Open Effect Maker automatically when an effect is created Task-number: QDS-8490 Task-number: QDS-8578 Change-Id: I04b075a0b283318906f309c7d394eda48577ae74 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -183,4 +183,16 @@ StudioControls.Menu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("New Effect")
|
||||||
|
|
||||||
|
NewEffectDialog {
|
||||||
|
id: newEffectDialog
|
||||||
|
parent: root.assetsView
|
||||||
|
dirPath: root.__dirPath
|
||||||
|
}
|
||||||
|
|
||||||
|
onTriggered: newEffectDialog.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import HelperWidgets as HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Create New Effect")
|
||||||
|
anchors.centerIn: parent
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
required property string dirPath
|
||||||
|
readonly property int __maxPath: 32
|
||||||
|
|
||||||
|
HelperWidgets.RegExpValidator {
|
||||||
|
id: effectNameValidator
|
||||||
|
regExp: /^[A-Z]\w[A-Za-z0-9_]*$/
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorDialog {
|
||||||
|
id: creationFailedDialog
|
||||||
|
title: qsTr("Could not create effect")
|
||||||
|
message: qsTr("An error occurred while trying to create the effect.")
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
Text {
|
||||||
|
text: qsTr("Effect name: ")
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: effectName
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicator.visible: false
|
||||||
|
validator: effectNameValidator
|
||||||
|
|
||||||
|
Keys.onEnterPressed: btnCreate.onClicked()
|
||||||
|
Keys.onReturnPressed: btnCreate.onClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Effect name cannot be empty.")
|
||||||
|
color: "#ff0000"
|
||||||
|
anchors.right: parent.right
|
||||||
|
visible: effectName.text === ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Effect path is too long.")
|
||||||
|
color: "#ff0000"
|
||||||
|
anchors.right: parent.right
|
||||||
|
visible: effectName.text.length > root.__maxPath
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
width: 1
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
id: btnCreate
|
||||||
|
|
||||||
|
text: qsTr("Create")
|
||||||
|
enabled: effectName.text !== ""
|
||||||
|
&& effectName.length >=3
|
||||||
|
&& effectName.text.length <= root.__maxPath
|
||||||
|
onClicked: {
|
||||||
|
const path = assetsModel.getUniqueEffectPath(root.dirPath, effectName.text)
|
||||||
|
if (assetsModel.createNewEffect(path))
|
||||||
|
root.accept()
|
||||||
|
else
|
||||||
|
creationFailedDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
const path = assetsModel.getUniqueEffectPath(root.dirPath, "Effect01")
|
||||||
|
effectName.text = path.split('/').pop().replace(".qep", '')
|
||||||
|
effectName.selectAll()
|
||||||
|
effectName.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
@@ -134,32 +134,10 @@ bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &
|
|||||||
bool AssetsLibraryModel::addNewFolder(const QString &folderPath)
|
bool AssetsLibraryModel::addNewFolder(const QString &folderPath)
|
||||||
{
|
{
|
||||||
QString iterPath = folderPath;
|
QString iterPath = folderPath;
|
||||||
static QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
|
|
||||||
QDir dir{folderPath};
|
QDir dir{folderPath};
|
||||||
|
|
||||||
while (dir.exists()) {
|
while (dir.exists()) {
|
||||||
// if the folder name ends with a number, increment it
|
iterPath = getUniqueName(iterPath);
|
||||||
QRegularExpressionMatch match = rgx.match(iterPath);
|
|
||||||
if (match.hasMatch()) { // ends with a number
|
|
||||||
QString numStr = match.captured(0);
|
|
||||||
int num = match.captured(0).toInt();
|
|
||||||
|
|
||||||
// get number of padding zeros, ex: for "005" = 2
|
|
||||||
int nPaddingZeros = 0;
|
|
||||||
for (; nPaddingZeros < numStr.size() && numStr[nPaddingZeros] == '0'; ++nPaddingZeros);
|
|
||||||
|
|
||||||
++num;
|
|
||||||
|
|
||||||
// if the incremented number's digits increased, decrease the padding zeros
|
|
||||||
if (std::fmod(std::log10(num), 1.0) == 0)
|
|
||||||
--nPaddingZeros;
|
|
||||||
|
|
||||||
iterPath = folderPath.mid(0, match.capturedStart())
|
|
||||||
+ QString('0').repeated(nPaddingZeros)
|
|
||||||
+ QString::number(num);
|
|
||||||
} else {
|
|
||||||
iterPath = folderPath + '1';
|
|
||||||
}
|
|
||||||
|
|
||||||
dir.setPath(iterPath);
|
dir.setPath(iterPath);
|
||||||
}
|
}
|
||||||
@@ -186,6 +164,36 @@ bool AssetsLibraryModel::allFilePathsAreImages(const QStringList &filePaths) con
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AssetsLibraryModel::getUniqueEffectPath(const QString &parentFolder, const QString &effectName)
|
||||||
|
{
|
||||||
|
auto genEffectPath = [=](const QString &name) {
|
||||||
|
return QString(parentFolder + "/" + name + ".qep");
|
||||||
|
};
|
||||||
|
|
||||||
|
QString uniqueName = effectName;
|
||||||
|
QString path = genEffectPath(uniqueName);
|
||||||
|
QFileInfo file{path};
|
||||||
|
|
||||||
|
while (file.exists()) {
|
||||||
|
uniqueName = getUniqueName(uniqueName);
|
||||||
|
|
||||||
|
path = genEffectPath(uniqueName);
|
||||||
|
file.setFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetsLibraryModel::createNewEffect(const QString &effectPath, bool openEffectMaker)
|
||||||
|
{
|
||||||
|
bool created = QFile(effectPath).open(QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
if (created && openEffectMaker)
|
||||||
|
ModelNodeOperations::openEffectMaker(effectPath);
|
||||||
|
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
{
|
{
|
||||||
QString path = m_sourceFsModel->filePath(sourceParent);
|
QString path = m_sourceFsModel->filePath(sourceParent);
|
||||||
@@ -242,6 +250,36 @@ void AssetsLibraryModel::syncHaveFiles()
|
|||||||
setHaveFiles(checkHaveFiles());
|
setHaveFiles(checkHaveFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AssetsLibraryModel::getUniqueName(const QString &oldName) {
|
||||||
|
static QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
|
||||||
|
|
||||||
|
QString uniqueName = oldName;
|
||||||
|
// if the folder name ends with a number, increment it
|
||||||
|
QRegularExpressionMatch match = rgx.match(uniqueName);
|
||||||
|
if (match.hasMatch()) { // ends with a number
|
||||||
|
QString numStr = match.captured(0);
|
||||||
|
int num = match.captured(0).toInt();
|
||||||
|
|
||||||
|
// get number of padding zeros, ex: for "005" = 2
|
||||||
|
int nPaddingZeros = 0;
|
||||||
|
for (; nPaddingZeros < numStr.size() && numStr[nPaddingZeros] == '0'; ++nPaddingZeros);
|
||||||
|
|
||||||
|
++num;
|
||||||
|
|
||||||
|
// if the incremented number's digits increased, decrease the padding zeros
|
||||||
|
if (std::fmod(std::log10(num), 1.0) == 0)
|
||||||
|
--nPaddingZeros;
|
||||||
|
|
||||||
|
uniqueName = oldName.mid(0, match.capturedStart())
|
||||||
|
+ QString('0').repeated(nPaddingZeros)
|
||||||
|
+ QString::number(num);
|
||||||
|
} else {
|
||||||
|
uniqueName = oldName + '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueName;
|
||||||
|
}
|
||||||
|
|
||||||
void AssetsLibraryModel::setRootPath(const QString &newPath)
|
void AssetsLibraryModel::setRootPath(const QString &newPath)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@@ -47,6 +47,9 @@ public:
|
|||||||
Q_INVOKABLE bool deleteFolderRecursively(const QModelIndex &folderIndex);
|
Q_INVOKABLE bool deleteFolderRecursively(const QModelIndex &folderIndex);
|
||||||
Q_INVOKABLE bool allFilePathsAreImages(const QStringList &filePaths) const;
|
Q_INVOKABLE bool allFilePathsAreImages(const QStringList &filePaths) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QString getUniqueEffectPath(const QString &parentFolder, const QString &effectName);
|
||||||
|
Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openEffectMaker = true);
|
||||||
|
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
{
|
{
|
||||||
int result = QSortFilterProxyModel::columnCount(parent);
|
int result = QSortFilterProxyModel::columnCount(parent);
|
||||||
@@ -79,6 +82,7 @@ private:
|
|||||||
void destroyBackendModel();
|
void destroyBackendModel();
|
||||||
bool checkHaveFiles(const QModelIndex &parentIdx) const;
|
bool checkHaveFiles(const QModelIndex &parentIdx) const;
|
||||||
bool checkHaveFiles() const;
|
bool checkHaveFiles() const;
|
||||||
|
QString getUniqueName(const QString &oldName);
|
||||||
|
|
||||||
QString m_searchText;
|
QString m_searchText;
|
||||||
QString m_rootPath;
|
QString m_rootPath;
|
||||||
|
Reference in New Issue
Block a user