QmlDesigner: Add 'Isolate Selection' to Navigator context menu

Task-number: QDS-14803
Change-Id: I111d3d6e3f174346a1e6c8b2e37e1c0e0a6ab9d8
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Shrief Gabr
2025-03-01 03:22:36 +02:00
parent 715ce2c36b
commit 861c8f0266
5 changed files with 134 additions and 5 deletions

View File

@@ -39,6 +39,8 @@ inline constexpr char resetPositionCommandId[] = "ResetPosition";
inline constexpr char copyFormatCommandId[] = "CopyFormat";
inline constexpr char applyFormatCommandId[] = "ApplyFormat";
inline constexpr char visiblityCommandId[] = "ToggleVisiblity";
inline constexpr char isolateSelectionCommandId[] = "IsolateSelection";
inline constexpr char showAllCommandId[] = "ShowAll";
inline constexpr char anchorsFillCommandId[] = "AnchorsFill";
inline constexpr char anchorsResetCommandId[] = "AnchorsReset";
@@ -142,7 +144,10 @@ inline constexpr char redoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextM
inline constexpr char visibilityDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Visibility");
inline constexpr char isolateSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Isolate Selection");
inline constexpr char showAllDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Show All Nodes");
inline constexpr char resetSizeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Reset Size");
inline constexpr char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
@@ -266,6 +271,10 @@ inline constexpr char lowerToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu
inline constexpr char resetSizeToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Reset size and use implicit size.");
inline constexpr char isolateNodesToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Show selected nodes only.");
inline constexpr char showAllToolTip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
"Show all nodes.");
inline constexpr char resetPositionTooltip[] = QT_TRANSLATE_NOOP(
"QmlDesignerContextMenu", "Reset position and use implicit position.");
inline constexpr char copyFormatTooltip[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
@@ -330,6 +339,8 @@ enum PrioritiesEnum : int {
ResetView,
Group,
Visibility,
IsolateSelection,
ShowAllNodes,
ShowBoundingRect,
/******** Section *****************************/
CustomActionsSection = 6000,

View File

@@ -1515,6 +1515,28 @@ void DesignerActionManager::createDefaultDesignerActions()
&resetSize,
&selectionNotEmptyAndHasWidthOrHeightProperty));
addDesignerAction(new ModelNodeAction(
isolateSelectionCommandId,
isolateSelectionDisplayName,
contextIcon(DesignerIcons::VisibilityIcon), // TODO: placeholder icon
isolateNodesToolTip,
rootCategory,
QKeySequence("shift+h"),
Priorities::IsolateSelection,
&isolateSelectedNodes,
&selectionNot2D3DMix));
addDesignerAction(new ModelNodeAction(
showAllCommandId,
showAllDisplayName,
contextIcon(DesignerIcons::VisibilityIcon), // TODO: placeholder icon
showAllToolTip,
rootCategory,
QKeySequence("alt+h"),
Priorities::ShowAllNodes,
&showAllNodes,
&always));
addDesignerAction(new SeparatorDesignerAction(editCategory, 40));
addDesignerAction(new VisiblityModelNodeAction(

View File

@@ -4,14 +4,15 @@
#pragma once
#include "abstractaction.h"
#include "bindingproperty.h"
#include "abstractactiongroup.h"
#include "qmlitemnode.h"
#include <qmldesignerplugin.h>
#include <nodemetainfo.h>
#include "utils3d.h"
#include <bindingproperty.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/icore.h>
#include <nodemetainfo.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
#include <utils/proxyaction.h>
@@ -113,6 +114,23 @@ inline bool selectionNotEmpty(const SelectionContext &selectionState)
return !selectionState.selectedModelNodes().isEmpty();
}
inline bool selectionNot2D3DMix(const SelectionContext &selectionState)
{
const QList<ModelNode> selectedNodes = selectionState.view()->selectedModelNodes();
if (selectedNodes.size() <= 1)
return true;
ModelNode active3DScene = Utils3D::active3DSceneNode(selectionState.view());
bool isFirstNode3D = active3DScene.isAncestorOf(selectedNodes.first());
for (const ModelNode &node : selectedNodes) {
if (active3DScene.isAncestorOf(node) != isFirstNode3D)
return false;
}
return true;
}
inline bool singleSelectionNotRoot(const SelectionContext &selectionState)
{
return selectionState.singleNodeIsSelected()

View File

@@ -279,6 +279,82 @@ void setVisible(const SelectionContext &selectionState)
}
}
static QSet<ModelNode> collectAncestorsAndDescendants(AbstractView *view, const ModelNode &node)
{
QSet<ModelNode> keepVisible;
ModelNode ancestor = node.parentProperty().parentModelNode();
while (ancestor && ancestor != view->rootModelNode()) {
keepVisible.insert(ancestor);
if (!ancestor.hasParentProperty())
break;
ancestor = ancestor.parentProperty().parentModelNode();
}
const QList<ModelNode> descendants = node.allSubModelNodes();
for (const ModelNode &subNode : descendants)
keepVisible.insert(subNode);
return keepVisible;
}
void isolateSelectedNodes(const SelectionContext &selectionState)
{
AbstractView *view = selectionState.view();
const QList<ModelNode> selectedNodes = view->selectedModelNodes();
if (selectedNodes.isEmpty() || view->rootModelNode().isSelected())
return;
const QList<ModelNode> allModelNodes = view->allModelNodes();
ModelNode active3DScene = Utils3D::active3DSceneNode(view);
QSet<ModelNode> nodesToKeepVisible({view->rootModelNode()});
for (const ModelNode &node : selectedNodes) {
nodesToKeepVisible.insert(node);
nodesToKeepVisible.unite(collectAncestorsAndDescendants(view, node));
}
auto hideNode = [](const ModelNode &node) {
QmlVisualNode(node).setVisibilityOverride(true);
};
auto doNotHideSubNodes = [&nodesToKeepVisible](const ModelNode &node) {
if (node.hasAnySubModelNodes()) {
const QList<ModelNode> allSubModelNodes = node.allSubModelNodes();
for (const ModelNode &subNode : allSubModelNodes)
nodesToKeepVisible.insert(subNode);
}
};
const bool is3DSelection = active3DScene.isAncestorOf(selectedNodes.first());
const QList<ModelNode> nodesToProcess = is3DSelection ? active3DScene.allSubModelNodes()
: allModelNodes;
for (const ModelNode &node : nodesToProcess) {
if (nodesToKeepVisible.contains(node))
continue;
if (!is3DSelection) {
NodeHints hint = NodeHints::fromModelNode(node);
if (!((node && !hint.hideInNavigator()) || hint.visibleInNavigator())
|| node.id() == Constants::MATERIAL_LIB_ID) {
continue;
}
}
doNotHideSubNodes(node); // makes sure only the top-most node in the hierarchy is hidden
hideNode(node);
}
}
void showAllNodes(const SelectionContext &selectionState)
{
const QList<ModelNode> allModelNodes = selectionState.view()->allModelNodes();
for (const ModelNode &node : allModelNodes)
QmlVisualNode(node).setVisibilityOverride(false);
}
void setFillWidth(const SelectionContext &selectionState)
{
if (!selectionState.view()

View File

@@ -73,6 +73,8 @@ void paste(const SelectionContext &selectionState);
void undo(const SelectionContext &selectionState);
void redo(const SelectionContext &selectionState);
void setVisible(const SelectionContext &selectionState);
void isolateSelectedNodes(const SelectionContext &selectionState);
void showAllNodes(const SelectionContext &selectionState);
void setFillWidth(const SelectionContext &selectionState);
void setFillHeight(const SelectionContext &selectionState);
void resetSize(const SelectionContext &selectionState);