/*******************************************************************************
* Copyright (c) 2000, 2013 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.wst.jsdt.internal.ui.packageview;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.IBasicPropertyConstants;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.wst.jsdt.core.ElementChangedEvent;
import org.eclipse.wst.jsdt.core.IClassFile;
import org.eclipse.wst.jsdt.core.IElementChangedListener;
import org.eclipse.wst.jsdt.core.IIncludePathAttribute;
import org.eclipse.wst.jsdt.core.IIncludePathEntry;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptElementDelta;
import org.eclipse.wst.jsdt.core.IJavaScriptModel;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
import org.eclipse.wst.jsdt.core.IParent;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.navigator.ContainerFolder;
import org.eclipse.wst.jsdt.internal.ui.navigator.deferred.ClearPlaceHolderJob;
import org.eclipse.wst.jsdt.internal.ui.navigator.deferred.LoadingModelNode;
import org.eclipse.wst.jsdt.internal.ui.navigator.deferred.LoadingModelUIAnimationJob;
import org.eclipse.wst.jsdt.internal.ui.workingsets.WorkingSetModel;
import org.eclipse.wst.jsdt.ui.PreferenceConstants;
import org.eclipse.wst.jsdt.ui.ProjectLibraryRoot;
import org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider;
/**
* Content provider for the PackageExplorer.
*
* <p>
* Since 2.1 this content provider can provide the children for flat or hierarchical
* layout.
* </p>
*
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider
*/
public class PackageExplorerContentProvider extends StandardJavaScriptElementContentProvider implements ITreeContentProvider, IElementChangedListener, IPropertyChangeListener {
protected static final int ORIGINAL= 0;
protected static final int PARENT= 1 << 0;
protected static final int GRANT_PARENT= 1 << 1;
protected static final int PROJECT= 1 << 2;
private TreeViewer fViewer;
private Object fInput;
private boolean fIsFlatLayout;
private boolean fShowLibrariesNode;
private boolean fFoldPackages;
private Collection fPendingUpdates;
private UIJob fUpdateJob;
/**
* Creates a new content provider for Java elements.
* @param provideMembers if set, members of compilation units and class files are shown
*/
public PackageExplorerContentProvider(boolean provideMembers) {
super(provideMembers);
fShowLibrariesNode= false;
fIsFlatLayout= false;
fFoldPackages= arePackagesFoldedInHierarchicalLayout();
fPendingUpdates= null;
JavaScriptPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
fUpdateJob= null;
}
private boolean arePackagesFoldedInHierarchicalLayout(){
return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.APPEARANCE_FOLD_PACKAGES_IN_PACKAGE_EXPLORER);
}
protected Object getViewerInput() {
return fInput;
}
/* (non-Javadoc)
* Method declared on IElementChangedListener.
*/
public void elementChanged(final ElementChangedEvent event) {
final ArrayList runnables= new ArrayList();
try {
// 58952 delete project does not update Package Explorer [package explorer]
// if the input to the viewer is deleted then refresh to avoid the display of stale elements
if (inputDeleted(runnables))
return;
processDelta(event.getDelta(), runnables);
} catch (JavaScriptModelException e) {
JavaScriptPlugin.log(e);
} finally {
executeRunnables(runnables);
}
}
protected final void executeRunnables(final Collection runnables) {
// now post all collected runnables
final Control ctrl= fViewer.getControl();
if (ctrl != null && !ctrl.isDisposed()) {
//Are we in the UIThread? If so spin it until we are done
if ((ctrl.getDisplay().getThread() == Thread.currentThread()) && !fViewer.isBusy()) {
runUpdates(runnables);
} else {
synchronized (this) {
if (fPendingUpdates == null) {
fPendingUpdates= runnables;
} else {
fPendingUpdates.addAll(runnables);
}
}
postAsyncUpdate(ctrl.getDisplay());
}
}
}
private void postAsyncUpdate(final Display display) {
if (fUpdateJob == null) {
fUpdateJob= new UIJob(display, PackagesMessages.PackageExplorerContentProvider_update_job_description) {
public IStatus runInUIThread(IProgressMonitor monitor) {
TreeViewer viewer= fViewer;
if (viewer != null && viewer.isBusy()) {
schedule(100); // reschedule when viewer is busy: bug 184991
} else {
runPendingUpdates();
}
return Status.OK_STATUS;
}
};
fUpdateJob.setSystem(true);
}
fUpdateJob.schedule();
}
/**
* Run all of the runnables that are the widget updates. Must be called in the display thread.
*/
public void runPendingUpdates() {
Collection pendingUpdates;
synchronized (this) {
pendingUpdates= fPendingUpdates;
fPendingUpdates= null;
}
if (pendingUpdates != null && fViewer != null) {
Control control = fViewer.getControl();
if (control != null && !control.isDisposed()) {
runUpdates(pendingUpdates);
}
}
}
private void runUpdates(Collection runnables) {
Iterator runnableIterator = runnables.iterator();
while (runnableIterator.hasNext()){
((Runnable) runnableIterator.next()).run();
}
}
private boolean inputDeleted(Collection runnables) {
if (fInput == null)
return false;
if ((fInput instanceof IJavaScriptElement) && ((IJavaScriptElement) fInput).exists())
return false;
if ((fInput instanceof IResource) && ((IResource) fInput).exists())
return false;
if (fInput instanceof WorkingSetModel)
return false;
if (fInput instanceof IWorkingSet) // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=156239
return false;
postRefresh(fInput, ORIGINAL, fInput, runnables);
return true;
}
/* (non-Javadoc)
* Method declared on IContentProvider.
*/
public void dispose() {
super.dispose();
JavaScriptCore.removeElementChangedListener(this);
JavaScriptPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider#getPackageFragmentRootContent(org.eclipse.wst.jsdt.core.IPackageFragmentRoot)
*/
protected Object[] getPackageFragmentRootContent(IPackageFragmentRoot root) throws JavaScriptModelException {
if (fIsFlatLayout) {
return super.getPackageFragmentRootContent(root);
}
// hierarchical package mode
ArrayList result= new ArrayList();
getHierarchicalPackageChildren(root, null, result);
if (!isProjectPackageFragmentRoot(root)) {
Object[] nonJavaResources= root.getNonJavaScriptResources();
for (int i= 0; i < nonJavaResources.length; i++) {
result.add(nonJavaResources[i]);
}
}
return result.toArray();
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider#getPackageContent(org.eclipse.wst.jsdt.core.IPackageFragment)
*/
protected Object[] getPackageContent(IPackageFragment fragment) throws JavaScriptModelException {
if (fIsFlatLayout) {
return super.getPackageContent(fragment);
}
// hierarchical package mode
ArrayList result= new ArrayList();
getHierarchicalPackageChildren((IPackageFragmentRoot) fragment.getParent(), fragment, result);
Object[] nonPackages= super.getPackageContent(fragment);
if (result.isEmpty())
return nonPackages;
for (int i= 0; i < nonPackages.length; i++) {
result.add(nonPackages[i]);
}
return result.toArray();
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider#getFolderContent(org.eclipse.core.resources.IFolder)
*/
protected Object[] getFolderContent(IFolder folder) throws CoreException {
if (fIsFlatLayout) {
return super.getFolderContent(folder);
}
// hierarchical package mode
ArrayList result= new ArrayList();
getHierarchicalPackagesInFolder(folder, result);
Object[] others= super.getFolderContent(folder);
if (result.isEmpty())
return others;
for (int i= 0; i < others.length; i++) {
result.add(others[i]);
}
return result.toArray();
}
public Object[] getChildren(Object parentElement) {
try {
if (parentElement instanceof IJavaScriptModel)
return concatenate(getJavaProjects((IJavaScriptModel)parentElement), getNonJavaProjects((IJavaScriptModel)parentElement));
if(parentElement instanceof ContainerFolder) {
return getContainerPackageFragmentRoots((PackageFragmentRootContainer)((ContainerFolder)parentElement).getParentObject());
}
if (parentElement instanceof PackageFragmentRootContainer) {
if(LoadingModelNode.isBeingLoaded((PackageFragmentRootContainer)parentElement)) {
return new Object[] {
LoadingModelNode.createPlaceHolder((PackageFragmentRootContainer)parentElement) };
} else {
LoadingModelNode placeHolder =
LoadingModelNode.createPlaceHolder((PackageFragmentRootContainer)parentElement);
/* we need to load the model,
possible long running operation */
if(LoadingModelNode.canBeginLoading((PackageFragmentRootContainer)parentElement))
new LoadModelJob((AbstractTreeViewer)fViewer,
placeHolder,
(PackageFragmentRootContainer)parentElement)
.schedule();
return new Object[] { placeHolder };
}
}
else if (parentElement instanceof NamespaceGroup && ((NamespaceGroup) parentElement).getPackageFragmentRootContainer() != null) {
return getContainerPackageFragmentRoots(((NamespaceGroup) parentElement).getPackageFragmentRootContainer(), true, ((NamespaceGroup) parentElement));
}
if(parentElement instanceof ProjectLibraryRoot) {
// return ((ProjectLibraryRoot)parentElement).getChildren();
// Include source folders (and also scour their model contents)
Object[] children1 = ((ProjectLibraryRoot) parentElement).getChildren();
List sourceRoots = new ArrayList();
try {
IPackageFragmentRoot[] packageFragmentRoots = ((ProjectLibraryRoot) parentElement).getProject().getPackageFragmentRoots();
for (int i = 0; i < packageFragmentRoots.length; i++) {
IIncludePathEntry entry = packageFragmentRoots[i].getRawIncludepathEntry();
if (IIncludePathEntry.CPE_SOURCE == entry.getEntryKind()) {
boolean hidden = false;
IIncludePathAttribute[] attribs = entry.getExtraAttributes();
for (int k = 0; !hidden && attribs != null && k < attribs.length; k++) {
hidden |= (attribs[k] == IIncludePathAttribute.HIDE);
}
if (!hidden) {
sourceRoots.add(packageFragmentRoots[i]);
}
}
}
}
catch (JavaScriptModelException e) {
e.printStackTrace();
}
Object[] combined = new Object[children1.length + sourceRoots.size()];
System.arraycopy(children1, 0, combined, 0, children1.length);
if (!sourceRoots.isEmpty()) {
System.arraycopy(sourceRoots.toArray(), 0, combined, children1.length, sourceRoots.size());
}
return combined;
}
// if (parentElement instanceof IPackageFragmentRoot) {
// Object[] children = super.getChildren(parentElement);
// for (int i = 0; i < children.length; i++) {
// // replace the "default package" with its contents
// if (children[i] instanceof IPackageFragment && ((IPackageFragment) children[i]).isDefaultPackage()) {
// List combined = new ArrayList(children.length);
// for (int j = 0; j < children.length; j++) {
// if (j != i) {
// combined.add(children[j]);
// }
// else {
// Object[] defaultChildren = super.getChildren(children[j]);
// for (int k = 0; k < defaultChildren.length; k++) {
// combined.add(defaultChildren[k]);
// }
// }
// }
// return combined.toArray();
// }
// }
// return children;
// }
if (parentElement instanceof IProject) {
IProject project= (IProject) parentElement;
if (project.isAccessible())
return project.members();
return NO_CHILDREN;
}
if (parentElement instanceof IPackageFragmentRoot && ((IPackageFragmentRoot)parentElement).isVirtual()) {
return getLibraryChildren((IPackageFragmentRoot)parentElement, fIsFlatLayout, null);
}
else if (parentElement instanceof NamespaceGroup && ((NamespaceGroup) parentElement).getPackageFragmentRoot() != null && ((NamespaceGroup) parentElement).getPackageFragmentRoot().isVirtual()) {
return getLibraryChildren(((NamespaceGroup) parentElement).getPackageFragmentRoot(), true, ((NamespaceGroup) parentElement));
}
else if(parentElement instanceof IPackageFragmentRoot && IIncludePathEntry.CPE_SOURCE == ((IPackageFragmentRoot) parentElement).getRawIncludepathEntry().getEntryKind()) {
return getSourceChildren(parentElement, fIsFlatLayout, null);
}
else if (parentElement instanceof NamespaceGroup && ((NamespaceGroup) parentElement).getPackageFragmentRoot() != null && IIncludePathEntry.CPE_SOURCE == ((NamespaceGroup) parentElement).getPackageFragmentRoot().getRawIncludepathEntry().getEntryKind()) {
return getSourceChildren(((NamespaceGroup) parentElement).getPackageFragmentRoot(), true, ((NamespaceGroup) parentElement));
}
// if script unit
else if (parentElement instanceof IJavaScriptUnit) {
return getSourceChildren(parentElement, fIsFlatLayout, null);
}
// if group with script unit as parent
else if(parentElement instanceof NamespaceGroup && ((NamespaceGroup) parentElement).getJavaScriptUnit() != null) {
return getSourceChildren(((NamespaceGroup) parentElement).getJavaScriptUnit(), true, ((NamespaceGroup) parentElement));
}
return super.getChildren(parentElement);
} catch (CoreException e) {
e.printStackTrace();
return NO_CHILDREN;
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
if (element instanceof JsGlobalScopeContainer) {
return true;//((JsGlobalScopeContainer) element).hasChildren();
}
if (element instanceof ProjectLibraryRoot) {
return ((ProjectLibraryRoot) element).hasChildren();
}
return super.hasChildren(element);
}
private Object[] getSourceChildren(Object parentElement, boolean neverGroup, NamespaceGroup onlyGroup) throws JavaScriptModelException {
/* if the parent is a fragment root use its children
* else if parent element is a script unit, use it as the child
*/
Object[] rawChildren = new Object[0];
if(parentElement instanceof IPackageFragmentRoot) {
rawChildren = ((IParent) parentElement).getChildren();
} else if(parentElement instanceof IJavaScriptUnit) {
rawChildren = new Object[] { parentElement };
}
if (rawChildren == null)
return new Object[0];
ArrayList allChildren = new ArrayList();
ArrayList expanded = new ArrayList();
expanded.addAll(Arrays.asList(rawChildren));
if (expanded.isEmpty())
return new Object[0];
Object next = expanded.remove(0);
Map groups = new HashMap();
while (next != null) {
if (next instanceof IPackageFragment) {
expanded.addAll(Arrays.asList(((IPackageFragment) next).getChildren()));
}
else if (next instanceof IPackageFragmentRoot) {
expanded.addAll(Arrays.asList(((IPackageFragmentRoot) next).getChildren()));
}
else if (next instanceof IClassFile || next instanceof IJavaScriptUnit) {
IJavaScriptElement[] filtered = filter(((IParent) next).getChildren());
List newChildren = Arrays.asList(filtered);
allChildren.removeAll(newChildren);
if (fIsFlatLayout || neverGroup) {
if (onlyGroup == null) {
allChildren.addAll(newChildren);
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupNamesEnd = displayName.lastIndexOf('.');
if (groupNamesEnd == onlyGroup.fNamePrefixLength && displayName.startsWith(onlyGroup.fNamePrefix)) {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupEnd = displayName.lastIndexOf('.');
if (groupEnd > 0) {
String groupName = displayName.substring(0, groupEnd);
if (!groups.containsKey(groupName)) {
// create the group based on the parent type
NamespaceGroup group = null;
if(parentElement instanceof IPackageFragmentRoot) {
group = new NamespaceGroup((IPackageFragmentRoot) parentElement, groupName);
} else if(parentElement instanceof IJavaScriptUnit) {
group = new NamespaceGroup((IJavaScriptUnit) parentElement, groupName);
}
if(group != null) {
groups.put(groupName, group);
allChildren.add(group);
}
}
}
else {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
if (expanded.size() > 0)
next = expanded.remove(0);
else
next = null;
}
return allChildren.toArray();
}
private Object[] getLibraryChildren(IPackageFragmentRoot container, boolean neverGroup, NamespaceGroup onlyGroup) {
Object[] children=null;
try {
children = container.getChildren();
} catch (JavaScriptModelException ex1) {
ex1.printStackTrace();
}
if(children==null) return null;
ArrayList allChildren = new ArrayList();
Map groups = null;
if (!fIsFlatLayout) {
groups = new HashMap();
}
boolean unique = false;
try {
while(!unique && children!=null && children.length>0) {
for(int i = 0;i<children.length;i++) {
String display1 = ((IJavaScriptElement)children[0]).getDisplayName();
String display2 = ((IJavaScriptElement)children[i]).getDisplayName();
if(!( (display1==display2) || (display1!=null && display1.compareTo(display2)==0))){
allChildren.addAll(Arrays.asList(children));
unique=true;
break;
}
}
List more = new ArrayList();
for(int i = 0;!unique && i<children.length;i++) {
if(children[i] instanceof IPackageFragment) {
more.addAll(Arrays.asList(((IPackageFragment)children[i]).getChildren()));
}else if(children[i] instanceof IPackageFragmentRoot) {
more.addAll(Arrays.asList(((IPackageFragmentRoot)children[i]).getChildren()));
}else if(children[i] instanceof IClassFile || children[i] instanceof IJavaScriptUnit) {
IJavaScriptElement[] filtered = filter(((IParent) children[i]).getChildren());
List newChildren = Arrays.asList(filtered);
allChildren.removeAll(newChildren);
if (fIsFlatLayout || neverGroup) {
if (onlyGroup == null) {
allChildren.addAll(newChildren);
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupNamesEnd = displayName.lastIndexOf('.');
if (groupNamesEnd == onlyGroup.fNamePrefixLength && displayName.startsWith(onlyGroup.fNamePrefix)) {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupEnd = displayName.lastIndexOf('.');
if (groupEnd > 0) {
String groupName = displayName.substring(0, groupEnd);
if (!groups.containsKey(groupName)) {
NamespaceGroup group = new NamespaceGroup(container, groupName);
groups.put(groupName, group);
allChildren.add(group);
}
}
else {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
else {
/* bottomed out, now at javaScriptElement level */
unique=true;
break;
}
}
if(!unique) children = more.toArray();
}
} catch (JavaScriptModelException ex) {
ex.printStackTrace();
}
return allChildren.toArray();
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.StandardJavaScriptElementContentProvider#getPackageFragmentRoots(org.eclipse.wst.jsdt.core.IJavaScriptProject)
*/
protected Object[] getPackageFragmentRoots(IJavaScriptProject project) throws JavaScriptModelException {
if (!project.getProject().isOpen())
return NO_CHILDREN;
List result= new ArrayList();
boolean addJARContainer= false;
ArrayList projectPackageFragmentRoots = new ArrayList();
IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
for (int i= 0; i < roots.length; i++) {
IPackageFragmentRoot root= roots[i];
IIncludePathEntry classpathEntry= root.getRawIncludepathEntry();
IIncludePathAttribute[] attribs = classpathEntry.getExtraAttributes();
boolean shouldHide = false;
for(int p = 0;p<attribs.length;p++){
if(attribs[p]==IIncludePathAttribute.HIDE) shouldHide = true;
}
int entryKind= classpathEntry.getEntryKind();
if (entryKind == IIncludePathEntry.CPE_CONTAINER) {
// all JsGlobalScopeContainers are added later
} else if (fShowLibrariesNode && (entryKind != IIncludePathEntry.CPE_SOURCE) && entryKind!=IIncludePathEntry.CPE_CONTAINER) {
addJARContainer= true;
projectPackageFragmentRoots.add(root);
} else {
if (isProjectPackageFragmentRoot(root)) {
// filter out package fragments that correspond to projects and
// replace them with the package fragments directly
// Object[] fragments= getPackageFragmentRootContent(root);
// for (int j= 0; j < fragments.length; j++) {
// result.add(fragments[j]);
// }
} /*else if(!shouldHide){
result.add(root);
}*/
}
}
if (addJARContainer) {
projectPackageFragmentRoots.add(new LibraryContainer(project));
}
// separate loop to make sure all containers are on the classpath
IIncludePathEntry[] rawClasspath= project.getRawIncludepath();
for (int i= 0; i < rawClasspath.length; i++) {
IIncludePathEntry classpathEntry= rawClasspath[i];
if (classpathEntry.getEntryKind() == IIncludePathEntry.CPE_CONTAINER) {
projectPackageFragmentRoots.add(new JsGlobalScopeContainer(project, classpathEntry));
}
}
// Object[] resources= project.getNonJavaScriptResources();
// for (int i= 0; i < resources.length; i++) {
// result.add(resources[i]);
// }
ProjectLibraryRoot projectLibs = new ProjectLibraryRoot(project);
result.add(0,projectLibs);
return result.toArray();
}
public Object getParent(Object element) {
if (element instanceof NamespaceGroup) {
return ((NamespaceGroup)element).getParent();
}
if (element instanceof IPackageFragmentRoot) {
IJavaScriptProject project = (IJavaScriptProject) ((IPackageFragmentRoot) element).getAncestor(IJavaScriptElement.JAVASCRIPT_PROJECT);
if (project != null) {
return new ProjectLibraryRoot(project);
}
}
return super.getParent(element);
}
// private Object[] getContainerPackageFragmentRoots3(PackageFragmentRootContainer container) {
// Object[] children = container.getChildren();
// if(children==null) return null;
// ArrayList allChildren = new ArrayList();
// for(int i=0;i<children.length;i++) {
// try {
// allChildren.addAll(Arrays.asList(((IPackageFragmentRoot)children[i]).getChildren()));
// } catch (JavaScriptModelException ex) {
//
// }
// }
// return allChildren.toArray();
// }
//
private Object[] getContainerPackageFragmentRoots(PackageFragmentRootContainer container) {
return getContainerPackageFragmentRoots(container, false, null);
}
private Object[] getContainerPackageFragmentRoots(PackageFragmentRootContainer container, boolean neverGroup, NamespaceGroup onlyGroup) {
Object[] children = container.getChildren();
if (children == null)
return new Object[0];
for (int i = 0; i < children.length; i++) {
/* if one of the children is not a JS model element, or is an archive, return as-is for further navigation */
if (!(children[i] instanceof IJavaScriptElement) || (((IJavaScriptElement) children[i]).getElementType() == IJavaScriptElement.PACKAGE_FRAGMENT_ROOT && ((IPackageFragmentRoot) children[i]).isArchive()))
return children;
}
ArrayList allChildren = new ArrayList();
ArrayList expanded = new ArrayList();
expanded.addAll(Arrays.asList(children));
if(expanded.isEmpty()) return new Object[0];
Map groups = null;
if (!fIsFlatLayout) {
groups = new HashMap();
}
Object next = expanded.remove(0);
while(next!=null) {
try {
if(next instanceof IPackageFragment) {
expanded.addAll(Arrays.asList(((IPackageFragment)next).getChildren()));
}else if(next instanceof IPackageFragmentRoot) {
expanded.addAll(Arrays.asList(((IPackageFragmentRoot)next).getChildren()));
}else if(next instanceof IClassFile || next instanceof IJavaScriptUnit) {
IJavaScriptElement[] filtered = filter(((IParent) next).getChildren());
List newChildren = Arrays.asList(filtered);
allChildren.removeAll(newChildren);
if (fIsFlatLayout || neverGroup) {
if (onlyGroup == null) {
allChildren.addAll(newChildren);
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupNamesEnd = displayName.lastIndexOf('.');
if (groupNamesEnd == onlyGroup.fNamePrefixLength && displayName.startsWith(onlyGroup.fNamePrefix)) {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
else {
for (int j = 0; j < filtered.length; j++) {
switch(filtered[j].getElementType()) {
case IJavaScriptElement.TYPE :
case IJavaScriptElement.FIELD :
case IJavaScriptElement.METHOD :
case IJavaScriptElement.INITIALIZER :
case IJavaScriptElement.LOCAL_VARIABLE : {
String displayName = filtered[j].getDisplayName();
int groupEnd = displayName.lastIndexOf('.');
if (groupEnd > 0) {
String groupName = displayName.substring(0, groupEnd);
if (!groups.containsKey(groupName)) {
NamespaceGroup group = new NamespaceGroup(container, groupName);
groups.put(groupName, group);
allChildren.add(group);
}
}
else {
allChildren.add(filtered[j]);
}
break;
}
default : {
allChildren.add(filtered[j]);
}
}
}
}
}
else {
allChildren.add(next);
}
} catch (JavaScriptModelException ex) {
ex.printStackTrace();
}
if(expanded.size()>0)
next = expanded.remove(0);
else
next = null;
}
return allChildren.toArray();
}
private Object[] getContainerPackageFragmentRootsDeprc(PackageFragmentRootContainer container, boolean createFolder) {
if(container!=null) {
Object[] children = container.getChildren();
if(children==null) return null;
ArrayList allChildren = new ArrayList();
boolean unique = false;
while(!unique && children!=null && children.length>0) {
String display1=null;
for(int i = 0;i<children.length;i++) {
display1 = ((IJavaScriptElement)children[0]).getDisplayName();
String display2 = ((IJavaScriptElement)children[i]).getDisplayName();
if(!( (display1==display2) || (display1!=null && display1.compareTo(display2)==0))){
allChildren.addAll(Arrays.asList(children));
unique=true;
break;
}
}
if(!unique && createFolder) {
ContainerFolder folder = new ContainerFolder(display1, container);
return new Object[] {folder};
}
ArrayList more = new ArrayList();
for(int i = 0;!unique && i<children.length;i++) {
try {
if(children[i] instanceof IPackageFragment) {
more.addAll(Arrays.asList(((IPackageFragment)children[i]).getChildren()));
}else if(children[i] instanceof IPackageFragmentRoot) {
more.addAll(Arrays.asList(((IPackageFragmentRoot)children[i]).getChildren()));
}else if(children[i] instanceof IClassFile) {
more.addAll(Arrays.asList( filter(((IClassFile)children[i]).getChildren())) );
}else if(children[i] instanceof IJavaScriptUnit) {
more.addAll(Arrays.asList( filter(((IJavaScriptUnit)children[i]).getChildren())) );
}else {
/* bottomed out, now at javaElement level */
unique=true;
break;
}
} catch (JavaScriptModelException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
if(!unique) children = more.toArray();
}
return allChildren.toArray();
}else {
return new Object[0];
}
}
private Object[] getNonJavaProjects(IJavaScriptModel model) throws JavaScriptModelException {
return model.getNonJavaScriptResources();
}
protected Object internalGetParent(Object element) {
if (!fIsFlatLayout && element instanceof IPackageFragment) {
return getHierarchicalPackageParent((IPackageFragment) element);
} else if (element instanceof IPackageFragmentRoot) {
// since we insert logical package containers we have to fix
// up the parent for package fragment roots so that they refer
// to the container and containers refer to the project
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
try {
IIncludePathEntry entry= root.getRawIncludepathEntry();
int entryKind= entry.getEntryKind();
if (entryKind == IIncludePathEntry.CPE_CONTAINER) {
return new JsGlobalScopeContainer(root.getJavaScriptProject(), entry);
} else if (fShowLibrariesNode && (entryKind == IIncludePathEntry.CPE_LIBRARY || entryKind == IIncludePathEntry.CPE_VARIABLE)) {
return new LibraryContainer(root.getJavaScriptProject());
}
} catch (JavaScriptModelException e) {
// fall through
}
} else if (element instanceof PackageFragmentRootContainer) {
return ((PackageFragmentRootContainer)element).getJavaProject();
}
return super.internalGetParent(element);
}
/* (non-Javadoc)
* Method declared on IContentProvider.
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
super.inputChanged(viewer, oldInput, newInput);
fViewer= (TreeViewer)viewer;
if (oldInput == null && newInput != null) {
JavaScriptCore.addElementChangedListener(this);
} else if (oldInput != null && newInput == null) {
JavaScriptCore.removeElementChangedListener(this);
}
fInput= newInput;
}
// hierarchical packages
/**
* Returns the hierarchical packages inside a given fragment or root.
* @param parent The parent package fragment root
* @param fragment The package to get the children for or 'null' to get the children of the root.
* @param result Collection where the resulting elements are added
* @throws JavaScriptModelException
*/
private void getHierarchicalPackageChildren(IPackageFragmentRoot parent, IPackageFragment fragment, Collection result) throws JavaScriptModelException {
IJavaScriptElement[] children= parent.getChildren();
String prefix= fragment != null ? fragment.getElementName() + '/' : ""; //$NON-NLS-1$
if (prefix.length()==1)
prefix=""; //$NON-NLS-1$
int prefixLen= prefix.length();
for (int i= 0; i < children.length; i++) {
IPackageFragment curr= (IPackageFragment) children[i];
if (fragment==null)
{
if (curr.isDefaultPackage())
result.add(curr);
}
else
{
String name= curr.getElementName();
if (name.startsWith(prefix) && name.length() > prefixLen && name.indexOf('/', prefixLen) == -1) {
if (fFoldPackages) {
curr= getFolded(children, curr);
}
result.add(curr);
}
}
}
}
/**
* Returns the hierarchical packages inside a given folder.
* @param folder The parent folder
* @param result Collection where the resulting elements are added
* @throws CoreException thrown when elements could not be accessed
*/
private void getHierarchicalPackagesInFolder(IFolder folder, Collection result) throws CoreException {
IResource[] resources= folder.members();
for (int i= 0; i < resources.length; i++) {
IResource resource= resources[i];
if (resource instanceof IFolder) {
IFolder curr= (IFolder) resource;
IJavaScriptElement element= JavaScriptCore.create(curr);
if (element instanceof IPackageFragment) {
if (element.exists()) {
if (fFoldPackages) {
IPackageFragment fragment= (IPackageFragment) element;
IPackageFragmentRoot root= (IPackageFragmentRoot) fragment.getParent();
element= getFolded(root.getChildren(), fragment);
}
result.add(element);
}
}
}
}
}
public Object getHierarchicalPackageParent(IPackageFragment child) {
String name= child.getElementName();
IPackageFragmentRoot parent= (IPackageFragmentRoot) child.getParent();
int index= name.lastIndexOf('/');
if (index != -1) {
String realParentName= name.substring(0, index);
IPackageFragment element= parent.getPackageFragment(realParentName);
if (element.exists()) {
try {
if (fFoldPackages && isEmpty(element) && findSinglePackageChild(element, parent.getChildren()) != null) {
return getHierarchicalPackageParent(element);
}
} catch (JavaScriptModelException e) {
// ignore
}
return element;
} else { // bug 65240
IResource resource= element.getResource();
if (resource != null) {
return resource;
}
}
}
if (parent.getResource() instanceof IProject) {
return parent.getJavaScriptProject();
}
return parent;
}
private static IPackageFragment getFolded(IJavaScriptElement[] children, IPackageFragment pack) throws JavaScriptModelException {
while (isEmpty(pack)) {
IPackageFragment collapsed= findSinglePackageChild(pack, children);
if (collapsed == null) {
return pack;
}
pack= collapsed;
}
return pack;
}
private static boolean isEmpty(IPackageFragment fragment) throws JavaScriptModelException {
return !fragment.containsJavaResources() && fragment.getNonJavaScriptResources().length == 0;
}
private static IPackageFragment findSinglePackageChild(IPackageFragment fragment, IJavaScriptElement[] children) {
String prefix= fragment.getElementName() + '/';
int prefixLen= prefix.length();
IPackageFragment found= null;
for (int i= 0; i < children.length; i++) {
IJavaScriptElement element= children[i];
String name= element.getElementName();
if (name.startsWith(prefix) && name.length() > prefixLen && name.indexOf('/', prefixLen) == -1) {
if (found == null) {
found= (IPackageFragment) element;
} else {
return null;
}
}
}
return found;
}
// ------ delta processing ------
/**
* Processes a delta recursively. When more than two children are affected the
* tree is fully refreshed starting at this node.
*
* @param delta the delta to process
* @param runnables the resulting view changes as runnables (type {@link Runnable})
* @return true is returned if the conclusion is to refresh a parent of an element. In that case no siblings need
* to be processed
* @throws JavaScriptModelException thrown when the access to an element failed
*/
private boolean processDelta(IJavaScriptElementDelta delta, Collection runnables) throws JavaScriptModelException {
int kind= delta.getKind();
int flags= delta.getFlags();
IJavaScriptElement element= delta.getElement();
int elementType= element.getElementType();
if (elementType != IJavaScriptElement.JAVASCRIPT_MODEL && elementType != IJavaScriptElement.JAVASCRIPT_PROJECT) {
IJavaScriptProject proj= element.getJavaScriptProject();
if (proj == null || !proj.getProject().isOpen()) // TODO: Not needed if parent already did the 'open' check!
return false;
}
if (!fIsFlatLayout && elementType == IJavaScriptElement.PACKAGE_FRAGMENT) {
if (kind == IJavaScriptElementDelta.REMOVED) {
final Object parent = getHierarchicalPackageParent((IPackageFragment) element);
if (parent instanceof IPackageFragmentRoot) {
postRemove(element, runnables);
return false;
} else {
postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
return true;
}
} else if (kind == IJavaScriptElementDelta.ADDED) {
final Object parent = getHierarchicalPackageParent((IPackageFragment) element);
if (parent instanceof IPackageFragmentRoot) {
postAdd(parent, element, runnables);
return false;
} else {
postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
return true;
}
}
handleAffectedChildren(delta, element, runnables);
return false;
}
if (elementType == IJavaScriptElement.JAVASCRIPT_UNIT) {
IJavaScriptUnit cu= (IJavaScriptUnit) element;
if (!JavaModelUtil.isPrimary(cu)) {
return false;
}
if (!getProvideMembers() && cu.isWorkingCopy() && kind == IJavaScriptElementDelta.CHANGED) {
return false;
}
if ((kind == IJavaScriptElementDelta.CHANGED) && !isStructuralCUChange(flags)) {
return false; // test moved ahead
}
if (!isOnClassPath(cu)) { // TODO: isOnClassPath expensive! Should be put after all cheap tests
return false;
}
}
if (elementType == IJavaScriptElement.JAVASCRIPT_PROJECT) {
// handle open and closing of a project
if ((flags & (IJavaScriptElementDelta.F_CLOSED | IJavaScriptElementDelta.F_OPENED)) != 0) {
postRefresh(element, ORIGINAL, element, runnables);
return false;
}
// if the raw class path has changed we refresh the entire project
if ((flags & IJavaScriptElementDelta.F_INCLUDEPATH_CHANGED) != 0) {
postRefresh(element, ORIGINAL, element, runnables);
if (element.getElementType() == IJavaScriptElement.JAVASCRIPT_PROJECT) {
postRefresh(((IJavaScriptProject)element).getProject(), ORIGINAL, ((IJavaScriptProject)element).getProject(), runnables);
}
return false;
}
// refresh just like on removal
if (kind == IJavaScriptElementDelta.ADDED) {
postRefresh(element, PARENT, element, runnables);
return true;
}
}
if (kind == IJavaScriptElementDelta.REMOVED) {
Object parent= internalGetParent(element);
if (element instanceof IPackageFragment) {
// refresh package fragment root to allow filtering empty (parent) packages: bug 72923
if (fViewer.testFindItem(parent) != null)
postRefresh(parent, PARENT, element, runnables);
return true;
}
postRemove(element, runnables);
if (parent instanceof IPackageFragment)
postUpdateIcon((IPackageFragment)parent, runnables);
// we are filtering out empty subpackages, so we
// a package becomes empty we remove it from the viewer.
if (isPackageFragmentEmpty(element.getParent())) {
if (fViewer.testFindItem(parent) != null)
postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
return true;
}
return false;
}
if (kind == IJavaScriptElementDelta.ADDED) {
Object parent= internalGetParent(element);
// we are filtering out empty subpackages, so we
// have to handle additions to them specially.
if (parent instanceof IPackageFragment) {
Object grandparent= internalGetParent(parent);
// 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
// avoid posting a refresh to an invisible parent
if (parent.equals(fInput)) {
postRefresh(parent, PARENT, element, runnables);
} else {
// refresh from grandparent if parent isn't visible yet
if (fViewer.testFindItem(parent) == null)
postRefresh(grandparent, GRANT_PARENT, element, runnables);
else {
postRefresh(parent, PARENT, element, runnables);
}
}
return true;
} else {
postAdd(parent, element, runnables);
}
}
if (elementType == IJavaScriptElement.JAVASCRIPT_UNIT) {
if (kind == IJavaScriptElementDelta.CHANGED) {
// isStructuralCUChange already performed above
postRefresh(element, ORIGINAL, element, runnables);
IResource underlyingResource = ((IJavaScriptUnit)element).getUnderlyingResource();
if(underlyingResource != null) {
postRefresh(underlyingResource, ORIGINAL, element, runnables);
}
updateSelection(delta, runnables);
}
return false;
}
// no changes possible in class files
if (elementType == IJavaScriptElement.CLASS_FILE)
return false;
if (elementType == IJavaScriptElement.PACKAGE_FRAGMENT_ROOT) {
// the contents of an external JAR has changed
if ((flags & IJavaScriptElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
postRefresh(element, ORIGINAL, element, runnables);
return false;
}
// the source attachment of a JAR has changed
if ((flags & (IJavaScriptElementDelta.F_SOURCEATTACHED | IJavaScriptElementDelta.F_SOURCEDETACHED)) != 0)
postUpdateIcon(element, runnables);
if (isClassPathChange(delta)) {
// throw the towel and do a full refresh of the affected java project.
postRefresh(element.getJavaScriptProject(), PROJECT, element, runnables);
return true;
}
}
handleAffectedChildren(delta, element, runnables);
return false;
}
private static boolean isStructuralCUChange(int flags) {
// No refresh on working copy creation (F_PRIMARY_WORKING_COPY)
return ((flags & IJavaScriptElementDelta.F_CHILDREN) != 0) || ((flags & (IJavaScriptElementDelta.F_CONTENT | IJavaScriptElementDelta.F_FINE_GRAINED)) == IJavaScriptElementDelta.F_CONTENT);
}
/* package */ void handleAffectedChildren(IJavaScriptElementDelta delta, IJavaScriptElement element, Collection runnables) throws JavaScriptModelException {
int count= 0;
IResourceDelta[] resourceDeltas= delta.getResourceDeltas();
if (resourceDeltas != null) {
for (int i= 0; i < resourceDeltas.length; i++) {
int kind= resourceDeltas[i].getKind();
if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
count++;
}
}
}
IJavaScriptElementDelta[] affectedChildren= delta.getAffectedChildren();
for (int i= 0; i < affectedChildren.length; i++) {
int kind= affectedChildren[i].getKind();
if (kind == IJavaScriptElementDelta.ADDED || kind == IJavaScriptElementDelta.REMOVED) {
count++;
}
}
if (count > 1) {
// more than one child changed, refresh from here downwards
if (element instanceof IPackageFragment) {
// a package fragment might become non empty refresh from the parent
IJavaScriptElement parent= (IJavaScriptElement) internalGetParent(element);
// 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
// avoid posting a refresh to an invisible parent
if (element.equals(fInput)) {
postRefresh(element, ORIGINAL, element, runnables);
} else {
postRefresh(parent, PARENT, element, runnables);
}
} else if (element instanceof IPackageFragmentRoot) {
Object toRefresh= internalGetParent(element);
postRefresh(toRefresh, ORIGINAL, toRefresh, runnables);
} else {
postRefresh(element, ORIGINAL, element, runnables);
}
return;
}
if (resourceDeltas != null) {
for (int i= 0; i < resourceDeltas.length; i++) {
if (processResourceDelta(resourceDeltas[i], element, runnables)) {
return; // early return, element got refreshed
}
}
}
for (int i= 0; i < affectedChildren.length; i++) {
if (processDelta(affectedChildren[i], runnables)) {
return; // early return, element got refreshed
}
}
}
protected void processAffectedChildren(IJavaScriptElementDelta[] affectedChildren, Collection runnables) throws JavaScriptModelException {
for (int i= 0; i < affectedChildren.length; i++) {
processDelta(affectedChildren[i], runnables);
}
}
private boolean isOnClassPath(IJavaScriptUnit element) {
IJavaScriptProject project= element.getJavaScriptProject();
if (project == null || !project.exists())
return false;
return project.isOnIncludepath(element);
}
/**
* Updates the selection. It finds newly added elements
* and selects them.
* @param delta the delta to process
* @param runnables the resulting view changes as runnables (type {@link Runnable})
*/
private void updateSelection(IJavaScriptElementDelta delta, Collection runnables) {
final IJavaScriptElement addedElement= findAddedElement(delta);
if (addedElement != null) {
final StructuredSelection selection= new StructuredSelection(addedElement);
runnables.add(new Runnable() {
public void run() {
// 19431
// if the item is already visible then select it
if (fViewer.testFindItem(addedElement) != null)
fViewer.setSelection(selection);
}
});
}
}
private IJavaScriptElement findAddedElement(IJavaScriptElementDelta delta) {
if (delta.getKind() == IJavaScriptElementDelta.ADDED)
return delta.getElement();
IJavaScriptElementDelta[] affectedChildren= delta.getAffectedChildren();
for (int i= 0; i < affectedChildren.length; i++)
return findAddedElement(affectedChildren[i]);
return null;
}
/**
* Updates the package icon
* @param element the element to update
* @param runnables the resulting view changes as runnables (type {@link Runnable})
*/
private void postUpdateIcon(final IJavaScriptElement element, Collection runnables) {
runnables.add(new Runnable() {
public void run() {
// 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
fViewer.update(element, new String[]{IBasicPropertyConstants.P_IMAGE});
}
});
}
/**
* Process a resource delta.
*
* @param delta the delta to process
* @param parent the parent
* @param runnables the resulting view changes as runnables (type {@link Runnable})
* @return true if the parent got refreshed
*/
private boolean processResourceDelta(IResourceDelta delta, Object parent, Collection runnables) {
int status= delta.getKind();
int flags= delta.getFlags();
IResource resource= delta.getResource();
// filter out changes affecting the output folder
if (resource == null)
return false;
// this could be optimized by handling all the added children in the parent
if ((status & IResourceDelta.REMOVED) != 0) {
if (parent instanceof IPackageFragment) {
// refresh one level above to deal with empty package filtering properly
postRefresh(internalGetParent(parent), PARENT, parent, runnables);
return true;
} else {
postRemove(resource, runnables);
return false;
}
}
if ((status & IResourceDelta.ADDED) != 0) {
if (parent instanceof IPackageFragment) {
// refresh one level above to deal with empty package filtering properly
postRefresh(internalGetParent(parent), PARENT, parent, runnables);
return true;
} else
{
postAdd(parent, resource, runnables);
return false;
}
}
if ((status & IResourceDelta.CHANGED) != 0) {
if ((flags & IResourceDelta.TYPE) != 0) {
postRefresh(parent, PARENT, resource, runnables);
return true;
}
}
// open/close state change of a project
if ((flags & IResourceDelta.OPEN) != 0) {
postProjectStateChanged(internalGetParent(parent), runnables);
return true;
}
IResourceDelta[] resourceDeltas= delta.getAffectedChildren();
int count= 0;
for (int i= 0; i < resourceDeltas.length; i++) {
int kind= resourceDeltas[i].getKind();
if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
count++;
if (count > 1) {
postRefresh(parent, PARENT, resource, runnables);
return true;
}
}
}
for (int i= 0; i < resourceDeltas.length; i++) {
if (processResourceDelta(resourceDeltas[i], resource, runnables)) {
return false; // early return, element got refreshed
}
}
return false;
}
public void setIsFlatLayout(boolean state) {
fIsFlatLayout= state;
}
public void setShowLibrariesNode(boolean state) {
fShowLibrariesNode= state;
}
private void postRefresh(Object root, int relation, Object affectedElement, Collection runnables) {
// JFace doesn't refresh when object isn't part of the viewer
// Therefore move the refresh start down to the viewer's input
if (isParent(root, fInput))
root= fInput;
List toRefresh= new ArrayList(1);
toRefresh.add(root);
augmentElementToRefresh(toRefresh, relation, affectedElement);
postRefresh(toRefresh, true, runnables);
}
/**
* Can be implemented by subclasses to add additional elements to refresh
*
* @param toRefresh the elements to refresh
* @param relation the relation to the affected element ({@link #GRANT_PARENT}, {@link #PARENT}, {@link #ORIGINAL}, {@link #PROJECT})
* @param affectedElement the affected element
*/
protected void augmentElementToRefresh(List toRefresh, int relation, Object affectedElement) {
}
private boolean isParent(Object root, Object child) {
Object parent= getParent(child);
if (parent == null)
return false;
if (parent.equals(root))
return true;
return isParent(root, parent);
}
protected void postRefresh(final List toRefresh, final boolean updateLabels, Collection runnables) {
runnables.add(new Runnable() {
public void run() {
for (Iterator iter= toRefresh.iterator(); iter.hasNext();) {
fViewer.refresh(iter.next(), updateLabels);
}
}
});
}
protected void postAdd(final Object parent, final Object element, Collection runnables) {
runnables.add(new Runnable() {
public void run() {
Widget[] items= fViewer.testFindItems(element);
for (int i= 0; i < items.length; i++) {
Widget item= items[i];
if (item instanceof TreeItem && !item.isDisposed()) {
TreeItem parentItem= ((TreeItem) item).getParentItem();
if (parentItem != null && !parentItem.isDisposed() && parent.equals(parentItem.getData())) {
return; // no add, element already added (most likely by a refresh)
}
}
}
fViewer.add(parent, element);
}
});
}
protected void postRemove(final Object element, Collection runnables) {
runnables.add(new Runnable() {
public void run() {
fViewer.remove(element);
}
});
}
protected void postProjectStateChanged(final Object root, Collection runnables) {
runnables.add(new Runnable() {
public void run() {
fViewer.refresh(root, true);
// trigger a synthetic selection change so that action refresh their
// enable state.
fViewer.setSelection(fViewer.getSelection());
}
});
}
/*
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (arePackagesFoldedInHierarchicalLayout() != fFoldPackages){
fFoldPackages= arePackagesFoldedInHierarchicalLayout();
if (fViewer != null && !fViewer.getControl().isDisposed()) {
fViewer.getControl().setRedraw(false);
Object[] expandedObjects= fViewer.getExpandedElements();
fViewer.refresh();
fViewer.setExpandedElements(expandedObjects);
fViewer.getControl().setRedraw(true);
}
}
}
// inner class for deferred model loading
public class LoadModelJob extends Job {
private LoadingModelNode placeHolder;
private AbstractTreeViewer viewer;
private PackageFragmentRootContainer packageFragmentRootContainer;
public LoadModelJob(AbstractTreeViewer viewer, LoadingModelNode placeHolder, PackageFragmentRootContainer packageFragmentRootContainer) {
super(placeHolder.getText());
this.viewer = viewer;
this.placeHolder = placeHolder;
this.packageFragmentRootContainer = packageFragmentRootContainer;
}
protected IStatus run(IProgressMonitor monitor) {
LoadingModelUIAnimationJob updateUIJob = new LoadingModelUIAnimationJob(viewer, placeHolder);
updateUIJob.schedule();
Object[] retVal = new Object[0];
try {
// Load the model in the background after starting the animation job
retVal = getContainerPackageFragmentRoots(packageFragmentRootContainer, fIsFlatLayout, null);
} finally {
/* dispose of the place holder, causes the termination of the animation job */
placeHolder.dispose();
new ClearPlaceHolderJob(viewer, placeHolder, packageFragmentRootContainer, retVal).schedule();
}
return Status.OK_STATUS;
}
}
}