-
Notifications
You must be signed in to change notification settings - Fork 248
Show Open/Close Project for mixed selections in Project Explorer #3866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -261,7 +261,8 @@ protected List<? extends IResource> getSelectedResources() { | |
| @Override | ||
| 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(); | ||
|
Comment on lines
262
to
266
|
||
| if (delta != null) { | ||
| IResourceDelta[] projDeltas = delta.getAffectedChildren(IResourceDelta.CHANGED); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -190,7 +190,7 @@ public void resourceChanged(IResourceChangeEvent event) { | |
| // Warning: code duplicated in CloseResourceAction | ||
| List<? extends IResource> sel = getSelectedResources(); | ||
| // don't bother looking at delta if selection not applicable | ||
| if (selectionIsOfType(IResource.PROJECT)) { | ||
| if (sel.stream().anyMatch(IProject.class::isInstance)) { | ||
| IResourceDelta delta = event.getDelta(); | ||
| if (delta != null) { | ||
| IResourceDelta[] projDeltas = delta.getAffectedChildren(IResourceDelta.CHANGED); | ||
|
|
@@ -304,13 +304,15 @@ protected boolean updateSelection(IStructuredSelection s) { | |
| // selected. | ||
| setText(IDEWorkbenchMessages.OpenResourceAction_text); | ||
| setToolTipText(IDEWorkbenchMessages.OpenResourceAction_toolTip); | ||
| if (!selectionIsOfType(IResource.PROJECT)) { | ||
| List<IProject> projects = getSelectedResources().stream() | ||
| .filter(IProject.class::isInstance).map(IProject.class::cast).toList(); | ||
| if (projects.isEmpty()) { | ||
|
Comment on lines
+307
to
+309
|
||
| return false; | ||
| } | ||
|
|
||
| boolean hasClosedProjects = false; | ||
| for (IResource currentResource : getSelectedResources()) { | ||
| if (!((IProject) currentResource).isOpen()) { | ||
| for (IProject currentResource : projects) { | ||
| if (!currentResource.isOpen()) { | ||
| if (hasClosedProjects) { | ||
| setText(IDEWorkbenchMessages.OpenResourceAction_text_plural); | ||
| setToolTipText(IDEWorkbenchMessages.OpenResourceAction_toolTip_plural); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -237,13 +237,8 @@ | |||||||||||||
| class="org.eclipse.ui.internal.navigator.resources.actions.ResourceMgmtActionProvider" | ||||||||||||||
| id="org.eclipse.ui.navigator.resources.ResourceMgmtActions"> | ||||||||||||||
| <enablement> | ||||||||||||||
| <or> | ||||||||||||||
| <adapt type="org.eclipse.core.resources.IResource" /> | ||||||||||||||
| <adapt type="java.util.Collection"> | ||||||||||||||
| <count value="0" /> | ||||||||||||||
| </adapt> | ||||||||||||||
| <adapt type="org.eclipse.ui.IWorkingSet" /> | ||||||||||||||
| </or> | ||||||||||||||
| <!-- Always enabled: fillContextMenu() filters to applicable projects --> | ||||||||||||||
| <or/> | ||||||||||||||
|
Comment on lines
+240
to
+241
|
||||||||||||||
| <!-- Always enabled: fillContextMenu() filters to applicable projects --> | |
| <or/> | |
| <or> | |
| <adapt type="org.eclipse.core.resources.IResource"/> | |
| <instanceof value="org.eclipse.ui.IWorkingSet"/> | |
| </or> |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -118,6 +118,67 @@ public void testFillContextMenu_openProjectNoBuilderSelection() throws CoreExcep | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Test for a file selected together with an open project: Close Project must | ||||||||||||||
| * be both present and enabled. Regression test for the bug where | ||||||||||||||
| * selectionIsOfType(PROJECT) disabled the action for any mixed selection. | ||||||||||||||
| * | ||||||||||||||
| * @throws CoreException | ||||||||||||||
| */ | ||||||||||||||
| @Test | ||||||||||||||
| public void testFillContextMenu_fileAndOpenProjectSelection_closeProjectEnabled() throws CoreException { | ||||||||||||||
| // _p1 is already open; _project has a known 'src' folder + files | ||||||||||||||
| IProject openProj = ResourcesPlugin.getWorkspace().getRoot().getProject("Test"); | ||||||||||||||
| openProj.open(null); | ||||||||||||||
| // Select a file alongside a project (the typical Ctrl+A expanded scenario) | ||||||||||||||
| ResourceMgmtActionProvider provider = providerForObjects(_p1, openProj.getFile(".project")); | ||||||||||||||
| provider.fillContextMenu(manager); | ||||||||||||||
| assertTrue(menuHasContribution("org.eclipse.ui.CloseResourceAction"), | ||||||||||||||
| "Close Project should be in the menu"); | ||||||||||||||
| assertTrue(isMenuContributionEnabled("org.eclipse.ui.CloseResourceAction"), | ||||||||||||||
| "Close Project should be enabled when open projects are in the selection"); | ||||||||||||||
| assertTrue(menuHasContribution("org.eclipse.ui.CloseUnrelatedProjectsAction"), | ||||||||||||||
| "Close Unrelated Projects should be in the menu"); | ||||||||||||||
| assertTrue(isMenuContributionEnabled("org.eclipse.ui.CloseUnrelatedProjectsAction"), | ||||||||||||||
| "Close Unrelated Projects should be enabled when open projects are in the selection"); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Test for mixed selection: an open project alongside a non-adaptable element | ||||||||||||||
| * (e.g. a working set header from Ctrl+A in Project Explorer). Close Project | ||||||||||||||
| * and Refresh must still appear — regression test for issue #3790. | ||||||||||||||
| * | ||||||||||||||
| * @throws CoreException | ||||||||||||||
| */ | ||||||||||||||
| @Test | ||||||||||||||
| public void testFillContextMenu_mixedSelectionOpenProjectAndNonAdaptableElement() throws CoreException { | ||||||||||||||
| IProject openProj = ResourcesPlugin.getWorkspace().getRoot().getProject("Test"); | ||||||||||||||
| openProj.open(null); | ||||||||||||||
| // Plain Object does not implement IAdaptable, so it is never resolved to a | ||||||||||||||
| // project — it counts as a non-project element in the selection. | ||||||||||||||
| Object nonResource = new Object(); | ||||||||||||||
| ResourceMgmtActionProvider provider = providerForObjects(openProj, nonResource); | ||||||||||||||
| provider.fillContextMenu(manager); | ||||||||||||||
| checkMenuHasCorrectContributions(false, true, false, true, true); | ||||||||||||||
|
||||||||||||||
| 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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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()).