From fd09187f9a4fff3bf4f18794cf994773dc8fdf28 Mon Sep 17 00:00:00 2001 From: Simeon Andreev Date: Wed, 25 Nov 2020 12:46:13 +0100 Subject: [PATCH] Bug 383348 - Replace actions with invalid menu paths in CDT UI This change adjusts replaces the following actions (part of action set org.eclipse.cdt.ui.buildConfigActionSet) with commands and menus: * org.eclipse.cdt.ui.manageConfigsAction2 * org.eclipse.cdt.ui.buildConfigMenuAction * org.eclipse.cdt.ui.wsselection This is done to avoid menu extension errors on perspective customization, due to problematic code in CustomizePerspectiveDialog. In particular the customize perspective dialog will populate main menu submenus only after going over actions; this causes the menu paths of the actions above to be detected as invalid, despite actually being valid and functional. The original action classes are deprecated and marked for removal. The respective classes are defined in non-internal packages; removal would be considered API breakage and so must be done in a major version bump. Change-Id: I31517697689772395b7e1868ef4cab07ad946085 Signed-off-by: Simeon Andreev --- core/org.eclipse.cdt.ui/plugin.properties | 2 + core/org.eclipse.cdt.ui/plugin.xml | 120 +++++-- .../ui/actions/ManageConfigsHandler.java | 44 +++ .../ui/actions/WorkingSetConfigHandler.java | 53 ++++ .../ChangeBuildConfigContribution.java | 298 ++++++++++++++++++ .../HasManagedCdtProjectSelection.java | 50 +++ .../NonEmptyWorkingSetPropertyTester.java | 50 +++ .../actions/ChangeBuildConfigMenuAction.java | 3 + .../cdt/ui/actions/ManageConfigsAction.java | 3 + .../ui/actions/WorkingSetConfigAction.java | 2 + 10 files changed, 603 insertions(+), 22 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ManageConfigsHandler.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/WorkingSetConfigHandler.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/ChangeBuildConfigContribution.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/HasManagedCdtProjectSelection.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/NonEmptyWorkingSetPropertyTester.java diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 9aac275b99c..178d9267284 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -496,6 +496,8 @@ SearchUnresolvedIncludes.name=Search for Unresolved Includes SearchUnresolvedIncludes.label=Search for Unresolved &Includes CreateParserLog.name=Create Parser Log File CreateParserLog.label=Create Parser &Log File +wsselection.command.name=Manage Working Sets +ManageConfigs.command.name=Manage Build Configurations indexerPage.name = Indexer Page proposalFilter.name = Code Completion Proposal Filter diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index ee0a5873c7d..103e3a96954 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -1750,6 +1750,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + @@ -4719,6 +4777,24 @@ + + + + + + + + + + + + projects = findProjects(); + + SortedSet configNames = new TreeSet<>(); + String sCurrentConfig = null; + boolean bCurrentConfig = true; + for (IProject prj : projects) { + ICConfigurationDescription[] cfgDescs = getCfgs(prj); + + String sActiveConfig = null; + // Store names and detect active configuration + for (ICConfigurationDescription cfgDesc : cfgDescs) { + String s = cfgDesc.getName(); + if (!configNames.contains(s)) + configNames.add(s); + if (cfgDesc.isActive()) + sActiveConfig = s; + } + + // Check whether all projects have the same active configuration + if (bCurrentConfig) { + if (sCurrentConfig == null) + sCurrentConfig = sActiveConfig; + else { + if (!sCurrentConfig.equals(sActiveConfig)) + bCurrentConfig = false; + } + } + } + + List actions = new ArrayList<>(); + int accel = 0; + for (String sName : configNames) { + String sDesc = null; + boolean commonName = true; + boolean commonDesc = true; + boolean firstProj = true; + for (IProject prj : projects) { + ICConfigurationDescription[] cfgDescs = getCfgs(prj); + int i = 0; + for (; i < cfgDescs.length; i++) { + if (cfgDescs[i].getName().equals(sName)) { + String sNewDesc = cfgDescs[i].getDescription(); + if (sNewDesc != null && sNewDesc.length() == 0) { + sNewDesc = null; + } + if (commonDesc) { + if (firstProj) { + sDesc = sNewDesc; + firstProj = false; + } else if (sNewDesc == null && sDesc != null + || sNewDesc != null && !sNewDesc.equals(sDesc)) { + commonDesc = false; + } + } + break; + } + } + if (i == cfgDescs.length) { + commonName = false; + break; + } + } + if (commonName) { + StringBuffer builder = new StringBuffer(sName); + if (commonDesc) { + if (sDesc != null) { + builder.append(" ("); //$NON-NLS-1$ + builder.append(sDesc); + builder.append(")"); //$NON-NLS-1$ + } + } else { + builder.append(" (...)"); //$NON-NLS-1$ + } + + IAction action = new ChangeConfigAction(projects, sName, builder.toString(), accel + 1); + if (bCurrentConfig && sCurrentConfig != null && sCurrentConfig.equals(sName)) { + action.setChecked(true); + } + ActionContributionItem item = new ActionContributionItem(action); + actions.add(item); + accel++; + } + } + return actions.toArray(new IContributionItem[0]); + } + + private static HashSet findProjects() { + HashSet fProjects = new LinkedHashSet<>(); + ISelection selection = CUIPlugin.getActivePage().getSelection(); + boolean badObject = addProjectsFromSelection(selection, fProjects); + + if (badObject || fProjects.isEmpty()) { + // Check for lone CDT project in workspace + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + if (projects != null && projects.length == 1) { + IProject project = projects[0]; + if (CoreModel.getDefault().isNewStyleProject(project) && (getCfgs(project).length > 0)) { + fProjects.add(project); + } + } + + // Check the three supported views + IWorkbenchPage page = CUIPlugin.getActivePage(); + int viewCount = 0; + if (page != null) { + IViewReference theViewRef = null; + IViewReference viewRef = null; + + theViewRef = page.findViewReference("org.eclipse.cdt.ui.CView"); //$NON-NLS-1$ + viewCount += (theViewRef != null) ? 1 : 0; + + viewRef = page.findViewReference("org.eclipse.ui.navigator.ProjectExplorer"); //$NON-NLS-1$ + viewCount += (viewRef != null) ? 1 : 0; + theViewRef = (theViewRef == null) ? viewRef : theViewRef; + + viewRef = page.findViewReference("org.eclipse.ui.views.ResourceNavigator"); //$NON-NLS-1$ + viewCount += (viewRef != null) ? 1 : 0; + theViewRef = (theViewRef == null) ? viewRef : theViewRef; + + if (theViewRef != null && viewCount == 1) { + IViewPart view = theViewRef.getView(false); + if (view != null) { + ISelection cdtSelection = view.getSite().getSelectionProvider().getSelection(); + if (cdtSelection != null) { + if (!cdtSelection.isEmpty()) { + if (!cdtSelection.equals(selection)) { + addProjectsFromSelection(cdtSelection, fProjects); + } + } + } + } + } + } + } + return fProjects; + } + + private static boolean addProjectsFromSelection(ISelection selection, HashSet fProjects) { + boolean badObject = false; + if (selection != null) { + if (selection instanceof IStructuredSelection) { + if (selection.isEmpty()) { + // could be a form editor or something. try to get the project from the active part + IWorkbenchPage page = CUIPlugin.getActivePage(); + if (page != null) { + IWorkbenchPart part = page.getActivePart(); + if (part != null) { + Object o = part.getAdapter(IResource.class); + if (o != null && o instanceof IResource) { + fProjects.add(((IResource) o).getProject()); + } + } + } + } + Iterator iter = ((IStructuredSelection) selection).iterator(); + while (iter.hasNext()) { + Object selItem = iter.next(); + IProject project = null; + if (selItem instanceof ICElement) { + ICProject cproject = ((ICElement) selItem).getCProject(); + if (cproject != null) + project = cproject.getProject(); + } else if (selItem instanceof IResource) { + project = ((IResource) selItem).getProject(); + } else if (selItem instanceof IncludeRefContainer) { + ICProject fCProject = ((IncludeRefContainer) selItem).getCProject(); + if (fCProject != null) + project = fCProject.getProject(); + } else if (selItem instanceof IncludeReferenceProxy) { + IncludeRefContainer irc = ((IncludeReferenceProxy) selItem).getIncludeRefContainer(); + if (irc != null) { + ICProject fCProject = irc.getCProject(); + if (fCProject != null) + project = fCProject.getProject(); + } + } else if (selItem instanceof IAdaptable) { + Object adapter = ((IAdaptable) selItem).getAdapter(IProject.class); + if (adapter != null && adapter instanceof IProject) { + project = (IProject) adapter; + } + } + // Check whether the project is CDT project + if (project != null) { + if (!CoreModel.getDefault().isNewStyleProject(project)) + project = null; + else { + ICConfigurationDescription[] tmp = getCfgs(project); + if (tmp.length == 0) + project = null; + } + } + if (project != null) { + fProjects.add(project); + } else { + badObject = true; + break; + } + } + } else if (selection instanceof ITextSelection) { + // If a text selection check the selected part to see if we can find + // an editor part that we can adapt to a resource and then + // back to a project. + IWorkbenchWindow window = CUIPlugin.getActiveWorkbenchWindow(); + if (window != null) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IWorkbenchPart part = page.getActivePart(); + if (part instanceof IEditorPart) { + IEditorPart epart = (IEditorPart) part; + IResource resource = epart.getEditorInput().getAdapter(IResource.class); + if (resource != null) { + IProject project = resource.getProject(); + badObject = !(project != null && CoreModel.getDefault().isNewStyleProject(project)); + + if (!badObject) { + fProjects.add(project); + } + } + } + } + } + + } + } + return badObject; + } + + private static ICConfigurationDescription[] getCfgs(IProject prj) { + ICProjectDescription prjd = CoreModel.getDefault().getProjectDescription(prj, false); + if (prjd != null) { + ICConfigurationDescription[] cfgs = prjd.getConfigurations(); + if (cfgs != null) { + return cfgs; + } + } + + return new ICConfigurationDescription[0]; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/HasManagedCdtProjectSelection.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/HasManagedCdtProjectSelection.java new file mode 100644 index 00000000000..cc1f4800539 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/HasManagedCdtProjectSelection.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2020 Simeon Andreev 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: + * Simeon Andreev - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.workingsets; + +import java.util.Collection; + +import org.eclipse.cdt.ui.newui.ManageConfigSelector; +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.core.resources.IProject; + +/** + * Property tester for the enablement of the command handled by {@link org.eclipse.cdt.internal.ui.actions.ManageConfigsHandler}. + * Will evaluate {@code true} if the current selection is a managed CDT project, contains a managed CDT project, or belongs to a managed CDT project. + */ +public class HasManagedCdtProjectSelection extends PropertyTester { + + private static final String PROPERTY_HAS_MANAGED_CDT_PROJECT_SELECTION = "hasManagedCdtProjectSelection"; //$NON-NLS-1$ + + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (PROPERTY_HAS_MANAGED_CDT_PROJECT_SELECTION.equals(property)) { + boolean hasNonEmptyWorksets = hasManagedCdtProjectSelection(receiver); + return hasNonEmptyWorksets; + } + return false; + } + + private static boolean hasManagedCdtProjectSelection(Object receiver) { + if (receiver instanceof Collection) { + Collection selection = (Collection) receiver; + if (!selection.isEmpty()) { + IProject[] obs = ManageConfigSelector.getProjects(selection.toArray()); + return ManageConfigSelector.getManager(obs) != null; + } + } + return false; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/NonEmptyWorkingSetPropertyTester.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/NonEmptyWorkingSetPropertyTester.java new file mode 100644 index 00000000000..2944480388d --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/workingsets/NonEmptyWorkingSetPropertyTester.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2020 Simeon Andreev 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: + * Simeon Andreev - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.workingsets; + +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; + +/** + * Property tester for the enablement of the command handled by {@link org.eclipse.cdt.internal.ui.actions.WorkingSetConfigHandler}. + * Will evaluate {@code true} if there is a non-empty working set in the workspace. + */ +public class NonEmptyWorkingSetPropertyTester extends PropertyTester { + + private static final String PROPERTY_HAS_NON_EMPTY_WORKING_SET = "hasNonEmptyWorkingSet"; //$NON-NLS-1$ + + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (PROPERTY_HAS_NON_EMPTY_WORKING_SET.equals(property)) { + boolean hasNonEmptyWorksets = hasNonEmptyWorksets(); + return hasNonEmptyWorksets; + } + return false; + } + + private static boolean hasNonEmptyWorksets() { + IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); + IWorkingSet[] workingSets = workingSetManager.getWorkingSets(); + if (workingSets != null) { + for (IWorkingSet workingSet : workingSets) { + if (!workingSet.isEmpty()) { + return true; + } + } + } + return false; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ChangeBuildConfigMenuAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ChangeBuildConfigMenuAction.java index 06b6fea382e..aae36101f0d 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ChangeBuildConfigMenuAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ChangeBuildConfigMenuAction.java @@ -30,7 +30,10 @@ import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2; /** * Action which changes active build configuration of the current project + * + * @deprecated Replaced with menu contribution {@link org.eclipse.cdt.internal.ui.workingsets.ChangeBuildConfigContribution}. */ +@Deprecated(forRemoval = true) public class ChangeBuildConfigMenuAction extends ChangeBuildConfigActionBase implements IWorkbenchWindowPulldownDelegate2 { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ManageConfigsAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ManageConfigsAction.java index 2027fd369fa..0a09b297c1c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ManageConfigsAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/ManageConfigsAction.java @@ -28,7 +28,10 @@ import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2; /** * Action which lets to manage (add/remove etc.) build configurations of the project. + * + * @deprecated Replaced with a command and handler {@link org.eclipse.cdt.internal.ui.actions.ManageConfigsHandler}. */ +@Deprecated(forRemoval = true) public class ManageConfigsAction implements IWorkbenchWindowPulldownDelegate2, IObjectActionDelegate { IProject[] obs = null; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java index d238c84c8d3..df549077886 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/actions/WorkingSetConfigAction.java @@ -27,7 +27,9 @@ import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.PlatformUI; /** + * @deprecated Replaced with a command and handler {@link org.eclipse.cdt.internal.ui.actions.WorkingSetConfigHandler}. */ +@Deprecated(forRemoval = true) public class WorkingSetConfigAction implements IWorkbenchWindowActionDelegate, IPropertyChangeListener { private static final IWorkingSetManager wsm = PlatformUI.getWorkbench().getWorkingSetManager();