Show Open/Close Project for mixed selections in Project Explorer#3866
Show Open/Close Project for mixed selections in Project Explorer#3866vogella wants to merge 2 commits intoeclipse-platform:masterfrom
Conversation
05018be to
e1e0229
Compare
7252610 to
424a16a
Compare
Ctrl+A in an expanded Project Explorer produces a mixed selection: projects, child files/folders, and non-adaptable elements such as working set headers. Three problems combined to hide the Open/Close Project actions in that case: 1. The ResourceMgmtActionProvider enablement expression required ALL selected elements to adapt to IResource or IWorkingSet, so the provider was never activated for mixed selections. Fixed by replacing the expression with <or/> to always activate the provider. 2. CloseResourceAction and OpenResourceAction.updateSelection() called selectionIsOfType(PROJECT), which returns false whenever any non-IResource element (e.g. a working set header) is present in the selection, even if every resource element is a valid open/closed project. Fixed by checking getSelectedResources() directly. 3. CloseUnrelatedProjectsAction.resourceChanged() had the same selectionIsOfType guard, preventing the action from reacting to project state changes for mixed selections. Fixed analogously. ResourceMgmtActionProvider now overrides getSelectedResources() on the open/close action instances to filter the selection down to IProject elements only, so that files and folders selected alongside projects (expanded Ctrl+A) do not disable the actions. Fixes eclipse-platform#3790
Move the project-filtering logic from anonymous getSelectedResources() overrides in ResourceMgmtActionProvider into the action classes themselves (OpenResourceAction, CloseResourceAction, CloseUnrelatedProjectsAction). This fixes the API analysis build failure caused by illegally subclassing these action classes. The updateSelection() methods now filter getSelectedResources() to IProject instances, so mixed selections (e.g. Ctrl+A) correctly enable/disable Open/Close Project actions. The resourceChanged() methods also use stream-based project checks instead of selectionIsOfType() to react properly to project state changes during mixed selections.
424a16a to
ea62040
Compare
There was a problem hiding this comment.
Pull request overview
This PR targets Project Explorer context-menu behavior so that Open/Close Project-related actions remain visible for mixed selections (e.g., when Ctrl+A includes working set headers or other non-resource elements), aligning with the behavior requested in issue #3790.
Changes:
- Made
ResourceMgmtActionProviderenablement unconditional inplugin.xmlso the provider is invoked even for mixed/non-resource selections. - Added navigator tests covering mixed selections (projects + files, projects + non-adaptable objects, multiple open projects with child resources).
- Updated project open/close actions’ selection checks to be based on “any selected project” (stream filter) instead of
selectionIsOfType(PROJECT).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java | Adds regression coverage for mixed selections and helper methods to build arbitrary selections. |
| bundles/org.eclipse.ui.navigator.resources/plugin.xml | Changes action provider enablement to always-on (<or/>) to avoid being filtered out by mixed selections. |
| bundles/org.eclipse.ui.ide/extensions/org/eclipse/ui/actions/OpenResourceAction.java | Adjusts enablement and delta-check gating to detect projects in mixed selections. |
| bundles/org.eclipse.ui.ide/extensions/org/eclipse/ui/actions/CloseUnrelatedProjectsAction.java | Adjusts delta-check gating to detect projects in mixed selections. |
| bundles/org.eclipse.ui.ide/extensions/org/eclipse/ui/actions/CloseResourceAction.java | Adjusts enablement and delta-check gating to detect projects in mixed selections. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| List<IProject> projects = getSelectedResources().stream() | ||
| .filter(IProject.class::isInstance).map(IProject.class::cast).toList(); | ||
| if (projects.isEmpty()) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
updateSelection() now enables the action when any project is selected, even in mixed selections. However, run()/runInBackground() still uses getSelectedResources() and then casts every element to IProject (e.g., when building scheduling rules), which will throw ClassCastException if the selection includes non-project resources (files/folders) as allowed by the new enablement. Filter to IProject consistently (ideally by overriding getActionResources() to return only projects and using that list throughout run()).
| List<IProject> projects = getSelectedResources().stream() | ||
| .filter(IProject.class::isInstance).map(IProject.class::cast).toList(); | ||
| if (projects.isEmpty()) { |
There was a problem hiding this comment.
Allowing mixed selections means internal logic must also tolerate non-project resources. hasOtherClosedProjects() still iterates getSelectedResources() and blindly casts each entry to IProject, which can now be an IFile/IFolder and will cause a ClassCastException when opening projects with references from a mixed selection. Update this logic to only consider selected IProject instances (similar to the new projects filtering in updateSelection()).
| Object nonResource = new Object(); | ||
| ResourceMgmtActionProvider provider = providerForObjects(openProj, nonResource); | ||
| provider.fillContextMenu(manager); | ||
| checkMenuHasCorrectContributions(false, true, false, true, true); |
There was a problem hiding this comment.
This regression test covers visibility for a mixed selection that includes a non-adaptable element, but it doesn't assert enablement. Given the goal of issue #3790, it would be valuable to also assert that Close Project / Close Unrelated Projects are enabled (not just present) when an open project is part of the selection; otherwise the menu items could still be shown but unusable.
| checkMenuHasCorrectContributions(false, true, false, true, true); | |
| checkMenuHasCorrectContributions(false, true, false, true, true); | |
| assertTrue(isMenuContributionEnabled("org.eclipse.ui.CloseResourceAction"), | |
| "Close Project should be enabled when an open project is selected with a non-adaptable element"); | |
| assertTrue(isMenuContributionEnabled("org.eclipse.ui.CloseUnrelatedProjectsAction"), | |
| "Close Unrelated Projects should be enabled when an open project is selected with a non-adaptable element"); |
| <!-- Always enabled: fillContextMenu() filters to applicable projects --> | ||
| <or/> |
There was a problem hiding this comment.
Switching the provider enablement to unconditional () makes these actions show up for selections containing non-resource elements, but the underlying actions still need to ignore non-resource selection entries for enablement and execution (not just menu population). Please double-check that the actions added by ResourceMgmtActionProvider are enabled and runnable when the selection includes non-IResource/IWorkingSet elements (e.g., working set headers), otherwise this can regress into visible-but-disabled actions.
| <!-- Always enabled: fillContextMenu() filters to applicable projects --> | |
| <or/> | |
| <or> | |
| <adapt type="org.eclipse.core.resources.IResource"/> | |
| <instanceof value="org.eclipse.ui.IWorkingSet"/> | |
| </or> |
| public void resourceChanged(IResourceChangeEvent event) { | ||
| // don't bother looking at delta if selection not applicable | ||
| if (selectionIsOfType(IResource.PROJECT)) { | ||
| List<? extends IResource> selectedResources = super.getSelectedResources(); | ||
| if (selectedResources.stream().anyMatch(IProject.class::isInstance)) { | ||
| IResourceDelta delta = event.getDelta(); |
There was a problem hiding this comment.
CloseUnrelatedProjectsAction is now enabled for mixed selections via provider changes, but updateSelection() still depends on selectionIsOfType(IResource.PROJECT), which returns false when the selection contains any non-resource element (e.g., working set headers). That means this action can still appear but be disabled for the exact scenario in issue #3790. Consider aligning enablement logic with Open/CloseResourceAction (e.g., enable when any selected resource is a project, ignoring non-resources).
The
ResourceMgmtActionProviderenablement expression required all selected elements to adapt toIResourceorIWorkingSet. This hid Open/Close Project actions when the selection contained non-resource elements (e.g., working set headers from Ctrl+A).Changed the enablement to always activate the provider (using
<or/>, the same pattern asUndoRedoActionProvider). The existingfillContextMenu()logic viaselectionToProjects()already filters to applicable projects and only shows relevant actions — no behavioral change for pure-project selections.Fixes #3790