From 49e384a126e29d364005d1885d7720f4c946fac3 Mon Sep 17 00:00:00 2001 From: Sougandh S Date: Thu, 30 Jul 2026 15:56:22 +0530 Subject: [PATCH] Add Toggle to Sort LaunchConfigurations by most recent launch Adds a check-box toolbar action to the Launch Configurations dialog that toggles the tree sort order between alphabetical-by-type (the existing default) and most-recently-launched within each type group.The number of configurations considered "recent" is governed by the existing "Maximum number of launch history items" preference, so users who increase that limit will see a broader recency-based sort order. --- .../ui/DebugUIPreferenceInitializer.java | 1 + .../ui/IInternalDebugUIConstants.java | 7 ++ .../LaunchConfigurationComparator.java | 44 ++++++++++- .../LaunchConfigurationFilteredTree.java | 18 ++++- .../LaunchConfigurationView.java | 6 ++ .../LaunchConfigurationsDialog.java | 5 ++ .../LaunchConfigurationsMessages.java | 4 + .../LaunchConfigurationsMessages.properties | 4 +- .../SortLaunchConfigurationAction.java | 77 +++++++++++++++++++ 9 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/SortLaunchConfigurationAction.java diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIPreferenceInitializer.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIPreferenceInitializer.java index c59d59dcafa..8996fb0d235 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIPreferenceInitializer.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIPreferenceInitializer.java @@ -69,6 +69,7 @@ public void initializeDefaultPreferences() { prefs.setDefault(IInternalDebugUIConstants.PREF_USE_CONTEXTUAL_LAUNCH, true); prefs.setDefault(IInternalDebugUIConstants.PREF_LAUNCH_PARENT_PROJECT, false); prefs.setDefault(IInternalDebugUIConstants.PREF_LAUNCH_LAST_IF_NOT_LAUNCHABLE, true); + prefs.setDefault(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT, false); prefs.setDefault(IInternalDebugUIConstants.PREF_TERMINATE_AND_RELAUNCH_LAUNCH_ACTION, false); prefs.setDefault(IInternalDebugUIConstants.PREF_BREAKPOINT_SORTING_ORDER, diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/IInternalDebugUIConstants.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/IInternalDebugUIConstants.java index 128648fbd4b..d5805f9dec8 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/IInternalDebugUIConstants.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/IInternalDebugUIConstants.java @@ -435,4 +435,11 @@ public interface IInternalDebugUIConstants { */ String EXPRESSION_PASTE_AS_MULTI = "org.eclipse.debug.ui.expression.paste.multi"; //$NON-NLS-1$ + /** + * String indicating sorting order of launch configurations in + * LaunchConfigurations View + * + */ + String PREF_LAUNCHCONFIG_SORT_ON_RECENT = IDebugUIConstants.PLUGIN_ID + ".PREF_LAUNCHCONFIG_SORT_ON_RECENT"; //$NON-NLS-1$ + } diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationComparator.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationComparator.java index 0fe10048956..a202713ff02 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationComparator.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationComparator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2015 IBM Corporation and others. + * Copyright (c) 2007, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -24,6 +24,8 @@ import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.jface.viewers.Viewer; import org.eclipse.ui.model.WorkbenchViewerComparator; /** @@ -37,6 +39,20 @@ public class LaunchConfigurationComparator extends WorkbenchViewerComparator { * the map of categories of ILaunchConfigurationTypes to Integers entries */ private static Map fgCategories; + private Map recentLaunches = new HashMap<>(); + + public LaunchConfigurationComparator(String groupIdentifier) { + LaunchHistory history = DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchHistory(groupIdentifier); + if (history != null) { + ILaunchConfiguration[] launches = history.getCompleteLaunchHistory(); + for (int i = 0; i < launches.length; i++) { + recentLaunches.put(launches[i], Integer.valueOf(i)); + } + } + } + + public LaunchConfigurationComparator() { + } /** * @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object) @@ -56,6 +72,32 @@ public int category(Object element) { return map.size(); } + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + if (e1 instanceof ILaunchConfiguration c1 && e2 instanceof ILaunchConfiguration c2) { + int category1 = category(c1); + int category2 = category(c2); + if (category1 != category2) { + return category1 - category2; + } + Integer recent1 = recentLaunches.get(c1); + Integer recent2 = recentLaunches.get(c2); + if (recent1 != null || recent2 != null) { + if (recent1 == null) { + return 1; + } + if (recent2 == null) { + return -1; + } + int result = recent1.compareTo(recent2); + if (result != 0) { + return result; + } + } + } + return super.compare(viewer, e1, e2); + } + /** * Returns the map of categories * @return the map of categories diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java index 141bf0d6274..b2a4e3c7991 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java @@ -21,6 +21,7 @@ import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.IDebugHelpContextIds; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.ILaunchGroup; import org.eclipse.help.HelpSystem; @@ -76,8 +77,17 @@ public LaunchConfigurationFilteredTree(Composite parent, int treeStyle, PatternF @Override protected TreeViewer doCreateTreeViewer(Composite cparent, int style) { treeViewer = new LaunchConfigurationViewer(cparent, style); - treeViewer.setLabelProvider(new DecoratingLabelProvider(DebugUITools.newDebugModelPresentation(), PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator())); - treeViewer.setComparator(new WorkbenchViewerComparator()); + + treeViewer.setLabelProvider(new DecoratingLabelProvider(DebugUITools.newDebugModelPresentation(), + PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator())); + boolean sortByRecent = DebugUIPlugin.getDefault().getPreferenceStore() + .getBoolean(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT); + + if (sortByRecent) { + treeViewer.setComparator(new LaunchConfigurationComparator(fLaunchGroup.getIdentifier())); + } else { + treeViewer.setComparator(new WorkbenchViewerComparator()); + } treeViewer.setContentProvider(new LaunchConfigurationTreeContentProvider(fLaunchGroup.getMode(), cparent.getShell())); treeViewer.addFilter(new LaunchGroupFilter(fLaunchGroup)); treeViewer.setUseHashlookup(true); @@ -225,4 +235,8 @@ protected void updateToolbar(boolean visible) { getLaunchConfigurationViewer().filterChanged(); } + public ILaunchGroup getLaunchGroup() { + return fLaunchGroup; + } + } diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationView.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationView.java index 82007d14951..aff867c2783 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationView.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationView.java @@ -96,6 +96,8 @@ public class LaunchConfigurationView extends AbstractDebugView implements ILaunc */ private FilterLaunchConfigurationAction fFilterAction; + private SortLaunchConfigurationAction sort; + /** * This label is used to notify users that items (possibly) have been filtered from the * launch configuration view @@ -225,6 +227,9 @@ protected void createActions() { fFilterAction = new FilterLaunchConfigurationAction(); setAction(FilterLaunchConfigurationAction.ID_FILTER_ACTION, fFilterAction); + sort = new SortLaunchConfigurationAction(fTree); + setAction(SortLaunchConfigurationAction.ID_SORT_ACTION, sort); + fLinkPrototypeAction = new LinkPrototypeAction(getViewer(), getLaunchGroup().getMode()); setAction(LinkPrototypeAction.ID_LINK_PROTOTYPE_ACTION, fLinkPrototypeAction); @@ -291,6 +296,7 @@ public void dispose() { fExportAction.dispose(); fImportAction.dispose(); fFilterAction = null; + sort = null; fCollapseAllAction = null; fLinkPrototypeAction.dispose(); fUnlinkPrototypeAction.dispose(); diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsDialog.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsDialog.java index 3d3027112de..a5386fae947 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsDialog.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsDialog.java @@ -510,6 +510,7 @@ protected void createToolbarActions(ToolBarManager tmanager) { tmanager.add(new Separator()); tmanager.add(getCollapseAllAction()); tmanager.add(getFilterAction()); + tmanager.add(getSortAction()); tmanager.update(true); DebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this); } @@ -723,6 +724,10 @@ protected IAction getFilterAction() { return fLaunchConfigurationView.getAction(FilterLaunchConfigurationAction.ID_FILTER_ACTION); } + protected IAction getSortAction() { + return fLaunchConfigurationView.getAction(SortLaunchConfigurationAction.ID_SORT_ACTION); + } + /** * Gets the collapse all action * @return the collapse all action diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java index 75fa195c5dc..cf722c801a0 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java @@ -319,4 +319,8 @@ public class LaunchConfigurationsMessages extends NLS { public static String QuickGroupLaunchActionToolTip; + public static String SortLaunchConfigurationAction; + + public static String SortLaunchConfigurationActionDesc; + } diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties index 5418d644fcc..4ce7b0022fd 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties @@ -289,4 +289,6 @@ SelectLaunchersDialog_2=This dialog allows you to specify which launcher to use SelectLaunchersDialog_4=Change Workspace Settings... SelectLaunchersDialog_5=Description SelectLaunchersDialog_launchers=Launc&hers: -SelectFavTypeToFilter= Type to filter \ No newline at end of file +SelectFavTypeToFilter= Type to filter +SortLaunchConfigurationAction=Sort Launch Configurations +SortLaunchConfigurationActionDesc=Sort Launch Configurations by recent launch diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/SortLaunchConfigurationAction.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/SortLaunchConfigurationAction.java new file mode 100644 index 00000000000..4e6161531a5 --- /dev/null +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/SortLaunchConfigurationAction.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2026 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.internal.ui.launchConfigurations; + +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.ui.model.WorkbenchViewerComparator; + +/** + * provides the implementation for sorting the launch configurations within the + * Launch Configuration Dialog + * + */ +public class SortLaunchConfigurationAction extends Action { + + /** + * Action identifier for IDebugView#getAction(String) + */ + public static final String ID_SORT_ACTION = DebugUIPlugin.getUniqueIdentifier() + ".ID_SORT_ACTION"; //$NON-NLS-1$ + + LaunchConfigurationFilteredTree fTree; + + public SortLaunchConfigurationAction(LaunchConfigurationFilteredTree tree) { + super(LaunchConfigurationsMessages.SortLaunchConfigurationAction, IAction.AS_CHECK_BOX); + fTree = tree; + setChecked(DebugUIPlugin.getDefault().getPreferenceStore() + .getBoolean(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT)); + } + + @Override + public void run() { + TreeViewer viewer = fTree.getViewer(); + IPreferenceStore prefStore = DebugUIPlugin.getDefault().getPreferenceStore(); + boolean isSortByRecent = prefStore.getBoolean(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT); + if (!isSortByRecent) { + viewer.setComparator(new LaunchConfigurationComparator(fTree.getLaunchGroup().getIdentifier())); + prefStore.setValue(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT, true); + } else { + viewer.setComparator(new WorkbenchViewerComparator()); + prefStore.setValue(IInternalDebugUIConstants.PREF_LAUNCHCONFIG_SORT_ON_RECENT, false); + } + viewer.refresh(); + } + + @Override + public String getDescription() { + return LaunchConfigurationsMessages.SortLaunchConfigurationActionDesc; + } + + @Override + public ImageDescriptor getImageDescriptor() { + return DebugUITools.getImageDescriptor(IDebugUIConstants.IMG_LCL_DETAIL_PANE_HIDE); + } + + @Override + public String getToolTipText() { + return LaunchConfigurationsMessages.SortLaunchConfigurationActionDesc; + } +}