1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package org.eclipse.jdt.internal.ui.javaeditor;
14 import java.util.HashMap;
15 import java.util.Iterator;
17 import java.util.Map.Entry;
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.NullProgressMonitor;
24 import org.eclipse.jface.dialogs.MessageDialog;
26 import org.eclipse.jface.text.ISynchronizable;
27 import org.eclipse.jface.text.Position;
28 import org.eclipse.jface.text.source.Annotation;
29 import org.eclipse.jface.text.source.IAnnotationModel;
30 import org.eclipse.jface.text.source.IAnnotationModelExtension;
32 import org.eclipse.jdt.core.IJavaElement;
33 import org.eclipse.jdt.core.ITypeRoot;
34 import org.eclipse.jdt.core.dom.ASTNode;
35 import org.eclipse.jdt.core.dom.ASTVisitor;
36 import org.eclipse.jdt.core.dom.CompilationUnit;
37 import org.eclipse.jdt.core.dom.IMethodBinding;
38 import org.eclipse.jdt.core.dom.ITypeBinding;
39 import org.eclipse.jdt.core.dom.MethodDeclaration;
40 import org.eclipse.jdt.core.dom.SimpleName;
42 import org.eclipse.jdt.internal.corext.dom.Bindings;
43 import org.eclipse.jdt.internal.corext.util.JdtFlags;
44 import org.eclipse.jdt.internal.corext.util.Messages;
46 import org.eclipse.jdt.ui.JavaUI;
47 import org.eclipse.jdt.ui.SharedASTProvider;
49 import org.eclipse.jdt.internal.ui.JavaPlugin;
50 import org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener;
51 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
52 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
55 * Manages the override and overwrite indicators for
56 * the given Java element and annotation model.
60 class OverrideIndicatorManager implements IJavaReconcilingListener {
63 * Overwrite and override indicator annotation.
67 class OverrideIndicator extends Annotation {
69 private boolean fIsOverwriteIndicator;
70 private String fAstNodeKey;
73 * Creates a new override annotation.
75 * @param isOverwriteIndicator <code>true</code> if this annotation is
76 * an overwrite indicator, <code>false</code> otherwise
77 * @param text the text associated with this annotation
78 * @param key the method binding key
81 OverrideIndicator(boolean isOverwriteIndicator, String text, String key) {
82 super(ANNOTATION_TYPE, false, text);
83 fIsOverwriteIndicator= isOverwriteIndicator;
88 * Tells whether this is an overwrite or an override indicator.
90 * @return <code>true</code> if this is an overwrite indicator
92 public boolean isOverwriteIndicator() {
93 return fIsOverwriteIndicator;
97 * Opens and reveals the defining method.
100 CompilationUnit ast= SharedASTProvider.getAST(fJavaElement, SharedASTProvider.WAIT_ACTIVE_ONLY, null);
102 ASTNode node= ast.findDeclaringNode(fAstNodeKey);
103 if (node instanceof MethodDeclaration) {
105 IMethodBinding methodBinding= ((MethodDeclaration)node).resolveBinding();
106 IMethodBinding definingMethodBinding= Bindings.findOverriddenMethod(methodBinding, true);
107 if (definingMethodBinding != null) {
108 IJavaElement definingMethod= definingMethodBinding.getJavaElement();
109 if (definingMethod != null) {
110 JavaUI.openInEditor(definingMethod, true, true);
114 } catch (CoreException e) {
115 ExceptionHandler.handle(e, JavaEditorMessages.OverrideIndicatorManager_open_error_title, JavaEditorMessages.OverrideIndicatorManager_open_error_messageHasLogEntry);
120 String title= JavaEditorMessages.OverrideIndicatorManager_open_error_title;
121 String message= JavaEditorMessages.OverrideIndicatorManager_open_error_message;
122 MessageDialog.openError(JavaPlugin.getActiveWorkbenchShell(), title, message);
126 static final String ANNOTATION_TYPE= "org.eclipse.jdt.ui.overrideIndicator"; //$NON-NLS-1$
128 private IAnnotationModel fAnnotationModel;
129 private Object fAnnotationModelLockObject;
130 private Annotation[] fOverrideAnnotations;
131 private ITypeRoot fJavaElement;
134 public OverrideIndicatorManager(IAnnotationModel annotationModel, ITypeRoot javaElement, CompilationUnit ast) {
135 Assert.isNotNull(annotationModel);
136 Assert.isNotNull(javaElement);
138 fJavaElement= javaElement;
139 fAnnotationModel=annotationModel;
140 fAnnotationModelLockObject= getLockObject(fAnnotationModel);
142 updateAnnotations(ast, new NullProgressMonitor());
146 * Returns the lock object for the given annotation model.
148 * @param annotationModel the annotation model
149 * @return the annotation model's lock object
152 private Object getLockObject(IAnnotationModel annotationModel) {
153 if (annotationModel instanceof ISynchronizable) {
154 Object lock= ((ISynchronizable)annotationModel).getLockObject();
158 return annotationModel;
162 * Updates the override and implements annotations based
165 * @param ast the compilation unit AST
166 * @param progressMonitor the progress monitor
169 protected void updateAnnotations(CompilationUnit ast, IProgressMonitor progressMonitor) {
171 if (ast == null || progressMonitor.isCanceled())
174 final Map<Annotation, Position> annotationMap= new HashMap<Annotation, Position>(50);
176 ast.accept(new ASTVisitor(false) {
178 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
181 public boolean visit(MethodDeclaration node) {
182 IMethodBinding binding= node.resolveBinding();
183 if (binding != null) {
184 IMethodBinding definingMethod= Bindings.findOverriddenMethod(binding, true);
185 if (definingMethod != null) {
187 ITypeBinding definingType= definingMethod.getDeclaringClass();
188 String qualifiedMethodName= definingType.getQualifiedName() + "." + binding.getName(); //$NON-NLS-1$
190 boolean isImplements= JdtFlags.isAbstract(definingMethod);
193 text= Messages.format(JavaEditorMessages.OverrideIndicatorManager_implements, BasicElementLabels.getJavaElementName(qualifiedMethodName));
195 text= Messages.format(JavaEditorMessages.OverrideIndicatorManager_overrides, BasicElementLabels.getJavaElementName(qualifiedMethodName));
197 SimpleName name= node.getName();
198 Position position= new Position(name.getStartPosition(), name.getLength());
201 new OverrideIndicator(isImplements, text, binding.getKey()),
210 if (progressMonitor.isCanceled())
213 synchronized (fAnnotationModelLockObject) {
214 if (fAnnotationModel instanceof IAnnotationModelExtension) {
215 ((IAnnotationModelExtension)fAnnotationModel).replaceAnnotations(fOverrideAnnotations, annotationMap);
218 Iterator<Entry<Annotation, Position>> iter= annotationMap.entrySet().iterator();
219 while (iter.hasNext()) {
220 Entry<Annotation, Position> mapEntry= iter.next();
221 fAnnotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue());
224 fOverrideAnnotations= annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
229 * Removes all override indicators from this manager's annotation model.
231 void removeAnnotations() {
232 if (fOverrideAnnotations == null)
235 synchronized (fAnnotationModelLockObject) {
236 if (fAnnotationModel instanceof IAnnotationModelExtension) {
237 ((IAnnotationModelExtension)fAnnotationModel).replaceAnnotations(fOverrideAnnotations, null);
239 for (int i= 0, length= fOverrideAnnotations.length; i < length; i++)
240 fAnnotationModel.removeAnnotation(fOverrideAnnotations[i]);
242 fOverrideAnnotations= null;
247 * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled()
249 public void aboutToBeReconciled() {
253 * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit, boolean, IProgressMonitor)
255 public void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor) {
256 updateAnnotations(ast, progressMonitor);