Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package org.eclipse.ui.actions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IFile;
Expand Down Expand Up @@ -229,14 +228,14 @@ protected boolean updateSelection(IStructuredSelection s) {
// don't call super since we want to enable if open project is selected.
setText(defaultText);
setToolTipText(defaultToolTip);
if (!selectionIsOfType(IResource.PROJECT)) {
List<IProject> projects = getSelectedResources().stream()
.filter(IProject.class::isInstance).map(IProject.class::cast).toList();
if (projects.isEmpty()) {
return false;
}

boolean hasOpenProjects = false;
Iterator<? extends IResource> resources = getSelectedResources().iterator();
while (resources.hasNext()) {
IProject currentResource = (IProject) resources.next();
for (IProject currentResource : projects) {
if (currentResource.isOpen()) {
if (hasOpenProjects) {
setText(pluralText);
Expand All @@ -258,7 +257,7 @@ public synchronized void resourceChanged(IResourceChangeEvent event) {
// Warning: code duplicated in OpenResourceAction
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
if (delta != null) {
IResourceDelta[] projDeltas = delta.getAffectedChildren(IResourceDelta.CHANGED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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()) {
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);
Expand Down
9 changes: 2 additions & 7 deletions bundles/org.eclipse.ui.navigator.resources/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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/>
</enablement>
</actionProvider>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
* Test for a fully expanded selection: two open projects plus child resources
* from both (simulating Ctrl+A when both projects are expanded). Close Project
* must still appear for the open projects in the selection.
*
* @throws CoreException
*/
@Test
public void testFillContextMenu_twoOpenProjectsWithChildResourcesSelection() throws CoreException {
// _p1 and _p2 are already opened in setUp()
IFolder srcFolder = _project.getFolder("src");
IFolder binFolder = _project.getFolder("bin");
ResourceMgmtActionProvider provider = providerForObjects(_p1, _p2, srcFolder, binFolder);
provider.fillContextMenu(manager);
checkMenuHasCorrectContributions(false, true, false, true, true);
}

/**
* Test for 'open project' that doesn't have a builder attached - only 'open
* project' should be disabled
Expand Down Expand Up @@ -158,6 +219,19 @@ public void testFillContextMenu_openProjectWithBuilderSelection() throws CoreExc
}
}

/*
* Return a provider for a mixed/arbitrary selection (Object[])
*/
private ResourceMgmtActionProvider providerForObjects(Object... selectedElements) {
ICommonActionExtensionSite cfg = new CommonActionExtensionSite("NA", "NA",
CommonViewerSiteFactory.createCommonViewerSite(_commonNavigator.getViewSite()),
(NavigatorContentService) _contentService, _viewer);
ResourceMgmtActionProvider provider = new ResourceMgmtActionProvider();
provider.setContext(new ActionContext(new StructuredSelection(selectedElements)));
provider.init(cfg);
return provider;
}

/*
* Return a provider, given the selected navigator items
*/
Expand Down Expand Up @@ -206,4 +280,16 @@ private boolean menuHasContribution(String contribution) {
return false;
}

/*
* Check whether the named menu entry is enabled
*/
private boolean isMenuContributionEnabled(String contribution) {
for (IContributionItem thisItem : manager.getItems()) {
if (thisItem.getId() != null && thisItem.getId().equals(contribution)) {
return thisItem.isEnabled();
}
}
return false;
}

}
Loading