blob: 42bbf01a54bbe2f3451df4233c28f4f7721eaef7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2002 International Business Machines Corp. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.jdt.internal.ui.packageview;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.IElementChangedListener;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.preferences.AppearancePreferencePage;
/**
* Content provider which provides package fragments for hierarchical
* Package Explorer layout.
*
* @since 2.1
*/
public class PackageFragmentProvider implements IPropertyChangeListener, ITreeContentProvider, IElementChangedListener{
private TreeViewer fViewer;
private boolean fFoldPackages;
public PackageFragmentProvider() {
fFoldPackages= AppearancePreferencePage.arePackagesFoldedInHierarchicalLayout();
JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
}
/*
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(Object)
*/
public Object[] getChildren(Object parentElement) {
try {
if (parentElement instanceof IJavaElement) {
IJavaElement iJavaElement= (IJavaElement) parentElement;
int type= iJavaElement.getElementType();
switch (type) {
case IJavaElement.JAVA_PROJECT: {
IJavaProject project= (IJavaProject)iJavaElement;
IProject proj= project.getProject();
List children= new ArrayList();
IPackageFragmentRoot defaultroot= project.getPackageFragmentRoot(proj);
if(defaultroot.exists()){
IJavaElement[] els= defaultroot.getChildren();
children= getTopLevelChildrenByElementName(els);
}
return filter(children.toArray());
}
case IJavaElement.PACKAGE_FRAGMENT_ROOT :
{
IPackageFragmentRoot root = (IPackageFragmentRoot) parentElement;
if (root.exists()) {
IResource resource = root.getUnderlyingResource();
if (root.isArchive()) {
IJavaElement[] els = root.getChildren();
return filter(getTopLevelChildrenByElementName(els).toArray());
} else if (resource instanceof IFolder) {
IFolder folder = (IFolder) resource;
IResource[] reses = folder.members();
List children = getFolders(reses);
IPackageFragment defaultPackage= root.getPackageFragment(""); //$NON-NLS-1$
if(defaultPackage.exists())
children.add(defaultPackage);
return filter(children.toArray());
}
}
break;
}
case IJavaElement.PACKAGE_FRAGMENT :
{
IPackageFragment packageFragment = (IPackageFragment) parentElement;
if (!packageFragment.isDefaultPackage()) {
IResource resource = packageFragment.getUnderlyingResource();
if (resource != null && resource instanceof IFolder) {
IFolder folder = (IFolder) resource;
IResource[] reses = folder.members();
Object[] children = getFolders(reses).toArray();
return filter(children);
//if the resource is null, maybe member of an archive
} else {
IJavaElement parent = packageFragment.getParent();
if (parent instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root = (IPackageFragmentRoot) parent;
Object[] children = findNextLevelChildrenByElementName(root, packageFragment);
return filter(children);
}
}
}
break;
}
default :
// do nothing
}
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
} catch (CoreException e) {
JavaPlugin.log(e);
}
return new Object[0];
}
private Object[] filter(Object[] children) {
if (fFoldPackages) {
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof IPackageFragment) {
IPackageFragment fragment = (IPackageFragment) children[i];
if(!fragment.isDefaultPackage())
children[i] = getBottomPackage(fragment);
}
}
}
return children;
}
private Object getBottomPackage(IPackageFragment iPackageFragment) {
try {
if(isEmpty(iPackageFragment))
return findChildrenToBeCompounded(iPackageFragment);
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return iPackageFragment;
}
private IPackageFragment findChildrenToBeCompounded(IPackageFragment fragment) throws JavaModelException {
Object[] children = getChildren(fragment);
if ((children.length == 1) && (children[0] instanceof IPackageFragment)) {
if (isEmpty((IPackageFragment) children[0]))
return findChildrenToBeCompounded((IPackageFragment) children[0]);
else return (IPackageFragment)children[0];
}
return fragment;
}
private boolean isEmpty(IPackageFragment fragment) throws JavaModelException {
return (!fragment.containsJavaResources()) && (fragment.getNonJavaResources().length==0);
}
private Object[] findNextLevelChildrenByElementName(IPackageFragmentRoot parent, IPackageFragment fragment) {
List list= new ArrayList();
try {
IJavaElement[] children= parent.getChildren();
String fragmentname= fragment.getElementName();
for (int i= 0; i < children.length; i++) {
IJavaElement element= children[i];
if (element instanceof IPackageFragment) {
IPackageFragment frag= (IPackageFragment) element;
String name= element.getElementName();
if (!"".equals(fragmentname) && name.startsWith(fragmentname) && !name.equals(fragmentname)) { //$NON-NLS-1$
String tail= name.substring(fragmentname.length() + 1);
if (!"".equals(tail) && (tail.indexOf(".") == -1)) {//$NON-NLS-1$ //$NON-NLS-2$
list.add(frag);
}
}
}
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return list.toArray();
}
private List getTopLevelChildrenByElementName(IJavaElement[] elements){
List topLevelElements= new ArrayList();
for (int i= 0; i < elements.length; i++) {
IJavaElement iJavaElement= elements[i];
//if the name of the PackageFragment is the top level package it will contain no "." separators
if((iJavaElement.getElementName().indexOf(".")==-1) && (iJavaElement instanceof IPackageFragment)){ //$NON-NLS-1$
topLevelElements.add(iJavaElement);
}
}
return topLevelElements;
}
private List getFolders(IResource[] resources) throws JavaModelException {
List list= new ArrayList();
for (int i= 0; i < resources.length; i++) {
IResource resource= resources[i];
if (resource instanceof IFolder) {
IFolder folder= (IFolder) resource;
IJavaElement element= JavaCore.create(folder);
if (element instanceof IPackageFragment) {
list.add(element);
}
}
}
return list;
}
/*
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(Object)
*/
public Object getParent(Object element) {
if (element instanceof IPackageFragment) {
IPackageFragment frag = (IPackageFragment) element;
//@Changed: a fix, before: if(frag.exists() && isEmpty(frag))
return filterParent(getActualParent(frag));
}
return null;
}
public Object getActualParent(IPackageFragment fragment) {
try {
if (fragment.exists()) {
IJavaElement parent = fragment.getParent();
if ((parent instanceof IPackageFragmentRoot) && parent.exists()) {
IPackageFragmentRoot root = (IPackageFragmentRoot) parent;
if (root.isArchive()) {
return findNextLevelChildrenByElementName(fragment, root);
} else {
IResource resource = fragment.getUnderlyingResource();
if ((resource != null) && (resource instanceof IFolder)) {
IFolder folder = (IFolder) resource;
IResource res = folder.getParent();
IJavaElement el = JavaCore.create(res);
return el;
}
}
return parent;
}
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return null;
}
private Object filterParent(Object parent) {
if (fFoldPackages && (parent!=null)) {
try {
if (parent instanceof IPackageFragment) {
IPackageFragment fragment = (IPackageFragment) parent;
if (isEmpty(fragment) && hasSingleChild(fragment)) {
return filterParent(getActualParent(fragment));
}
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
return parent;
}
private boolean hasSingleChild(IPackageFragment fragment) {
return getChildren(fragment).length==1;
}
private Object findNextLevelChildrenByElementName(IJavaElement child, IJavaElement parent) {
String name= child.getElementName();
if(name.indexOf(".")==-1) //$NON-NLS-1$
return parent;
try {
String realParentName= child.getElementName().substring(0,name.lastIndexOf(".")); //$NON-NLS-1$
IJavaElement[] children= new IJavaElement[0];
if(parent instanceof IPackageFragmentRoot){
IPackageFragmentRoot root = (IPackageFragmentRoot) parent;
children= root.getChildren();
} else if (parent instanceof IJavaProject) {
IJavaProject project = (IJavaProject) parent;
children= project.getPackageFragments();
}
for (int i= 0; i < children.length; i++) {
IJavaElement element= children[i];
if(element.getElementName().equals(realParentName))
return element;
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return parent;
}
/*
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(Object)
*/
public boolean hasChildren(Object element) {
if (element instanceof IPackageFragment) {
IPackageFragment fragment= (IPackageFragment) element;
if(fragment.isDefaultPackage())
return false;
}
return getChildren(element).length > 0;
}
/*
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(Object)
*/
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
/*
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
}
/**
* Called when the view is closed and opened.
*
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(Viewer, Object, Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
fViewer= (TreeViewer)viewer;
}
/*
* @see org.eclipse.jdt.core.IElementChangedListener#elementChanged(org.eclipse.jdt.core.ElementChangedEvent)
*/
public void elementChanged(ElementChangedEvent event) {
processDelta(event.getDelta());
}
public void processDelta(IJavaElementDelta delta) {
int kind = delta.getKind();
final IJavaElement element = delta.getElement();
if (element instanceof IPackageFragment) {
if (kind == IJavaElementDelta.REMOVED) {
postRunnable(new Runnable() {
public void run() {
Control ctrl = fViewer.getControl();
if (ctrl != null && !ctrl.isDisposed()) {
ctrl.setRedraw(false);
if (!fFoldPackages)
((TreeViewer) fViewer).remove(element);
else
refreshGrandParent(element);
ctrl.setRedraw(true);
}
}
});
return;
} else if (kind == IJavaElementDelta.ADDED) {
final Object parent = getParent(element);
if (parent != null) {
postRunnable(new Runnable() {
public void run() {
Control ctrl = fViewer.getControl();
if (ctrl != null && !ctrl.isDisposed()) {
ctrl.setRedraw(false);
if (!fFoldPackages)
((TreeViewer) fViewer).add(parent, element);
else
refreshGrandParent(element);
ctrl.setRedraw(true);
}
}
});
}
return;
} else if (kind == IJavaElementDelta.CHANGED) {
postRunnable(new Runnable() {
public void run() {
Control ctrl = fViewer.getControl();
if (ctrl != null && !ctrl.isDisposed()) {
ctrl.setRedraw(false);
refreshGrandParent(element);
ctrl.setRedraw(true);
}
}
});
return;
}
}
IJavaElementDelta[] affectedChildren = delta.getAffectedChildren();
processAffectedChildren(affectedChildren);
}
// XXX: needs to be revisited - might be a performance issue
private void refreshGrandParent(final IJavaElement element) {
if (element instanceof IPackageFragment) {
Object gp= getGrandParent((IPackageFragment)element);
if (gp instanceof IJavaElement) {
IJavaElement el = (IJavaElement) gp;
if(el.exists())
fViewer.refresh(gp);
}
}
}
private Object getGrandParent(IPackageFragment element) {
Object parent= findNextLevelChildrenByElementName(element, element.getParent());
if (parent instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root= (IPackageFragmentRoot) parent;
if(isRootProject(root))
return root.getJavaProject();
else return root;
}
Object grandParent= getParent(parent);
if(grandParent==null){
return parent;
}
return grandParent;
}
private boolean isRootProject(IPackageFragmentRoot root) {
return IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH.equals(root.getElementName());
}
protected void processAffectedChildren(IJavaElementDelta[] affectedChildren) {
for (int i= 0; i < affectedChildren.length; i++) {
if (!(affectedChildren[i] instanceof ICompilationUnit)) {
processDelta(affectedChildren[i]);
}
}
}
private void postRunnable(final Runnable r) {
Control ctrl= fViewer.getControl();
if (ctrl != null && !ctrl.isDisposed()) {
Display currentDisplay= Display.getCurrent();
if (currentDisplay != null && currentDisplay.equals(ctrl.getDisplay()))
ctrl.getDisplay().syncExec(r);
else
ctrl.getDisplay().asyncExec(r);
}
}
/*
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if(AppearancePreferencePage.arePackagesFoldedInHierarchicalLayout()!=fFoldPackages){
fFoldPackages= AppearancePreferencePage.arePackagesFoldedInHierarchicalLayout();
fViewer.getControl().setRedraw(false);
Object[] expandedObjects= fViewer.getExpandedElements();
fViewer.refresh();
fViewer.setExpandedElements(expandedObjects);
fViewer.getControl().setRedraw(true);
}
}
}