Fixed bug 507294: [navigation] Ctrl+Click on interface should allow to
jump to the implementations similar as for interface methods

Change-Id: I22ec9a117d14febc7cd8046e7bea397aeb732e85
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditorMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditorMessages.properties
index 235b327..ebb98c5 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditorMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditorMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2014 IBM Corporation and others.
+# Copyright (c) 2000, 2016 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -139,7 +139,7 @@
 JavaElementHyperlink_hyperlinkText_qualified=Open ''{0}''
 
 JavaElementImplementationHyperlink_error_no_implementations_found_message=Problems finding implementations.
-JavaElementImplementationHyperlink_error_status_message=An error occurred while searching for implementations of method ''{0}''. See error log for details.
+JavaElementImplementationHyperlink_error_status_message=An error occurred while searching for implementations of ''{0}''. See error log for details.
 JavaElementImplementationHyperlink_hyperlinkText= Open Implementation
 JavaElementImplementationHyperlink_hyperlinkText_qualified=Open Implementation for ''{0}''
 JavaElementImplementationHyperlink_search_method_implementors=Searching for implementors of ''{0}''...
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkImplementationDetector.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkImplementationDetector.java
index 2c8ac99..4be3c1a 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkImplementationDetector.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkImplementationDetector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * Copyright (c) 2010, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,7 +16,8 @@
 import org.eclipse.jface.text.hyperlink.IHyperlink;
 
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
 
 import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
 
