| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.ui.actions; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| |
| import org.eclipse.jface.text.ITextSelection; |
| |
| import org.eclipse.ui.IWorkbenchSite; |
| import org.eclipse.ui.PlatformUI; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IImportDeclaration; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IOrdinaryClassFile; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| |
| import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; |
| import org.eclipse.jdt.internal.ui.IJavaStatusConstants; |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.actions.ActionMessages; |
| import org.eclipse.jdt.internal.ui.actions.ActionUtil; |
| import org.eclipse.jdt.internal.ui.actions.SelectionConverter; |
| import org.eclipse.jdt.internal.ui.browsing.LogicalPackage; |
| import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; |
| import org.eclipse.jdt.internal.ui.util.ExceptionHandler; |
| import org.eclipse.jdt.internal.ui.util.OpenTypeHierarchyUtil; |
| |
| /** |
| * This action opens a type hierarchy on the selected type. |
| * <p> |
| * The action is applicable to selections containing elements of type |
| * <code>IType</code>. |
| * |
| * <p> |
| * This class may be instantiated; it is not intended to be subclassed. |
| * </p> |
| * |
| * @since 2.0 |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class OpenTypeHierarchyAction extends SelectionDispatchAction { |
| |
| private JavaEditor fEditor; |
| |
| /** |
| * Creates a new <code>OpenTypeHierarchyAction</code>. The action requires |
| * that the selection provided by the site's selection provider is of type <code> |
| * org.eclipse.jface.viewers.IStructuredSelection</code>. |
| * |
| * @param site the site providing context information for this action |
| */ |
| public OpenTypeHierarchyAction(IWorkbenchSite site) { |
| super(site); |
| setText(ActionMessages.OpenTypeHierarchyAction_label); |
| setToolTipText(ActionMessages.OpenTypeHierarchyAction_tooltip); |
| setDescription(ActionMessages.OpenTypeHierarchyAction_description); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.OPEN_TYPE_HIERARCHY_ACTION); |
| } |
| |
| /** |
| * Creates a new <code>OpenTypeHierarchyAction</code>. The action requires |
| * that the selection provided by the given selection provider is of type <code> |
| * org.eclipse.jface.viewers.IStructuredSelection</code>. |
| * |
| * @param site the site providing context information for this action |
| * @param provider a special selection provider which is used instead |
| * of the site's selection provider or <code>null</code> to use the site's |
| * selection provider |
| * |
| * @since 3.2 |
| * @deprecated Use {@link #setSpecialSelectionProvider(ISelectionProvider)} instead. This API will be |
| * removed after 3.2 M5. |
| */ |
| @Deprecated |
| public OpenTypeHierarchyAction(IWorkbenchSite site, ISelectionProvider provider) { |
| this(site); |
| setSpecialSelectionProvider(provider); |
| } |
| |
| |
| /** |
| * Note: This constructor is for internal use only. Clients should not call this constructor. |
| * @param editor the Java editor |
| * |
| * @noreference This constructor is not intended to be referenced by clients. |
| */ |
| public OpenTypeHierarchyAction(JavaEditor editor) { |
| this(editor.getEditorSite()); |
| fEditor= editor; |
| setEnabled(SelectionConverter.canOperateOn(fEditor)); |
| } |
| |
| @Override |
| public void selectionChanged(ITextSelection selection) { |
| } |
| |
| @Override |
| public void selectionChanged(IStructuredSelection selection) { |
| setEnabled(isEnabled(selection)); |
| } |
| |
| private boolean isEnabled(IStructuredSelection selection) { |
| Object[] elements= selection.toArray(); |
| if (elements.length == 0) |
| return false; |
| |
| if (elements.length == 1) { |
| Object input= elements[0]; |
| if (input instanceof LogicalPackage) |
| return true; |
| if (!(input instanceof IJavaElement)) |
| return false; |
| |
| switch (((IJavaElement)input).getElementType()) { |
| case IJavaElement.INITIALIZER: |
| case IJavaElement.METHOD: |
| case IJavaElement.FIELD: |
| case IJavaElement.TYPE: |
| case IJavaElement.IMPORT_DECLARATION: |
| case IJavaElement.CLASS_FILE: |
| case IJavaElement.COMPILATION_UNIT: |
| return true; |
| case IJavaElement.LOCAL_VARIABLE: |
| case IJavaElement.TYPE_PARAMETER: |
| case IJavaElement.ANNOTATION: |
| return false; |
| default: |
| // continue below |
| } |
| } |
| |
| // strategy: allow non-IJavaElements (e.g. an IResource), but stop for invalid IJavaElements |
| boolean hasValidElement= false; |
| for (int j= 0; j < elements.length; j++) { |
| Object input= elements[j]; |
| if (input instanceof LogicalPackage) { |
| hasValidElement= true; |
| continue; |
| } |
| if (!(input instanceof IJavaElement)) |
| continue; |
| |
| switch (((IJavaElement)input).getElementType()) { |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| case IJavaElement.JAVA_PROJECT: |
| case IJavaElement.PACKAGE_FRAGMENT: |
| case IJavaElement.PACKAGE_DECLARATION: |
| hasValidElement= true; |
| continue; |
| default: |
| return false; |
| } |
| } |
| return hasValidElement; |
| } |
| |
| @Override |
| public void run(ITextSelection selection) { |
| IJavaElement input= SelectionConverter.getInput(fEditor); |
| if (!ActionUtil.isProcessable(getShell(), input)) |
| return; |
| |
| try { |
| IJavaElement[] elements= SelectionConverter.codeResolveOrInputForked(fEditor); |
| if (elements == null) |
| return; |
| List<IJavaElement> candidates= new ArrayList<>(elements.length); |
| for (int i= 0; i < elements.length; i++) { |
| IJavaElement[] resolvedElements= OpenTypeHierarchyUtil.getCandidates(elements[i]); |
| if (resolvedElements != null) |
| candidates.addAll(Arrays.asList(resolvedElements)); |
| } |
| run(candidates.toArray(new IJavaElement[candidates.size()])); |
| } catch (InvocationTargetException e) { |
| ExceptionHandler.handle(e, getShell(), getDialogTitle(), ActionMessages.SelectionConverter_codeResolve_failed); |
| } catch (InterruptedException e) { |
| // cancelled |
| } |
| } |
| |
| @Override |
| public void run(IStructuredSelection selection) { |
| List<IJavaElement> validElements= new ArrayList<>(); |
| Object[] selectedElements= selection.toArray(); |
| |
| for (int i= 0; i < selectedElements.length; i++) { |
| Object input= selectedElements[i]; |
| if (input instanceof LogicalPackage) { |
| IPackageFragment[] fragments= ((LogicalPackage)input).getFragments(); |
| if (fragments.length == 0) |
| continue; |
| validElements.addAll(Arrays.asList(fragments)); |
| } else if (input instanceof IPackageFragment) { |
| IPackageFragment fragment= (IPackageFragment)input; |
| IPackageFragmentRoot[] roots; |
| try { |
| roots= fragment.getJavaProject().getPackageFragmentRoots(); |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e); |
| continue; |
| } |
| String name= fragment.getElementName(); |
| for (int j= 0; j < roots.length; j++) { |
| IPackageFragment pack= roots[j].getPackageFragment(name); |
| if (pack.exists()) |
| validElements.add(pack); |
| } |
| } else { |
| if (!(input instanceof IJavaElement) || !ActionUtil.isProcessable(getShell(), (IJavaElement)input)) |
| continue; |
| IJavaElement element= (IJavaElement)input; |
| validElements.add(element); |
| } |
| } |
| if (validElements.size() == 0) { |
| IStatus status= createStatus(ActionMessages.OpenTypeHierarchyAction_messages_no_java_elements); |
| ErrorDialog.openError(getShell(), getDialogTitle(), ActionMessages.OpenTypeHierarchyAction_messages_title, status); |
| return; |
| } |
| List<IJavaElement> result= new ArrayList<>(); |
| IStatus status= compileCandidates(result, validElements); |
| if (status.isOK()) { |
| run(result.toArray(new IJavaElement[result.size()])); |
| } else { |
| ErrorDialog.openError(getShell(), getDialogTitle(), ActionMessages.OpenTypeHierarchyAction_messages_title, status); |
| } |
| } |
| |
| /* |
| * No Javadoc since the method isn't meant to be public but is |
| * since the beginning |
| */ |
| public void run(IJavaElement[] elements) { |
| if (elements.length == 0) { |
| getShell().getDisplay().beep(); |
| return; |
| } |
| OpenTypeHierarchyUtil.open(elements, getSite().getWorkbenchWindow()); |
| } |
| |
| private static String getDialogTitle() { |
| return ActionMessages.OpenTypeHierarchyAction_dialog_title; |
| } |
| |
| private static IStatus compileCandidates(List<IJavaElement> result, List<IJavaElement> elements) { |
| IStatus ok= Status.OK_STATUS; |
| boolean onlyContainers= true; |
| for (Iterator<IJavaElement> iter= elements.iterator(); iter.hasNext();) { |
| IJavaElement elem= iter.next(); |
| try { |
| switch (elem.getElementType()) { |
| case IJavaElement.INITIALIZER: |
| case IJavaElement.METHOD: |
| case IJavaElement.FIELD: |
| case IJavaElement.TYPE: |
| onlyContainers= false; |
| //$FALL-THROUGH$ |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| case IJavaElement.JAVA_PROJECT: |
| result.add(elem); |
| break; |
| case IJavaElement.PACKAGE_FRAGMENT: |
| if (((IPackageFragment)elem).containsJavaResources()) |
| result.add(elem); |
| break; |
| case IJavaElement.PACKAGE_DECLARATION: |
| result.add(elem.getAncestor(IJavaElement.PACKAGE_FRAGMENT)); |
| break; |
| case IJavaElement.IMPORT_DECLARATION: |
| IImportDeclaration decl= (IImportDeclaration)elem; |
| if (decl.isOnDemand()) |
| elem= JavaModelUtil.findTypeContainer(elem.getJavaProject(), Signature.getQualifier(elem.getElementName())); |
| else |
| elem= elem.getJavaProject().findType(elem.getElementName()); |
| if (elem != null) { |
| onlyContainers= false; |
| result.add(elem); |
| } |
| break; |
| case IJavaElement.CLASS_FILE: |
| if (elem instanceof IOrdinaryClassFile) { |
| onlyContainers= false; |
| result.add(((IOrdinaryClassFile) elem).getType()); |
| } |
| break; |
| case IJavaElement.COMPILATION_UNIT: |
| ICompilationUnit cu= (ICompilationUnit)elem; |
| IType[] types= cu.getTypes(); |
| if (types.length > 0) { |
| onlyContainers= false; |
| result.addAll(Arrays.asList(types)); |
| } |
| } |
| } catch (JavaModelException e) { |
| return e.getStatus(); |
| } |
| } |
| int size= result.size(); |
| if (size == 0 || (size > 1 && !onlyContainers)) |
| return createStatus(ActionMessages.OpenTypeHierarchyAction_messages_no_valid_java_element); |
| return ok; |
| } |
| |
| private static IStatus createStatus(String message) { |
| return new Status(IStatus.INFO, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, null); |
| } |
| } |