blob: 210cd15f766e8584c181b4b3d6cb924d984c5fb5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.jdt.internal.ui.typehierarchy;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
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.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.ui.IWorkingCopyProvider;
/**
* Base class for content providers for type hierarchy viewers.
* Implementors must override 'getTypesInHierarchy'.
* Java delta processing is also performed by the content provider
*/
public abstract class TypeHierarchyContentProvider implements ITreeContentProvider, IWorkingCopyProvider {
protected static final Object[] NO_ELEMENTS= new Object[0];
protected TypeHierarchyLifeCycle fTypeHierarchy;
protected IMember[] fMemberFilter;
protected TreeViewer fViewer;
private ViewerFilter fWorkingSetFilter;
public TypeHierarchyContentProvider(TypeHierarchyLifeCycle lifecycle) {
fTypeHierarchy= lifecycle;
fMemberFilter= null;
fWorkingSetFilter= null;
}
/**
* 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;
}
/**
* 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 ITypeHierarchy getHierarchy() {
return fTypeHierarchy.getHierarchy();
}
/* (non-Javadoc)
* @see IReconciled#providesWorkingCopies()
*/
public boolean providesWorkingCopies() {
return true;
}
/*
* Called for the root element
* @see IStructuredContentProvider#getElements
*/
public Object[] getElements(Object parent) {
ArrayList types= new ArrayList();
getRootTypes(types);
for (int i= types.size() - 1; i >= 0; i--) {
IType curr= (IType) types.get(i);
try {
if (!isInTree(curr)) {
types.remove(i);
}
} catch (JavaModelException e) {
// ignore
}
}
return types.toArray();
}
protected void getRootTypes(List res) {
ITypeHierarchy hierarchy= getHierarchy();
if (hierarchy != null) {
IType input= hierarchy.getType();
if (input != null) {
res.add(input);
}
// opened on a region: dont show
}
}
/**
* Hook to overwrite. Filter will be applied on the returned types
*/
protected abstract void getTypesInHierarchy(IType type, List res);
/**
* Hook to overwrite. Return null if parent is ambiguous.
*/
protected abstract IType getParentType(IType type);
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;
}
/*
* Called for the tree children.
* @see ITreeContentProvider#getChildren
*/
public Object[] getChildren(Object element) {
if (element instanceof IType) {
try {
IType type= (IType)element;
List children= new ArrayList();
if (fMemberFilter != null) {
addFilteredMemberChildren(type, children);
}
addTypeChildren(type, children);
return children.toArray();
} catch (JavaModelException e) {
// ignore
}
}
return NO_ELEMENTS;
}
/*
* @see ITreeContentProvider#hasChildren
*/
public boolean hasChildren(Object element) {
if (element instanceof IType) {
try {
IType type= (IType) element;
return hasTypeChildren(type) || (fMemberFilter != null && hasMemberFilterChildren(type));
} catch (JavaModelException e) {
return false;
}
}
return false;
}
private void addFilteredMemberChildren(IType parent, List children) throws JavaModelException {
for (int i= 0; i < fMemberFilter.length; i++) {
IMember member= fMemberFilter[i];
if (parent.equals(member.getDeclaringType())) {
if (!children.contains(member)) {
children.add(member);
}
} else if (member instanceof IMethod) {
IMethod curr= (IMethod)member;
IMethod meth= JavaModelUtil.findMethod2(curr, parent.getMethods());
if (meth != null && !children.contains(meth)) {
children.add(meth);
}
}
}
}
private void addTypeChildren(IType type, List children) throws JavaModelException {
ArrayList types= new ArrayList();
getTypesInHierarchy(type, types);
int len= types.size();
for (int i= 0; i < len; i++) {
IType curr= (IType) types.get(i);
if (isInTree(curr)) {
children.add(curr);
}
}
}
protected final boolean isInTree(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) {
IMethod curr= (IMethod)member;
IMethod meth= JavaModelUtil.findMethod2(curr, type.getMethods());
if (meth != null) {
return true;
}
}
}
return false;
}
private boolean hasTypeChildren(IType type) throws JavaModelException {
ArrayList types= new ArrayList();
getTypesInHierarchy(type, types);
int len= types.size();
for (int i= 0; i < len; i++) {
IType curr= (IType) types.get(i);
if (isInTree(curr)) {
return true;
}
}
return false;
}
/*
* @see IContentProvider#inputChanged
*/
public void inputChanged(Viewer part, Object oldInput, Object newInput) {
Assert.isTrue(part instanceof TreeViewer);
fViewer= (TreeViewer)part;
}
/*
* @see IContentProvider#dispose
*/
public void dispose() {
}
/*
* @see ITreeContentProvider#getParent
*/
public Object getParent(Object element) {
if (element instanceof IMember) {
IMember member= (IMember) element;
if (member.getElementType() == IJavaElement.TYPE) {
return getParentType((IType)member);
}
return member.getDeclaringType();
}
return null;
}
protected final boolean isAnonymous(IType type) {
return type.getElementName().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$
}
}