From d96a6ccb3e5612926f74feb00d5f2d787d9690d4 Mon Sep 17 00:00:00 2001 From: fedejeanne Date: Mon, 20 Jan 2025 15:38:58 +0100 Subject: [PATCH] Do not expand same class twice in (quick) type hierarchy Fixes eclipse-jdt#1830 --- org.eclipse.jdt.ui/.settings/.api_filters | 8 +++ .../HierarchyInformationControl.java | 30 +++++++++- .../typehierarchy/TypeHierarchyViewPart.java | 7 ++- .../ui/typehierarchy/TypeHierarchyViewer.java | 59 ++++++++++++++++--- 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/org.eclipse.jdt.ui/.settings/.api_filters b/org.eclipse.jdt.ui/.settings/.api_filters index b181190c4ad..ab29fec0ba9 100644 --- a/org.eclipse.jdt.ui/.settings/.api_filters +++ b/org.eclipse.jdt.ui/.settings/.api_filters @@ -137,6 +137,14 @@ + + + + + + + + diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/HierarchyInformationControl.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/HierarchyInformationControl.java index fe4cf55e3ad..33a0ae879ee 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/HierarchyInformationControl.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/HierarchyInformationControl.java @@ -14,6 +14,8 @@ package org.eclipse.jdt.internal.ui.typehierarchy; import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; @@ -23,6 +25,7 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.Widget; import org.eclipse.jface.bindings.TriggerSequence; import org.eclipse.jface.bindings.keys.KeySequence; @@ -130,7 +133,32 @@ protected TreeViewer createTreeViewer(Composite parent, int style) { gd.heightHint= tree.getItemHeight() * 12; tree.setLayoutData(gd); - TreeViewer treeViewer= new TreeViewer(tree); + TreeViewer treeViewer= new TreeViewer(tree) { + private Set visited; + + @Override + protected void inputChanged(Object input, Object oldInput) { + visited= new HashSet<>(); + super.inputChanged(input, oldInput); + visited= null; + } + + @Override + protected void internalExpandToLevel(Widget node, int level) { + if (!shouldExpand(node)) + return; + + super.internalExpandToLevel(node, level); + } + + private boolean shouldExpand(Widget widget) { + if (widget == null) { + return false; + } + Object data= widget.getData(); + return data == null || visited.add(data); + } + }; treeViewer.addFilter(new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java index 285e509ea7a..3d41b627128 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java @@ -1212,7 +1212,12 @@ private void updateHierarchyViewer(final boolean doExpand) { fPagebook.showPage(fNoHierarchyShownLabel); } else { if (getCurrentViewer().containsElements() != null) { - Runnable runnable= () -> JavaCore.runReadOnly(() -> getCurrentViewer().updateContent(doExpand)); + Runnable runnable= () -> JavaCore.runReadOnly(() -> { + TypeHierarchyViewer viewer= getCurrentViewer(); + viewer.preUpdateContent(); + viewer.updateContent(doExpand); + viewer.postUpdateContent(); + }); BusyIndicator.showWhile(getDisplay(), runnable); if (!isChildVisible(fViewerbook, getCurrentViewer().getControl())) { setViewerVisibility(true); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewer.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewer.java index f8f3c9d72dd..56e69b88e49 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewer.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewer.java @@ -13,10 +13,14 @@ *******************************************************************************/ package org.eclipse.jdt.internal.ui.typehierarchy; +import java.util.HashSet; +import java.util.Set; + import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.Widget; import org.eclipse.core.runtime.Assert; @@ -42,6 +46,8 @@ public abstract class TypeHierarchyViewer extends ProblemTreeViewer { private HierarchyLabelProvider fLabelProvider; + private Set visited; + public TypeHierarchyViewer(Composite parent, IContentProvider contentProvider, TypeHierarchyLifeCycle lifeCycle) { super(new Tree(parent, SWT.SINGLE)); @@ -83,8 +89,9 @@ public void initContextMenu(IMenuListener menuListener, String popupId, IWorkben } /** - * Fills up the context menu with items for the hierarchy viewer - * Should be called by the creator of the context menu + * Fills up the context menu with items for the hierarchy viewer Should be called by the creator + * of the context menu + * * @param menu the menu manager */ public void contributeToContextMenu(IMenuManager menu) { @@ -92,6 +99,7 @@ public void contributeToContextMenu(IMenuManager menu) { /** * Set the member filter + * * @param memberFilter the member filters to set */ public void setMemberFilter(IMember[] memberFilter) { @@ -103,6 +111,7 @@ public void setMemberFilter(IMember[] memberFilter) { /** * Returns if method filtering is enabled. + * * @return trueif method filtering is enabled. */ public boolean isMethodFiltering() { @@ -122,8 +131,9 @@ public void setWorkingSetFilter(ViewerFilter filter) { } /** - * Returns true if the hierarchy contains elements. Returns one of them - * With member filtering it is possible that no elements are visible + * Returns true if the hierarchy contains elements. Returns one of them With member filtering it + * is possible that no elements are visible + * * @return one of the elements contained */ public Object containsElements() { @@ -138,14 +148,15 @@ public Object containsElements() { } /** - * Returns true if the hierarchy contains elements. Returns one of them - * With member filtering it is possible that no elements are visible + * Returns true if the hierarchy contains elements. Returns one of them With member filtering it + * is possible that no elements are visible + * * @return the tree root */ public IType getTreeRootType() { TypeHierarchyContentProvider contentProvider= getHierarchyContentProvider(); if (contentProvider != null) { - Object[] elements= contentProvider.getElements(null); + Object[] elements= contentProvider.getElements(null); if (elements.length > 0 && elements[0] instanceof IType) { return (IType) elements[0]; } @@ -155,6 +166,7 @@ public IType getTreeRootType() { /** * Returns true if the hierarchy contains element the element. + * * @param element the element * @return true if element is shown */ @@ -164,6 +176,7 @@ public boolean isElementShown(Object element) { /** * Updates the content of this viewer: refresh and expanding the tree in the way wanted. + * * @param doExpand if set, update should expand */ public abstract void updateContent(boolean doExpand); @@ -179,7 +192,37 @@ public void setContentProvider(IContentProvider cp) { } protected TypeHierarchyContentProvider getHierarchyContentProvider() { - return (TypeHierarchyContentProvider)getContentProvider(); + return (TypeHierarchyContentProvider) getContentProvider(); } + @Override + protected void inputChanged(Object input, Object oldInput) { + preUpdateContent(); + super.inputChanged(input, oldInput); + postUpdateContent(); + } + + @Override + protected void internalExpandToLevel(Widget node, int level) { + if (!shouldExpand(node)) + return; + + super.internalExpandToLevel(node, level); + } + + private boolean shouldExpand(Widget widget) { + if (widget == null) { + return false; + } + Object data= widget.getData(); + return data == null || visited.add(data); + } + + void preUpdateContent() { + visited= new HashSet<>(); + } + + void postUpdateContent() { + visited= null; + } }