@@ -24,20 +25,21 @@
 
 
 /**
- * Java element implementation hyperlink detector for methods.
+ * Java element implementation hyperlink detector for types and methods.
  * 
  * @since 3.5
  */
 public class JavaElementHyperlinkImplementationDetector extends JavaElementHyperlinkDetector {
 
-	/*
-	 * @see org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetector#createHyperlink(org.eclipse.jface.text.IRegion, org.eclipse.jdt.ui.actions.SelectionDispatchAction, org.eclipse.jdt.core.IJavaElement, boolean, org.eclipse.ui.texteditor.ITextEditor)
-	 * @since 3.5
-	 */
 	@Override
 	protected void addHyperlinks(List<IHyperlink> hyperlinksCollector, IRegion wordRegion, SelectionDispatchAction openAction, IJavaElement element, boolean qualify, JavaEditor editor) {
-		if (element.getElementType() == IJavaElement.METHOD && SelectionConverter.canOperateOn(editor)) {
-			hyperlinksCollector.add(new JavaElementImplementationHyperlink(wordRegion, openAction, (IMethod)element, qualify, editor));
+		int elementType= element.getElementType();
+		try {
+			if ((elementType == IJavaElement.METHOD || (elementType == IJavaElement.TYPE && ((IType) element).isInterface())) && SelectionConverter.canOperateOn(editor)) {
+				hyperlinksCollector.add(new JavaElementImplementationHyperlink(wordRegion, openAction, element, qualify, editor));
+			}
+		} catch (JavaModelException e) {
+			// do nothing
 		}
 	}
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementImplementationHyperlink.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementImplementationHyperlink.java
index ba7404e..6c2c13b 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementImplementationHyperlink.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementImplementationHyperlink.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2011 IBM Corporation and others.
+ * Copyright (c) 2009, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -34,6 +34,7 @@
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.PlatformUI;
 
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IType;
@@ -78,7 +79,7 @@
 	
 	private final IRegion fRegion;
 	private final SelectionDispatchAction fOpenAction;
-	private final IMethod fMethod;
+	private final IJavaElement fElement;
 	private final boolean fQualify;
 
 	/**
@@ -87,66 +88,145 @@
 	private IEditorPart fEditor;
 
 	/**
-	 * Creates a new Java element implementation hyperlink for methods.
+	 * Creates a new Java element implementation hyperlink for types and methods.
 	 * 
 	 * @param region the region of the link
 	 * @param openAction the action to use to open the java elements
-	 * @param method the method to open
+	 * @param javaElement the element (type or method) to open
 	 * @param qualify <code>true</code> if the hyperlink text should show a qualified name for
-	 *            element.
+	 *            element
 	 * @param editor the editor
 	 */
-	public JavaElementImplementationHyperlink(IRegion region, SelectionDispatchAction openAction, IMethod method, boolean qualify, IEditorPart editor) {
+	public JavaElementImplementationHyperlink(IRegion region, SelectionDispatchAction openAction, IJavaElement javaElement, boolean qualify, IEditorPart editor) {
 		Assert.isNotNull(openAction);
 		Assert.isNotNull(region);
-		Assert.isNotNull(method);
+		Assert.isNotNull(javaElement);
+		Assert.isTrue(javaElement instanceof IType || javaElement instanceof IMethod);
 
 		fRegion= region;
 		fOpenAction= openAction;
-		fMethod= method;
+		fElement= javaElement;
 		fQualify= qualify;
 		fEditor= editor;
 	}
 
-	/*
-	 * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getHyperlinkRegion()
-	 */
 	@Override
 	public IRegion getHyperlinkRegion() {
 		return fRegion;
 	}
 
-	/*
-	 * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getHyperlinkText()
-	 */
 	@Override
 	public String getHyperlinkText() {
 		if (fQualify) {
-			String methodLabel= JavaElementLabels.getElementLabel(fMethod, JavaElementLabels.ALL_FULLY_QUALIFIED);
-			return Messages.format(JavaEditorMessages.JavaElementImplementationHyperlink_hyperlinkText_qualified, new Object[] { methodLabel });
+			String elementLabel= JavaElementLabels.getElementLabel(fElement, JavaElementLabels.ALL_FULLY_QUALIFIED);
+			return Messages.format(JavaEditorMessages.JavaElementImplementationHyperlink_hyperlinkText_qualified, new Object[] { elementLabel });
 		} else {
 			return JavaEditorMessages.JavaElementImplementationHyperlink_hyperlinkText;
 		}
 	}
 
-	/*
-	 * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getTypeLabel()
-	 */
 	@Override
 	public String getTypeLabel() {
 		return null;
 	}
 
 	/**
-	 * Opens the given implementation hyperlink for methods.
+	 * Opens the given implementation hyperlink for types and methods.
 	 * <p>
-	 * If there's only one implementor that hyperlink is opened in the editor, otherwise the
-	 * Quick Hierarchy is opened.
+	 * If there's only one implementor that hyperlink is opened in the editor, otherwise the Quick
+	 * Hierarchy is opened.
 	 * </p>
 	 */
 	@Override
 	public void open() {
-		openImplementations(fEditor, fRegion, fMethod, fOpenAction);
+		if (fElement instanceof IMethod) {
+			openImplementations(fEditor, fRegion, (IMethod) fElement, fOpenAction);
+		} else if (fElement instanceof IType) {
+			openImplementations(fEditor, fRegion, (IType) fElement, fOpenAction);
+		}
+	}
+
+	/**
+	 * Finds the implementations for the type.
+	 * <p>
+	 * If there's only one implementor that type is opened in the editor, otherwise the Quick
+	 * Hierarchy is opened.
+	 * </p>
+	 * 
+	 * @param editor the editor
+	 * @param region the region of the selection
+	 * @param type the type
+	 * @param openAction the action to use to open the types
+	 * @since 3.13
+	 */
+	public static void openImplementations(IEditorPart editor, IRegion region, final IType type, SelectionDispatchAction openAction) {
+		final String dummyString= new String();
+		final ArrayList<IType> links= new ArrayList<>();
+		IRunnableWithProgress runnable= new IRunnableWithProgress() {
+
+			@Override
+			public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+				if (monitor == null) {
+					monitor= new NullProgressMonitor();
+				}
+				try {
+					String typeLabel= JavaElementLabels.getElementLabel(type, JavaElementLabels.DEFAULT_QUALIFIED);
+					monitor.beginTask(Messages.format(JavaEditorMessages.JavaElementImplementationHyperlink_search_method_implementors, typeLabel), 10);
+					SearchRequestor requestor= new SearchRequestor() {
+						@Override
+						public void acceptSearchMatch(SearchMatch match) throws CoreException {
+							if (match.getAccuracy() == SearchMatch.A_ACCURATE) {
+								Object element= match.getElement();
+								if (element instanceof IType) {
+									links.add((IType) element);
+									if (links.size() > 1) {
+										throw new OperationCanceledException(dummyString);
+									}
+								}
+							}
+						}
+					};
+
+					IJavaSearchScope hierarchyScope= SearchEngine.createHierarchyScope(type);
+					SearchPattern pattern= SearchPattern.createPattern(type, IJavaSearchConstants.IMPLEMENTORS);
+					Assert.isNotNull(pattern);
+					SearchParticipant[] participants= new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
+					SearchEngine engine= new SearchEngine();
+					engine.search(pattern, participants, hierarchyScope, requestor, new SubProgressMonitor(monitor, 7));
+					if (monitor.isCanceled()) {
+						throw new OperationCanceledException();
+					}
+				} catch (CoreException e) {
+					throw new InvocationTargetException(e);
+				} finally {
+					monitor.done();
+				}
+			}
+		};
+
+		try {
+			IRunnableContext context= editor.getSite().getWorkbenchWindow();
+			context.run(true, true, runnable);
+		} catch (InvocationTargetException e) {
+			IStatus status= new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK,
+					Messages.format(JavaEditorMessages.JavaElementImplementationHyperlink_error_status_message, type.getElementName()), e.getCause());
+			JavaPlugin.log(status);
+			ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+					JavaEditorMessages.JavaElementImplementationHyperlink_hyperlinkText,
+					JavaEditorMessages.JavaElementImplementationHyperlink_error_no_implementations_found_message, status);
+		} catch (InterruptedException e) {
+			if (e.getMessage() != dummyString) {
+				return;
+			}
+		}
+
+		if (links.isEmpty()) {
+			openAction.run(new StructuredSelection(type));
+		} else if (links.size() == 1) {
+			openAction.run(new StructuredSelection(links.get(0)));
+		} else {
+			openQuickHierarchy(editor);
+		}
 	}
 
 	/**