diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml index 29443f654d3..0cd6595fecc 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml @@ -171,11 +171,16 @@ TreeViewDelegate { onReleased: (mouse) => { mouseArea.allowTooltip = true + if (root.__isDirectory) + return + if (mouse.button === Qt.LeftButton) { if (!(mouse.modifiers & Qt.ControlModifier)) root.assetsView.selectedAssets = {} root.assetsView.selectedAssets[root.__itemPath] = root.currFileSelected root.assetsView.selectedAssetsChanged() + + root.assetsView.currentFilePath = root.__itemPath } } diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml index 276dd2e2aef..ad51a960cb8 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml @@ -24,6 +24,8 @@ TreeView { property alias verticalScrollBar: verticalScrollBar property var selectedAssets: ({}) + // the latest file that was clicked, or changed to via Up or Down keys + property string currentFilePath: "" // used to see if the op requested is to expand or to collapse. property int lastRowCount: -1 @@ -34,6 +36,7 @@ TreeView { property int rootPathRow: 0 // i.e. first child of the root path readonly property int firstRow: root.rootPathRow + 1 + readonly property int lastRow: root.rows - 1 property var __createdDirectories: [] rowHeightProvider: (row) => { @@ -78,6 +81,19 @@ TreeView { updateRowsTimer.restart() } + + function onDeleteSelectedAssetsRequested() + { + let selectedPaths = root.selectedPathsAsList() + if (!selectedPaths.length) + return + + let deleted = assetsModel.requestDeleteFiles(selectedPaths) + if (!deleted) { + confirmDeleteFiles.files = selectedPaths + confirmDeleteFiles.open() + } + } } Connections { @@ -319,6 +335,73 @@ TreeView { return root.modelIndex(row, 0) } + function __selectRow(row: int) + { + let index = root.__modelIndex(row) + if (assetsModel.isDirectory(index)) + return + + let filePath = assetsModel.filePath(index) + + root.clearSelectedAssets() + root.setAssetSelected(filePath, true) + root.currentFilePath = filePath + } + + Keys.enabled: true + + Keys.onUpPressed: { + if (!root.currentFilePath) + return + + let index = assetsModel.indexForPath(root.currentFilePath) + let row = root.rowAtIndex(index) + let nextRow = row + let nextIndex = index + + do { + if (nextRow <= root.firstRow) + return // don't select hidden rows + + nextRow-- + nextIndex = root.__modelIndex(nextRow) + } while (assetsModel.isDirectory(nextIndex)) + + root.__selectRow(nextRow) + root.positionViewAtRow(nextRow, TableView.Contain) + } + + Keys.onDownPressed: { + if (!root.currentFilePath) + return + + let index = assetsModel.indexForPath(root.currentFilePath) + let row = root.rowAtIndex(index) + + let nextRow = row + let nextIndex = index + + do { + if (nextRow >= root.lastRow) + return // don't select hidden rows + + nextRow++ + nextIndex = root.__modelIndex(nextRow) + } while (assetsModel.isDirectory(nextIndex)) + + root.__selectRow(nextRow) + root.positionViewAtRow(nextRow, TableView.Contain) + } + + ConfirmDeleteFilesDialog { + id: confirmDeleteFiles + parent: root + files: [] + + onAccepted: root.clearSelectedAssets() + onClosed: confirmDeleteFiles.files = [] + } + DropArea { id: dropArea enabled: true diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp index 3ed096689e5..cb978d183fd 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -5,6 +5,7 @@ #include "assetslibrarywidget.h" #include "createtexture.h" +#include "designmodecontext.h" #include "qmldesignerplugin.h" #include @@ -61,7 +62,11 @@ WidgetInfo AssetsLibraryView::widgetInfo() { if (m_widget.isNull()) { m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache, - imageCacheData()->synchronousFontImageCache}; + imageCacheData()->synchronousFontImageCache, + this}; + + auto context = new Internal::AssetsLibraryContext(m_widget.data()); + Core::ICore::addContextObject(context); connect(m_widget, &AssetsLibraryWidget::addTexturesRequested, this, [&] (const QStringList &filePaths, AddTextureMode mode) { @@ -84,6 +89,15 @@ WidgetInfo AssetsLibraryView::widgetInfo() return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets")); } +void AssetsLibraryView::customNotification(const AbstractView *view, + const QString &identifier, + const QList &nodeList, + const QList &data) +{ + if (identifier == "delete_selected_assets") + m_widget->deleteSelectedAssets(); +} + void AssetsLibraryView::modelAttached(Model *model) { AbstractView::modelAttached(model); @@ -113,7 +127,8 @@ void AssetsLibraryView::setResourcePath(const QString &resourcePath) if (m_widget.isNull()) { m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache, - imageCacheData()->synchronousFontImageCache}; + imageCacheData()->synchronousFontImageCache, + this}; } m_widget->setResourcePath(resourcePath); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h index 95a4c868d52..374a9f730ef 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h @@ -37,6 +37,9 @@ private: class ImageCacheData; ImageCacheData *imageCacheData(); + void customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) override; + std::once_flag imageCacheFlag; std::unique_ptr m_imageCacheData; QPointer m_widget; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 8778cd77895..578b70e50dd 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -7,7 +7,8 @@ #include "assetslibraryiconprovider.h" #include "assetslibrarymodel.h" #include "designeractionmanager.h" -#include "model.h" +#include "assetslibraryview.h" + #include "modelnodeoperations.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" @@ -84,11 +85,13 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) } AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache, - SynchronousImageCache &synchronousFontImageCache) + SynchronousImageCache &synchronousFontImageCache, + AssetsLibraryView *view) : m_itemIconSize{24, 24} , m_fontImageCache{synchronousFontImageCache} , m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)} , m_assetsModel{new AssetsLibraryModel(this)} + , m_assetsView{view} , m_assetsWidget{new StudioQuickWidget(this)} { setWindowTitle(tr("Assets Library", "Title of assets library widget")); @@ -150,6 +153,19 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon reloadQmlSource(); } +void AssetsLibraryWidget::contextHelp(const Core::IContext::HelpCallback &callback) const +{ + if (m_assetsView) + QmlDesignerPlugin::contextHelp(callback, m_assetsView->contextHelpId()); + else + callback({}); +} + +void AssetsLibraryWidget::deleteSelectedAssets() +{ + emit deleteSelectedAssetsRequested(); +} + QString AssetsLibraryWidget::getUniqueEffectPath(const QString &parentFolder, const QString &effectName) { auto genEffectPath = [&parentFolder](const QString &name) { diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 3221d24a80a..8ac9ab792cf 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -3,8 +3,10 @@ #pragma once +#include +#include + #include "createtexture.h" -#include "previewtooltipbackend.h" #include #include @@ -31,6 +33,7 @@ class Model; class AssetsLibraryIconProvider; class AssetsLibraryModel; +class AssetsLibraryView; class SynchronousImageCache; class AsynchronousImageCache; class ImageCacheCollector; @@ -46,10 +49,11 @@ class AssetsLibraryWidget : public QFrame public: AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache, - SynchronousImageCache &synchronousFontImageCache); + SynchronousImageCache &synchronousFontImageCache, AssetsLibraryView *view); ~AssetsLibraryWidget() = default; QList createToolBarWidgets(); + void contextHelp(const Core::IContext::HelpCallback &callback) const; static QString qmlSourcesPath(); void clearSearchFilter(); @@ -64,6 +68,8 @@ public: bool hasMaterialLibrary() const; void setHasMaterialLibrary(bool enable); + void deleteSelectedAssets(); + Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText); @@ -107,6 +113,7 @@ signals: void hasMaterialLibraryChanged(); void isDraggingChanged(); void endDrag(); + void deleteSelectedAssetsRequested(); protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -124,6 +131,7 @@ private: AssetsLibraryIconProvider *m_assetsIconProvider = nullptr; AssetsLibraryModel *m_assetsModel = nullptr; + AssetsLibraryView *m_assetsView = nullptr; QScopedPointer m_assetsWidget; std::unique_ptr m_fontPreviewTooltipBackend; diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 8a691cd6223..66862e37267 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -114,12 +114,14 @@ void DesignerActionManager::polishActions() const Core::Context qmlDesignerEditor3DContext(Constants::C_QMLEDITOR3D); Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR); Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER); + Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY); Core::Context qmlDesignerUIContext; qmlDesignerUIContext.add(qmlDesignerFormEditorContext); qmlDesignerUIContext.add(qmlDesignerEditor3DContext); qmlDesignerUIContext.add(qmlDesignerNavigatorContext); qmlDesignerUIContext.add(qmlDesignerMaterialBrowserContext); + qmlDesignerUIContext.add(qmlDesignerAssetsLibraryContext); for (auto *action : actions) { if (!action->menuId().isEmpty()) { diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp index d046c594038..d0a2db8f54c 100644 --- a/src/plugins/qmldesigner/designmodecontext.cpp +++ b/src/plugins/qmldesigner/designmodecontext.cpp @@ -2,12 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "designmodecontext.h" -#include "qmldesignerconstants.h" +#include "assetslibrarywidget.h" #include "designmodewidget.h" -#include "formeditorwidget.h" #include "edit3dwidget.h" +#include "formeditorwidget.h" #include "materialbrowserwidget.h" #include "navigatorwidget.h" +#include "qmldesignerconstants.h" #include "texteditorwidget.h" namespace QmlDesigner { @@ -61,6 +62,18 @@ void MaterialBrowserContext::contextHelp(const HelpCallback &callback) const qobject_cast(m_widget)->contextHelp(callback); } +AssetsLibraryContext::AssetsLibraryContext(QWidget *widget) + : IContext(widget) +{ + setWidget(widget); + setContext(Core::Context(Constants::C_QMLASSETSLIBRARY, Constants::C_QT_QUICK_TOOLS_MENU)); +} + +void AssetsLibraryContext::contextHelp(const HelpCallback &callback) const +{ + qobject_cast(m_widget)->contextHelp(callback); +} + NavigatorContext::NavigatorContext(QWidget *widget) : IContext(widget) { diff --git a/src/plugins/qmldesigner/designmodecontext.h b/src/plugins/qmldesigner/designmodecontext.h index 6a04d8ea70e..6645c4a3605 100644 --- a/src/plugins/qmldesigner/designmodecontext.h +++ b/src/plugins/qmldesigner/designmodecontext.h @@ -47,6 +47,15 @@ public: void contextHelp(const Core::IContext::HelpCallback &callback) const override; }; +class AssetsLibraryContext : public Core::IContext +{ + Q_OBJECT + +public: + AssetsLibraryContext(QWidget *widget); + void contextHelp(const Core::IContext::HelpCallback &callback) const override; +}; + class NavigatorContext : public Core::IContext { Q_OBJECT diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 3a29dcad037..f94cf219376 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -17,6 +17,7 @@ const char C_QMLEDITOR3D[] = "QmlDesigner::Editor3D"; const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator"; const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor"; const char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser"; +const char C_QMLASSETSLIBRARY[] = "QmlDesigner::AssetsLibrary"; // Special context for preview menu, shared b/w designer and text editor const char C_QT_QUICK_TOOLS_MENU[] = "QmlDesigner::ToolsMenu"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index f0a686deeeb..3b51d9147ea 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -398,17 +398,18 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget) Core::Context qmlDesignerEditor3dContext(Constants::C_QMLEDITOR3D); Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR); Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER); + Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY); context->context().add(qmlDesignerMainContext); context->context().add(qmlDesignerFormEditorContext); context->context().add(qmlDesignerEditor3dContext); context->context().add(qmlDesignerNavigatorContext); context->context().add(qmlDesignerMaterialBrowserContext); + context->context().add(qmlDesignerAssetsLibraryContext); context->context().add(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); d->shortCutManager.registerActions(qmlDesignerMainContext, qmlDesignerFormEditorContext, - qmlDesignerEditor3dContext, qmlDesignerNavigatorContext, - qmlDesignerMaterialBrowserContext); + qmlDesignerEditor3dContext, qmlDesignerNavigatorContext); const QStringList mimeTypes = { QmlJSTools::Constants::QML_MIMETYPE, QmlJSTools::Constants::QMLUI_MIMETYPE }; diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp index 7528490e0a9..71d37ba2f98 100644 --- a/src/plugins/qmldesigner/shortcutmanager.cpp +++ b/src/plugins/qmldesigner/shortcutmanager.cpp @@ -61,11 +61,8 @@ ShortCutManager::ShortCutManager() void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContext, const Core::Context &qmlDesignerFormEditorContext, const Core::Context &qmlDesignerEditor3DContext, - const Core::Context &qmlDesignerNavigatorContext, - const Core::Context &qmlDesignerMaterialBrowserContext) + const Core::Context &qmlDesignerNavigatorContext) { - Q_UNUSED(qmlDesignerMaterialBrowserContext) - Core::ActionContainer *editMenu = Core::ActionManager::actionContainer(Core::Constants::M_EDIT); connect(&m_undoAction, &QAction::triggered, this, &ShortCutManager::undo); @@ -205,10 +202,11 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [&](const Core::Context &context) { isMatBrowserActive = context.contains(Constants::C_QMLMATERIALBROWSER); + isAssetsLibraryActive = context.contains(Constants::C_QMLASSETSLIBRARY); if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLEDITOR3D) && !context.contains(Constants::C_QMLNAVIGATOR)) { - m_deleteAction.setEnabled(isMatBrowserActive); + m_deleteAction.setEnabled(isMatBrowserActive || isAssetsLibraryActive); m_cutAction.setEnabled(false); m_copyAction.setEnabled(false); m_pasteAction.setEnabled(false); @@ -263,6 +261,9 @@ void ShortCutManager::deleteSelected() if (isMatBrowserActive) { DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->viewManager().designerActionManager(); designerActionManager.view()->emitCustomNotification("delete_selected_material"); + } else if (isAssetsLibraryActive) { + DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->viewManager().designerActionManager(); + designerActionManager.view()->emitCustomNotification("delete_selected_assets"); } else if (currentDesignDocument()) { currentDesignDocument()->deleteSelected(); } diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h index 63c724934c2..a7aad507138 100644 --- a/src/plugins/qmldesigner/shortcutmanager.h +++ b/src/plugins/qmldesigner/shortcutmanager.h @@ -25,8 +25,7 @@ public: void registerActions(const Core::Context &qmlDesignerMainContext, const Core::Context &qmlDesignerFormEditorContext, const Core::Context &qmlDesignerEditor3DContext, - const Core::Context &qmlDesignerNavigatorContext, - const Core::Context &qmlDesignerMaterialBrowserContext); + const Core::Context &qmlDesignerNavigatorContext); void connectUndoActions(DesignDocument *designDocument); void disconnectUndoActions(DesignDocument *designDocument); @@ -67,6 +66,7 @@ private: QAction m_escapeAction; bool isMatBrowserActive = false; + bool isAssetsLibraryActive = false; }; } // namespace QmlDesigner