/******************************************************************************* * Copyright (c) 2005, 2008 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.ui.editor; /******************************************************************************* * Copyright (c) 2000, 2008 Zend, 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Zend, IBM Corporation - initial API and implementation *******************************************************************************/ import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.*; import org.eclipse.dltk.ast.Modifiers; import org.eclipse.dltk.core.*; import org.eclipse.dltk.internal.ui.editor.EditorUtility; 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.php.core.ast.nodes.*; import org.eclipse.php.core.ast.visitor.AbstractVisitor; import org.eclipse.php.internal.ui.Logger; import org.eclipse.php.internal.ui.PHPUIMessages; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.util.ExceptionHandler; import org.eclipse.php.internal.ui.util.Messages; import org.eclipse.php.ui.editor.SharedASTProvider; import org.eclipse.ui.IEditorPart; /** * Manages the override and overwrite indicators for the given PHP element and * annotation model. * * @since 3.0 */ class OverrideIndicatorManager implements IPHPScriptReconcilingListener { /** * Overwrite and override indicator annotation. * * @since 3.0 */ class OverrideIndicator extends Annotation { private boolean fIsOverwriteIndicator; private String fAstNodeKey; /** * Creates a new override annotation. * * @param isOverwriteIndicator * <code>true</code> if this annotation is an overwrite * indicator, <code>false</code> otherwise * @param text * the text associated with this annotation * @param key * the method binding key * @since 3.0 */ OverrideIndicator(boolean isOverwriteIndicator, String text, String key) { super(ANNOTATION_TYPE, false, text); fIsOverwriteIndicator = isOverwriteIndicator; fAstNodeKey = key; } /** * Tells whether this is an overwrite or an override indicator. * * @return <code>true</code> if this is an overwrite indicator */ public boolean isOverwriteIndicator() { return fIsOverwriteIndicator; } /** * Opens and reveals the defining method. */ public void open() { try { IModelElement modelElement = DLTKCore.create(fAstNodeKey); if (modelElement instanceof IMethod) { IMethod method = (IMethod) modelElement; int offset = method.getNameRange().getOffset(); int length = method.getNameRange().getLength(); IEditorPart editor = EditorUtility.openInEditor(method, true); EditorUtility.revealInEditor(editor, offset, length); } else { String title = PHPUIMessages.OverrideIndicatorManager_open_error_title; String message = PHPUIMessages.OverrideIndicatorManager_open_error_message; MessageDialog.openError(PHPUiPlugin.getActiveWorkbenchShell(), title, message); } } catch (Exception e) { ExceptionHandler.handle( new CoreException(new Status(IStatus.ERROR, PHPUiPlugin.ID, 0, "Exception occurred", e)), //$NON-NLS-1$ PHPUIMessages.OverrideIndicatorManager_open_error_title, PHPUIMessages.OverrideIndicatorManager_open_error_messageHasLogEntry); } } } static final String ANNOTATION_TYPE = "org.eclipse.php.ui.overrideIndicator"; //$NON-NLS-1$ private IAnnotationModel fAnnotationModel; private Object fAnnotationModelLockObject; private Annotation[] fOverrideAnnotations; public OverrideIndicatorManager(IAnnotationModel annotationModel) { Assert.isNotNull(annotationModel); fAnnotationModel = annotationModel; fAnnotationModelLockObject = getLockObject(fAnnotationModel); } /** * Returns the lock object for the given annotation model. * * @param annotationModel * the annotation model * @return the annotation model's lock object * @since 3.0 */ private Object getLockObject(IAnnotationModel annotationModel) { if (annotationModel instanceof ISynchronizable) { Object lock = ((ISynchronizable) annotationModel).getLockObject(); if (lock != null) return lock; } return annotationModel; } /** * Updates the override and implements annotations based on the given AST. * * @param ast * the compilation unit AST * @param progressMonitor * the progress monitor * @since 3.0 */ protected void updateAnnotations(Program ast, IProgressMonitor progressMonitor) { if (ast == null || progressMonitor.isCanceled()) return; final Map<OverrideIndicator, Position> annotationMap = new HashMap<>(50); // don't provide override indicators to external / read only files. if (ast.getSourceModule().isReadOnly()) { return; } if (!ast.getSourceModule().getScriptProject().isOnBuildpath(ast.getSourceModule())) { return; } ast.accept(new AbstractVisitor() { /* * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core * .dom.MethodDeclaration) */ @Override public boolean visit(MethodDeclaration node) { IMethodBinding binding = node.resolveMethodBinding(); if (binding != null) { IMethodBinding definingMethod = Bindings.findOverriddenMethod(binding, true); if (definingMethod != null) { ITypeBinding definingType = definingMethod.getDeclaringClass(); String qualifiedMethodName = definingType.getName() + "." + binding.getName(); //$NON-NLS-1$ [TODO // - // Use // definingType.getQualifiedName()] boolean isImplements = (Modifiers.AccAbstract & definingMethod.getModifiers()) != 0; String text; if (isImplements) text = Messages.format(PHPUIMessages.OverrideIndicatorManager_implements, qualifiedMethodName);// $NON-NLS-1$ else text = Messages.format(PHPUIMessages.OverrideIndicatorManager_overrides, qualifiedMethodName);// $NON-NLS-1$ Identifier name = node.getFunction().getFunctionName(); Position position = new Position(name.getStart(), name.getLength()); OverrideIndicator indicator = new OverrideIndicator(isImplements, text, definingMethod.getKey()); annotationMap.put(indicator, 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 = (Annotation[]) annotationMap.keySet() .toArray(new Annotation[annotationMap.keySet().size()]); } } /** * Removes all override indicators from this manager's annotation model. */ 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; } } /* * (non-Javadoc) * * @seeorg.eclipse.dltk.internal.ui.text.IScriptReconcilingListener# * aboutToBeReconciled() */ @Override public void aboutToBeReconciled() { } /* * (non-Javadoc) * * @see * org.eclipse.dltk.internal.ui.text.IScriptReconcilingListener#reconciled * (org.eclipse.dltk.core.ISourceModule, boolean, * org.eclipse.core.runtime.IProgressMonitor) */ public void reconciled(ISourceModule sourceModule, boolean forced, IProgressMonitor progressMonitor) { Program ast; try { ast = SharedASTProvider.getAST(sourceModule, SharedASTProvider.WAIT_YES, null); if (ast != null) { updateAnnotations(ast, progressMonitor); } } catch (ModelException e) { Logger.logException(e); } catch (IOException e) { Logger.logException(e); } } /* * (non-Javadoc) * * @see org.eclipse.php.internal.ui.editor.IPhpScriptReconcilingListener# * reconciled (org.eclipse.php.internal.core.ast.nodes.Program, boolean, * org.eclipse.core.runtime.IProgressMonitor) */ @Override public void reconciled(Program ast, boolean forced, IProgressMonitor progressMonitor) { if (ast != null) { updateAnnotations(ast, progressMonitor); } } }