forked from qt-creator/qt-creator
QmlDesigner: Allow removing a content library material
Fixes: QDS-12541 Change-Id: I8efdd5c5f6185961bd8440e06d0adb60ad9d79f2 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -130,10 +130,14 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnimportBundleMaterialDialog {
|
UnimportBundleItemDialog {
|
||||||
id: confirmUnimportDialog
|
id: confirmUnimportDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeleteBundleItemDialog {
|
||||||
|
id: confirmDeleteDialog
|
||||||
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
id: stackLayout
|
id: stackLayout
|
||||||
width: root.width
|
width: root.width
|
||||||
@@ -246,6 +250,12 @@ Item {
|
|||||||
confirmUnimportDialog.open()
|
confirmUnimportDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRemoveFromContentLib: (bundleItem) => {
|
||||||
|
confirmDeleteDialog.targetBundleItem = bundleItem
|
||||||
|
confirmDeleteDialog.targetBundleLabel = "material"
|
||||||
|
confirmDeleteDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,12 +12,14 @@ StudioControls.Menu {
|
|||||||
property var targetMaterial: null
|
property var targetMaterial: null
|
||||||
property bool hasModelSelection: false
|
property bool hasModelSelection: false
|
||||||
property bool importerRunning: false
|
property bool importerRunning: false
|
||||||
|
property bool enableRemove: false // true: adds an option to remove targetMaterial
|
||||||
|
|
||||||
readonly property bool targetAvailable: targetMaterial && !importerRunning
|
readonly property bool targetAvailable: targetMaterial && !importerRunning
|
||||||
|
|
||||||
signal unimport();
|
signal unimport();
|
||||||
signal addToProject()
|
signal addToProject()
|
||||||
signal applyToSelected(bool add)
|
signal applyToSelected(bool add)
|
||||||
|
signal removeFromContentLib()
|
||||||
|
|
||||||
function popupMenu(targetMaterial = null)
|
function popupMenu(targetMaterial = null)
|
||||||
{
|
{
|
||||||
@@ -56,4 +58,11 @@ StudioControls.Menu {
|
|||||||
|
|
||||||
onTriggered: root.unimport()
|
onTriggered: root.unimport()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Remove from Content Library")
|
||||||
|
visible: root.enableRemove && root.targetAvailable
|
||||||
|
height: visible ? implicitHeight : 0
|
||||||
|
onTriggered: root.removeFromContentLib()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ HelperWidgets.ScrollView {
|
|||||||
required property var searchBox
|
required property var searchBox
|
||||||
|
|
||||||
signal unimport(var bundleItem);
|
signal unimport(var bundleItem);
|
||||||
|
signal removeFromContentLib(var bundleItem);
|
||||||
|
|
||||||
function closeContextMenu() {
|
function closeContextMenu() {
|
||||||
ctxMenuMaterial.close()
|
ctxMenuMaterial.close()
|
||||||
@@ -49,6 +50,7 @@ HelperWidgets.ScrollView {
|
|||||||
ContentLibraryMaterialContextMenu {
|
ContentLibraryMaterialContextMenu {
|
||||||
id: ctxMenuMaterial
|
id: ctxMenuMaterial
|
||||||
|
|
||||||
|
enableRemove: true
|
||||||
hasModelSelection: ContentLibraryBackend.userModel.hasModelSelection
|
hasModelSelection: ContentLibraryBackend.userModel.hasModelSelection
|
||||||
importerRunning: ContentLibraryBackend.userModel.importerRunning
|
importerRunning: ContentLibraryBackend.userModel.importerRunning
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ HelperWidgets.ScrollView {
|
|||||||
|
|
||||||
onUnimport: root.unimport(ctxMenuMaterial.targetMaterial)
|
onUnimport: root.unimport(ctxMenuMaterial.targetMaterial)
|
||||||
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuMaterial.targetMaterial)
|
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuMaterial.targetMaterial)
|
||||||
|
onRemoveFromContentLib: root.removeFromContentLib(ctxMenuMaterial.targetMaterial)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentLibraryTextureContextMenu {
|
ContentLibraryTextureContextMenu {
|
||||||
|
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets
|
||||||
|
import StudioControls as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
import ContentLibraryBackend
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var targetBundleItem
|
||||||
|
property var targetBundleModel
|
||||||
|
property string targetBundleLabel // "effect" or "material"
|
||||||
|
|
||||||
|
title: qsTr("Remove bundle %1").arg(root.targetBundleLabel)
|
||||||
|
anchors.centerIn: parent
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
implicitWidth: 300
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
onOpened: warningText.forceActiveFocus()
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 20
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: warningText
|
||||||
|
|
||||||
|
text: qsTr("Are you sure you? The action cannot be undone")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 10
|
||||||
|
|
||||||
|
Keys.onEnterPressed: btnRemove.onClicked()
|
||||||
|
Keys.onReturnPressed: btnRemove.onClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
Button {
|
||||||
|
id: btnRemove
|
||||||
|
|
||||||
|
text: qsTr("Remove")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
ContentLibraryBackend.userModel.removeFromContentLib(root.targetBundleItem)
|
||||||
|
root.accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -13,8 +13,8 @@ StudioControls.Dialog {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var targetBundleItem
|
property var targetBundleItem
|
||||||
property var targetBundleLabel // "effect" or "material"
|
|
||||||
property var targetBundleModel
|
property var targetBundleModel
|
||||||
|
property string targetBundleLabel // "effect" or "material"
|
||||||
|
|
||||||
title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel)
|
title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel)
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
@@ -32,6 +32,11 @@ bool ContentLibraryMaterial::filter(const QString &searchText)
|
|||||||
return m_visible;
|
return m_visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ContentLibraryMaterial::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
QUrl ContentLibraryMaterial::icon() const
|
QUrl ContentLibraryMaterial::icon() const
|
||||||
{
|
{
|
||||||
return m_icon;
|
return m_icon;
|
||||||
|
@@ -37,6 +37,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE bool isDownloaded() const;
|
Q_INVOKABLE bool isDownloaded() const;
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
QUrl icon() const;
|
QUrl icon() const;
|
||||||
QString qml() const;
|
QString qml() const;
|
||||||
TypeName type() const;
|
TypeName type() const;
|
||||||
|
@@ -33,9 +33,6 @@ ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent)
|
|||||||
, m_widget(parent)
|
, m_widget(parent)
|
||||||
{
|
{
|
||||||
m_userCategories = {tr("Materials"), tr("Textures")/*, tr("3D"), tr("Effects"), tr("2D components")*/}; // TODO
|
m_userCategories = {tr("Materials"), tr("Textures")/*, tr("3D"), tr("Effects"), tr("2D components")*/}; // TODO
|
||||||
|
|
||||||
loadMaterialBundle();
|
|
||||||
loadTextureBundle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ContentLibraryUserModel::rowCount(const QModelIndex &) const
|
int ContentLibraryUserModel::rowCount(const QModelIndex &) const
|
||||||
@@ -136,6 +133,44 @@ void ContentLibraryUserModel::removeTexture(ContentLibraryTexture *tex)
|
|||||||
emit dataChanged(index(texSectionIdx), index(texSectionIdx));
|
emit dataChanged(index(texSectionIdx), index(texSectionIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContentLibraryUserModel::removeFromContentLib(ContentLibraryMaterial *mat)
|
||||||
|
{
|
||||||
|
auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials/");
|
||||||
|
|
||||||
|
QJsonObject matsObj = m_bundleObj.value("materials").toObject();
|
||||||
|
|
||||||
|
// remove qml and icon files
|
||||||
|
Utils::FilePath::fromString(mat->qmlFilePath()).removeFile();
|
||||||
|
Utils::FilePath::fromUrl(mat->icon()).removeFile();
|
||||||
|
|
||||||
|
// remove from the bundle json file
|
||||||
|
matsObj.remove(mat->name());
|
||||||
|
m_bundleObj.insert("materials", matsObj);
|
||||||
|
auto result = bundlePath.pathAppended("user_materials_bundle.json")
|
||||||
|
.writeFileContents(QJsonDocument(m_bundleObj).toJson());
|
||||||
|
if (!result)
|
||||||
|
qWarning() << __FUNCTION__ << result.error();
|
||||||
|
|
||||||
|
// delete dependency files if they are only used by the deleted material
|
||||||
|
QStringList allFiles;
|
||||||
|
for (const QJsonValueConstRef &mat : std::as_const(matsObj))
|
||||||
|
allFiles.append(mat.toObject().value("files").toVariant().toStringList());
|
||||||
|
|
||||||
|
const QStringList matFiles = mat->files();
|
||||||
|
for (const QString &matFile : matFiles) {
|
||||||
|
if (allFiles.count(matFile) == 0) // only used by the deleted material
|
||||||
|
bundlePath.pathAppended(matFile).removeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from model
|
||||||
|
m_userMaterials.removeOne(mat);
|
||||||
|
mat->deleteLater();
|
||||||
|
|
||||||
|
// update model
|
||||||
|
int matSectionIdx = 0;
|
||||||
|
emit dataChanged(index(matSectionIdx), index(matSectionIdx));
|
||||||
|
}
|
||||||
|
|
||||||
// returns unique library material's name and qml component
|
// returns unique library material's name and qml component
|
||||||
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(const QString &matName) const
|
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(const QString &matName) const
|
||||||
{
|
{
|
||||||
|
@@ -67,12 +67,16 @@ public:
|
|||||||
void setBundleObj(const QJsonObject &newBundleObj);
|
void setBundleObj(const QJsonObject &newBundleObj);
|
||||||
QJsonObject &bundleJsonObjectRef();
|
QJsonObject &bundleJsonObjectRef();
|
||||||
|
|
||||||
|
void loadMaterialBundle();
|
||||||
|
void loadTextureBundle();
|
||||||
|
|
||||||
Internal::ContentLibraryBundleImporter *bundleImporter() const;
|
Internal::ContentLibraryBundleImporter *bundleImporter() const;
|
||||||
|
|
||||||
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||||
Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat);
|
Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||||
Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat);
|
Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||||
Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex);
|
Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex);
|
||||||
|
Q_INVOKABLE void removeFromContentLib(QmlDesigner::ContentLibraryMaterial *mat);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void isEmptyChanged();
|
void isEmptyChanged();
|
||||||
@@ -96,8 +100,6 @@ signals:
|
|||||||
void matBundleExistsChanged();
|
void matBundleExistsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadMaterialBundle();
|
|
||||||
void loadTextureBundle();
|
|
||||||
bool isValidIndex(int idx) const;
|
bool isValidIndex(int idx) const;
|
||||||
void createImporter(const QString &bundlePath, const QString &bundleId,
|
void createImporter(const QString &bundlePath, const QString &bundleId,
|
||||||
const QStringList &sharedFiles);
|
const QStringList &sharedFiles);
|
||||||
|
@@ -304,6 +304,9 @@ void ContentLibraryView::modelAttached(Model *model)
|
|||||||
|
|
||||||
m_widget->effectsModel()->loadBundle();
|
m_widget->effectsModel()->loadBundle();
|
||||||
updateBundleEffectsImportedState();
|
updateBundleEffectsImportedState();
|
||||||
|
|
||||||
|
m_widget->userModel()->loadMaterialBundle();
|
||||||
|
m_widget->userModel()->loadTextureBundle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLibraryView::modelAboutToBeDetached(Model *model)
|
void ContentLibraryView::modelAboutToBeDetached(Model *model)
|
||||||
|
Reference in New Issue
Block a user