blob: 9e44544ece54789995283fa0e213c4aa40b322db [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 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
* $Id$
*
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - Initial API and implementation
*******************************************************************************/
package org.eclipse.objectteams.otdt.internal.ui.javaeditor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.RoleTypeDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaSelectAnnotationRulerAction;
import org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.osgi.util.NLS;
/**
* Manages the override indicators for the given Java element and annotation model.
*
* Copied from {@link org.eclipse.jdt.internal.ui.javaeditor.OverrideIndicatorManager} and slightly adjusted.
*
* Note that inaccessible features preclude that this class were directly integrated into
* {@link JavaSelectAnnotationRulerAction}, which is why the jdt.ui.adaptor has to
* help (see {@link org.eclipse.objectteams.otdt.internal.ui.javaeditor.AnnotationAdaptor}).
*
* @author stephan
* @since 1.2.8
*/
@SuppressWarnings("restriction") // uses internal classes below org.eclipse.jdt.internal.ui
public class RoleOverrideIndicatorManager implements IJavaReconcilingListener {
/**
* Role class override indicator annotation.
*/
public class OverrideIndicator extends Annotation {
private String fAstNodeKey;
/**
* Creates a new override annotation.
*
* @param text the text associated with this annotation
* @param key the type binding key
*/
OverrideIndicator(String text, String key) {
super(ANNOTATION_TYPE, false, text);
fAstNodeKey= key;
}
/**
* Opens and reveals the defining role (closest tsuper).
*/
public void open() {
CompilationUnit ast= SharedASTProvider.getAST(fJavaElement, SharedASTProvider.WAIT_ACTIVE_ONLY, null);
if (ast != null) {
ASTNode node= ast.findDeclaringNode(fAstNodeKey);
//{ObjectTeams: specific search strategy for a role's tsupers:
if (node instanceof TypeDeclaration) {
try {
ITypeBinding typeBinding = ((TypeDeclaration)node).resolveBinding();
ITypeBinding[] tsuperRoles = typeBinding.getSuperRoles();
if (tsuperRoles != null && tsuperRoles.length > 0) {
IJavaElement definingRole = tsuperRoles[0].getJavaElement();
if (definingRole!= null) {
// SH}
JavaUI.openInEditor(definingRole, true, true);
return;
}
}
} catch (CoreException e) {
ExceptionHandler.handle(e, OTJavaEditorMessages.RoleOverrideIndicator_open_error_title, OTJavaEditorMessages.RoleOverrideIndicator_open_error_messageHasLogEntry);
return;
}
}
}
String title= OTJavaEditorMessages.RoleOverrideIndicator_open_error_title;
String message= OTJavaEditorMessages.RoleOverrideIndicator_open_error_message;
MessageDialog.openError(JavaPlugin.getActiveWorkbenchShell(), title, message);
}
}
static final String ANNOTATION_TYPE= "org.eclipse.objectteams.otdt.ui.roleOverrideIndicator"; //$NON-NLS-1$
private IAnnotationModel fAnnotationModel;
private Object fAnnotationModelLockObject;
private Annotation[] fOverrideAnnotations;
private ITypeRoot fJavaElement;
public RoleOverrideIndicatorManager(IAnnotationModel annotationModel, ITypeRoot javaElement, CompilationUnit ast) {
Assert.isNotNull(annotationModel);
Assert.isNotNull(javaElement);
fJavaElement= javaElement;
fAnnotationModel=annotationModel;
fAnnotationModelLockObject= getLockObject(fAnnotationModel);
updateAnnotations(ast, new NullProgressMonitor());
}
/**
* Returns the lock object for the given annotation model.
*
* @param annotationModel the annotation model
* @return the annotation model's lock object
*/
private Object getLockObject(IAnnotationModel annotationModel) {
if (annotationModel instanceof ISynchronizable) {
Object lock= ((ISynchronizable)annotationModel).getLockObject();
if (lock != null)
return lock;
}
return annotationModel;
}
/**
* Updates the override annotations based on the given AST.
*
* @param ast the compilation unit AST
* @param progressMonitor the progress monitor
*/
protected void updateAnnotations(CompilationUnit ast, IProgressMonitor progressMonitor) {
if (ast == null || progressMonitor.isCanceled())
return;
final Map<OverrideIndicator, Position> annotationMap= new HashMap<OverrideIndicator, Position>(10);
ast.accept(new ASTVisitor(false) {
/*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.RoleTypeDeclaration)
*/
public boolean visit(RoleTypeDeclaration node) {
ITypeBinding binding= node.resolveBinding();
if (binding != null) {
//{ObjectTeams: different search for super implementation:
ITypeBinding[] definingRoles= binding.getSuperRoles();
if (definingRoles != null && definingRoles.length > 0) {
ITypeBinding definingRole = definingRoles[0];
// SH}
ITypeBinding definingType= definingRole.getDeclaringClass();
String qualifiedRoleName= definingType.getQualifiedName() + "." + binding.getName(); //$NON-NLS-1$
String text= NLS.bind(OTJavaEditorMessages.RoleOverrideIndicator_overrides, new Object[] {BasicElementLabels.getJavaElementName(qualifiedRoleName)});
SimpleName name= node.getName();
Position position= new Position(name.getStartPosition(), name.getLength());
annotationMap.put(new OverrideIndicator(text, binding.getKey()), position);
}
}
return true;
}
});
if (progressMonitor.isCanceled())
return;
synchronized (fAnnotationModelLockObject) {
if (fAnnotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension)fAnnotationModel).replaceAnnotations(fOverrideAnnotations, annotationMap);
} else {
removeAnnotations();
Iterator<Map.Entry<OverrideIndicator, Position>> iter= annotationMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<OverrideIndicator, Position> mapEntry= iter.next();
fAnnotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue());
}
}
fOverrideAnnotations= annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
}
}
/**
* Removes all override indicators from this manager's annotation model.
*/
//FIXME: made public to workaround IllegalAccessError with split package access
// from bundle org.eclipse.objectteams.otdt.jdt.ui(x-friends not working)
public void removeAnnotations() {
if (fOverrideAnnotations == null)
return;
synchronized (fAnnotationModelLockObject) {
if (fAnnotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension)fAnnotationModel).replaceAnnotations(fOverrideAnnotations, null);
} else {
for (int i= 0, length= fOverrideAnnotations.length; i < length; i++)
fAnnotationModel.removeAnnotation(fOverrideAnnotations[i]);
}
fOverrideAnnotations= null;
}
}
/*
* @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled()
*/
public void aboutToBeReconciled() {
}
/*
* @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit, boolean, IProgressMonitor)
*/
public void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor) {
updateAnnotations(ast, progressMonitor);
}
}