package net.sourceforge.c4jplugin.internal.ui.contracthierarchy; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ui.IWorkingCopyProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; /** * Base class for content providers for contract hierarchy viewers. * Implementors must override 'getContractsInHierarchy'. * Java delta processing is also performed by the content provider */ public abstract class ContractHierarchyContentProvider implements IStructuredContentProvider, IWorkingCopyProvider { protected static final Object[] NO_ELEMENTS= new Object[0]; protected ContractHierarchyLifeCycle fTypeHierarchy; protected IMember[] fMemberFilter; private ViewerFilter fWorkingSetFilter; private ConditionOverrideTester fMethodOverrideTester; private IContractHierarchyLifeCycleListener fTypeHierarchyLifeCycleListener; public ContractHierarchyContentProvider(ContractHierarchyLifeCycle lifecycle) { fTypeHierarchy= lifecycle; fMemberFilter= null; fWorkingSetFilter= null; fMethodOverrideTester= null; fTypeHierarchyLifeCycleListener= new IContractHierarchyLifeCycleListener() { public void contractHierarchyChanged(ContractHierarchyLifeCycle typeHierarchyProvider, IType[] changedTypes) { if (changedTypes == null) { fMethodOverrideTester= null; } } }; lifecycle.addChangedListener(fTypeHierarchyLifeCycleListener); } /** * Sets members to filter the hierarchy for. Set to <code>null</code> to disable member filtering. * When member filtering is enabled, the hierarchy contains only types that contain * an implementation of one of the filter members and the members themself. * The hierarchy can be empty as well. */ public final void setMemberFilter(IMember[] memberFilter) { fMemberFilter= memberFilter; } private boolean initializeConditionOverrideTester(IMethod filterCondition, IType typeToFindIn) { IType filterType= filterCondition.getDeclaringType(); IContractHierarchy hierarchy= fTypeHierarchy.getContractHierarchy(); boolean filterOverrides= hierarchy.isSupercontract(typeToFindIn, filterType); IType focusType= filterOverrides ? filterType : typeToFindIn; if (fMethodOverrideTester == null || !fMethodOverrideTester.getFocusType().equals(focusType)) { fMethodOverrideTester= new ConditionOverrideTester(focusType, hierarchy); } return filterOverrides; } protected boolean hasCompatibleCondition(IMethod filterMethod, IType typeToFindIn) throws JavaModelException { boolean filterMethodOverrides= initializeConditionOverrideTester(filterMethod, typeToFindIn); IMethod[] methods= typeToFindIn.getMethods(); for (int i= 0; i < methods.length; i++) { if (isCompatibleCondition(filterMethod, methods[i], filterMethodOverrides)) { return true; } } return false; } private boolean isCompatibleCondition(IMethod filterMethod, IMethod method, boolean filterOverrides) throws JavaModelException { // if (filterOverrides) { // return fMethodOverrideTester.isSubsignature(filterMethod, method); // } else { // return fMethodOverrideTester.isSubsignature(method, filterMethod); // } return filterMethod.getSignature().equals(method.getSignature()); } /** * The members to filter or <code>null</code> if member filtering is disabled. */ public IMember[] getMemberFilter() { return fMemberFilter; } /** * Sets a filter representing a working set or <code>null</code> if working sets are disabled. */ public void setWorkingSetFilter(ViewerFilter filter) { fWorkingSetFilter= filter; } protected final IContractHierarchy getHierarchy() { return fTypeHierarchy.getContractHierarchy(); } /* (non-Javadoc) * @see IReconciled#providesWorkingCopies() */ public boolean providesWorkingCopies() { return true; } /* * Called for the root element * @see IStructuredContentProvider#getElements */ abstract public Object[] getElements(Object parent); protected void addCompatibleMethods(IMethod filterMethod, IType typeToFindIn, List children) throws JavaModelException { boolean filterMethodOverrides= initializeConditionOverrideTester(filterMethod, typeToFindIn); IMethod[] methods= typeToFindIn.getMethods(); for (int i= 0; i < methods.length; i++) { IMethod curr= methods[i]; if (isCompatibleCondition(filterMethod, curr, filterMethodOverrides) && !children.contains(curr)) { children.add(curr); } } } /** * Hook to overwrite. Filter will be applied on the returned types */ protected abstract void getContractsInHierarchy(IType type, List<IType> res); private boolean isInScope(IType type) { if (fWorkingSetFilter != null && !fWorkingSetFilter.select(null, null, type)) { return false; } IJavaElement input= fTypeHierarchy.getInputElement(); int inputType= input.getElementType(); if (inputType == IJavaElement.TYPE) { return true; } IJavaElement parent= type.getAncestor(input.getElementType()); if (inputType == IJavaElement.PACKAGE_FRAGMENT) { if (parent == null || parent.getElementName().equals(input.getElementName())) { return true; } } else if (input.equals(parent)) { return true; } return false; } protected final boolean isInControl(IType type) throws JavaModelException { if (isInScope(type)) { if (fMemberFilter != null) { return hasMemberFilterChildren(type) || hasTypeChildren(type); } else { return true; } } return hasTypeChildren(type); } private boolean hasMemberFilterChildren(IType type) throws JavaModelException { for (int i= 0; i < fMemberFilter.length; i++) { IMember member= fMemberFilter[i]; if (type.equals(member.getDeclaringType())) { return true; } else if (member instanceof IMethod) { if (hasCompatibleCondition((IMethod) member, type)) { return true; } } } return false; } private boolean hasTypeChildren(IType type) throws JavaModelException { ArrayList<IType> types= new ArrayList<IType>(); getContractsInHierarchy(type, types); for (IType curr : types) { if (isInControl(curr)) { return true; } } return false; } /* * @see IContentProvider#inputChanged */ public void inputChanged(Viewer part, Object oldInput, Object newInput) { Assert.isTrue(part instanceof StructuredViewer && part instanceof IContractHierarchyViewer); } /* * @see IContentProvider#dispose */ public void dispose() { fTypeHierarchy.removeChangedListener(fTypeHierarchyLifeCycleListener); } protected final boolean isAnonymous(IType type) { return type.getElementName().length() == 0; } /* protected final boolean isAnonymousFromInterface(IType type) { return isAnonymous(type) && fTypeHierarchy.getHierarchy().getSuperInterfaces(type).length != 0; } */ protected final boolean isObject(IType type) { return "Object".equals(type.getElementName()) && type.getDeclaringType() == null && "java.lang".equals(type.getPackageFragment().getElementName()); //$NON-NLS-1$//$NON-NLS-2$ } }