diff --git a/bundles/org.eclipse.ui.navigator.resources/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.navigator.resources/META-INF/MANIFEST.MF index 5e9f968e313..52eee57bc2d 100644 --- a/bundles/org.eclipse.ui.navigator.resources/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.navigator.resources/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.ui.navigator.resources; singleton:=true -Bundle-Version: 3.9.500.qualifier +Bundle-Version: 3.9.600.qualifier Bundle-Activator: org.eclipse.ui.internal.navigator.resources.plugin.WorkbenchNavigatorPlugin Bundle-Vendor: %Plugin.providerName Bundle-Localization: plugin diff --git a/bundles/org.eclipse.ui.navigator.resources/src/org/eclipse/ui/internal/navigator/resources/actions/ResourceMgmtActionProvider.java b/bundles/org.eclipse.ui.navigator.resources/src/org/eclipse/ui/internal/navigator/resources/actions/ResourceMgmtActionProvider.java index a8fcea10af4..5804c1d7241 100644 --- a/bundles/org.eclipse.ui.navigator.resources/src/org/eclipse/ui/internal/navigator/resources/actions/ResourceMgmtActionProvider.java +++ b/bundles/org.eclipse.ui.navigator.resources/src/org/eclipse/ui/internal/navigator/resources/actions/ResourceMgmtActionProvider.java @@ -18,7 +18,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.ICommand; @@ -114,20 +113,16 @@ public void fillActionBars(IActionBars actionBars) { @Override public void fillContextMenu(IMenuManager menu) { IStructuredSelection selection = (IStructuredSelection) getContext().getSelection(); - boolean isProjectSelection = true; boolean hasOpenProjects = false; boolean hasClosedProjects = false; - boolean hasBuilder = true; // false if any project is closed or does not - // have builder + boolean hasBuilder = true; // false if any project is closed or does not have builder + List projects = selectionToProjects(selection); + boolean selectionContainsNonProject = projects.size() < selection.size(); - Iterator projects = selectionToProjects(selection).iterator(); - - while (projects.hasNext() && (!hasOpenProjects || !hasClosedProjects || hasBuilder || isProjectSelection)) { - IProject project = projects.next(); - - if (project == null) { - isProjectSelection = false; - continue; + for (IProject project : projects) { + if (hasOpenProjects && hasClosedProjects && !hasBuilder) { + // we've set all booleans of interest; no need to loop any further + break; } if (project.isOpen()) { hasOpenProjects = true; @@ -139,30 +134,29 @@ public void fillContextMenu(IMenuManager menu) { hasBuilder = false; } } - if (!selection.isEmpty() && isProjectSelection && !ResourcesPlugin.getWorkspace().isAutoBuilding() + if (!selection.isEmpty() && !ResourcesPlugin.getWorkspace().isAutoBuilding() && hasBuilder) { // Allow manual incremental build only if auto build is off. buildAction.selectionChanged(selection); menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, buildAction); } - // Add the 'refresh' item if any selection is either (a) an open project, or (b) - // a non-project selection (so the 'refresh' item is not shown if all selections - // are closed projects) - if (hasOpenProjects || !isProjectSelection) { + // Add the 'refresh' item if ANY selection is either (a) an open project, or (b) + // a non-project selection. + // Put another way: the 'refresh' item is NOT shown if ALL selections are closed + // projects. + if (hasOpenProjects || selectionContainsNonProject) { refreshAction.selectionChanged(selection); menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, refreshAction); } - if (isProjectSelection) { - if (hasClosedProjects) { - openProjectAction.selectionChanged(selection); - menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, openProjectAction); - } - if (hasOpenProjects) { - closeProjectAction.selectionChanged(selection); - menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, closeProjectAction); - closeUnrelatedProjectsAction.selectionChanged(selection); - menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, closeUnrelatedProjectsAction); - } + if (hasClosedProjects) { + openProjectAction.selectionChanged(selection); + menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, openProjectAction); + } + if (hasOpenProjects) { + closeProjectAction.selectionChanged(selection); + menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, closeProjectAction); + closeUnrelatedProjectsAction.selectionChanged(selection); + menu.appendToGroup(ICommonMenuConstants.GROUP_BUILD, closeUnrelatedProjectsAction); } } diff --git a/tests/org.eclipse.ui.tests.navigator/META-INF/MANIFEST.MF b/tests/org.eclipse.ui.tests.navigator/META-INF/MANIFEST.MF index 30b05fff0f3..438a3039643 100644 --- a/tests/org.eclipse.ui.tests.navigator/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.ui.tests.navigator/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %bundlename Bundle-SymbolicName: org.eclipse.ui.tests.navigator;singleton:=true -Bundle-Version: 3.7.600.qualifier +Bundle-Version: 3.7.700.qualifier Bundle-Localization: plugin Require-Bundle: org.eclipse.core.resources, org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/NavigatorTestSuite.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/NavigatorTestSuite.java index 6b32b4bb593..e9d59c0c9b2 100644 --- a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/NavigatorTestSuite.java +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/NavigatorTestSuite.java @@ -24,6 +24,7 @@ import org.eclipse.ui.tests.navigator.resources.FoldersAsProjectsContributionTest; import org.eclipse.ui.tests.navigator.resources.NestedResourcesTests; import org.eclipse.ui.tests.navigator.resources.PathComparatorTest; +import org.eclipse.ui.tests.navigator.resources.ResourceMgmtActionProviderTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @@ -34,7 +35,7 @@ ProgrammaticOpenTest.class, PipelineTest.class, PipelineChainTest.class, JstPipelineTest.class, LabelProviderTest.class, SorterTest.class, ViewerTest.class, CdtTest.class, M12Tests.class, FirstClassM1Tests.class, LinkHelperTest.class, ShowInTest.class, ResourceTransferTest.class, - EvaluationCacheTest.class, + EvaluationCacheTest.class, ResourceMgmtActionProviderTests.class, NestedResourcesTests.class, PathComparatorTest.class, FoldersAsProjectsContributionTest.class, GoBackForwardsTest.class // DnDTest.class, // DnDTest.testSetDragOperation() fails diff --git a/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java new file mode 100644 index 00000000000..51e8c7f4082 --- /dev/null +++ b/tests/org.eclipse.ui.tests.navigator/src/org/eclipse/ui/tests/navigator/resources/ResourceMgmtActionProviderTests.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright (c) 2024 Dave Carpeneto 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 + *******************************************************************************/ +package org.eclipse.ui.tests.navigator.resources; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.eclipse.core.resources.ICommand; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.ui.actions.ActionContext; +import org.eclipse.ui.internal.navigator.NavigatorContentService; +import org.eclipse.ui.internal.navigator.extensions.CommonActionExtensionSite; +import org.eclipse.ui.internal.navigator.resources.actions.ResourceMgmtActionProvider; +import org.eclipse.ui.navigator.CommonViewerSiteFactory; +import org.eclipse.ui.navigator.ICommonActionExtensionSite; +import org.eclipse.ui.navigator.ICommonMenuConstants; +import org.eclipse.ui.tests.navigator.NavigatorTestBase; +import org.junit.Before; +import org.junit.Test; + +public final class ResourceMgmtActionProviderTests extends NavigatorTestBase { + + private IMenuManager manager; + + public ResourceMgmtActionProviderTests() { + _navigatorInstanceId = TEST_VIEWER; + } + + @Override + @Before + public void setUp() { + super.setUp(); + manager = new MenuManager(); + manager.add(new GroupMarker(ICommonMenuConstants.GROUP_BUILD)); + } + + /** + * Test for 'no selection' condition - no menu items should be included + */ + @Test + public void testFillContextMenu_noSelection() { + ResourceMgmtActionProvider provider = provider((IResource[]) null); + provider.fillContextMenu(manager); + checkMenuHasCorrectContributions(false, false, false, false, false); + } + + /** + * Test for 'folder' condition - only 'refresh' should be included + */ + @Test + public void testFillContextMenu_folderSelection() { + + IFolder justAFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(new Path("some/folder")); + ResourceMgmtActionProvider provider = provider(justAFolder); + provider.fillContextMenu(manager); + checkMenuHasCorrectContributions(false, true, false, false, false); + } + + /** + * Test for 'closed project' - only 'open project' should be included + */ + @Test + public void testFillContextMenu_closedProjectSelection() { + IProject closedProj = ResourcesPlugin.getWorkspace().getRoot().getProject("closedProj"); + ResourceMgmtActionProvider provider = provider(closedProj); + provider.fillContextMenu(manager); + checkMenuHasCorrectContributions(false, false, true, false, false); + } + + /** + * Test for 'open project' that doesn't have a builder attached - all but + * 'build' & 'open project' should be enabled + */ + @Test + public void testFillContextMenu_openProjectNoBuilderSelection() { + IProject openProj = ResourcesPlugin.getWorkspace().getRoot().getProject("Test"); + boolean autoBuildInitialState = ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding(); + + try { + if (!autoBuildInitialState) { + // we want to enable auto-building for this test to guarantee that the 'build' + // menu option isn't shown + IWorkspaceDescription wsd = ResourcesPlugin.getWorkspace().getDescription(); + wsd.setAutoBuilding(true); + ResourcesPlugin.getWorkspace().setDescription(wsd); + } + openProj.open(null); + } catch (CoreException e) { + fail(e.getClass().getSimpleName() + " thrown: " + e.getLocalizedMessage()); + } + ResourceMgmtActionProvider provider = provider(openProj); + provider.fillContextMenu(manager); + checkMenuHasCorrectContributions(false, true, false, true, true); + + if (!autoBuildInitialState) { + // clean-up: reset autobuild since we changed it + try { + IWorkspaceDescription wsd = ResourcesPlugin.getWorkspace().getDescription(); + wsd.setAutoBuilding(false); + ResourcesPlugin.getWorkspace().setDescription(wsd); + } catch (CoreException e) { + fail(e.getClass().getSimpleName() + " thrown: " + e.getLocalizedMessage()); + } + } + } + + /** + * Test for 'open project' that doesn't have a builder attached - only 'open + * project' should be disabled + */ + @Test + public void testFillContextMenu_openProjectWithBuilderSelection() { + IProject openProj = ResourcesPlugin.getWorkspace().getRoot().getProject("Test"); + IWorkspaceDescription wsd = ResourcesPlugin.getWorkspace().getDescription(); + boolean autobuildInitialState = wsd.isAutoBuilding(); + boolean hasNoInitialBuildCommands = false; + IProjectDescription desc = null; + try { + if (autobuildInitialState) { + wsd.setAutoBuilding(false); + ResourcesPlugin.getWorkspace().setDescription(wsd); + } + openProj.open(null); + desc = openProj.getDescription(); + if (desc.getBuildSpec().length == 0) { + hasNoInitialBuildCommands = true; + ICommand cmd = desc.newCommand(); + desc.setBuildSpec(new ICommand[] { cmd }); + openProj.setDescription(desc, null); + } + } catch (CoreException e) { + fail(e.getClass().getSimpleName() + " thrown: " + e.getLocalizedMessage()); + } + ResourceMgmtActionProvider provider = provider(openProj); + provider.fillContextMenu(manager); + checkMenuHasCorrectContributions(true, true, false, true, true); + try { + // clean-up where needed: reset autobuild if we changed it & remove + // the build config if we added it + if (autobuildInitialState) { + wsd.setAutoBuilding(true); + ResourcesPlugin.getWorkspace().setDescription(wsd); + } + if (desc != null && hasNoInitialBuildCommands) { + desc.setBuildSpec(new ICommand[0]); + openProj.setDescription(desc, null); + } + } catch (CoreException e) { + fail(e.getClass().getSimpleName() + " thrown: " + e.getLocalizedMessage()); + } + } + + /* + * Return a provider, given the selected navigator items + */ + private ResourceMgmtActionProvider provider(IResource... selectedElements) { + ICommonActionExtensionSite cfg = new CommonActionExtensionSite("NA", "NA", + CommonViewerSiteFactory.createCommonViewerSite(_commonNavigator.getViewSite()), + (NavigatorContentService) _contentService, _viewer); + ResourceMgmtActionProvider provider = new ResourceMgmtActionProvider(); + StructuredSelection selection = null; + if (selectedElements != null && selectedElements.length > 0) { + selection = new StructuredSelection(selectedElements); + } else { + selection = new StructuredSelection(); + } + provider.setContext(new ActionContext(selection)); + provider.init(cfg); + return provider; + } + + /* + * Check the expected menu items (passed in) against what the menu actually has + */ + private void checkMenuHasCorrectContributions(boolean... actions) { + if (actions.length != 5) { // there's 5 menus we check for + fail(String.format("Incorrect number of menu items being checked : %d", actions.length)); + } + int index = 0; + for (String thisAction : new String[] { "org.eclipse.ui.BuildAction", "org.eclipse.ui.RefreshAction", + "org.eclipse.ui.OpenResourceAction", "org.eclipse.ui.CloseResourceAction", + "org.eclipse.ui.CloseUnrelatedProjectsAction" }) { + assertTrue(String.format("Unexpected menu membership for %s (%b)", thisAction, !actions[index]), + actions[index] == menuHasContribution(thisAction)); + index++; + } + } + + /* + * Check the menu for the named entry + */ + private boolean menuHasContribution(String contribution) { + for (IContributionItem thisItem : manager.getItems()) { + if (thisItem.getId().equals(contribution)) { + return true; + } + } + return false; + } + +} \ No newline at end of file