From 339ebeab8e74d394f7f9e2b0f87999314265d43d Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Thu, 2 Feb 2023 21:03:17 +0200 Subject: [PATCH] QmlDesigner: Implement keyboard commands in AssetsLibrary Up and Down now change selection--they work only for files, they skip directories. The Delete key will (ask confirmation to) delete the selected files, just as it happens when clicking Delete from the Context menu. Also, did a small fix in the AssetDelegate, where, on mouse release, you could have a directory added to the selection list. Task-number: QDS-8710 Change-Id: I05e232ed0ce94709df41a5150a49300ad65c0a86 Reviewed-by: Mahmoud Badri --- .../assetsLibraryQmlSources/AssetDelegate.qml | 5 ++ .../assetsLibraryQmlSources/AssetsView.qml | 83 +++++++++++++++++++ .../assetslibrary/assetslibraryview.cpp | 19 ++++- .../assetslibrary/assetslibraryview.h | 3 + .../assetslibrary/assetslibrarywidget.cpp | 20 ++++- .../assetslibrary/assetslibrarywidget.h | 12 ++- .../componentcore/designeractionmanager.cpp | 2 + src/plugins/qmldesigner/designmodecontext.cpp | 17 +++- src/plugins/qmldesigner/designmodecontext.h | 9 ++ .../qmldesigner/qmldesignerconstants.h | 1 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 5 +- src/plugins/qmldesigner/shortcutmanager.cpp | 11 +-- src/plugins/qmldesigner/shortcutmanager.h | 4 +- 13 files changed, 174 insertions(+), 17 deletions(-) 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