KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > packageview > PackageExplorerContentProvider


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.ui.packageview;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collection JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.Path;
20
21 import org.eclipse.core.resources.IFolder;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.resources.IResourceDelta;
25
26 import org.eclipse.swt.widgets.Control;
27
28 import org.eclipse.jface.util.IPropertyChangeListener;
29 import org.eclipse.jface.util.PropertyChangeEvent;
30 import org.eclipse.jface.viewers.IBasicPropertyConstants;
31 import org.eclipse.jface.viewers.ITreeContentProvider;
32 import org.eclipse.jface.viewers.StructuredSelection;
33 import org.eclipse.jface.viewers.TreeViewer;
34 import org.eclipse.jface.viewers.Viewer;
35
36 import org.eclipse.ui.IWorkingSet;
37
38 import org.eclipse.jdt.core.ElementChangedEvent;
39 import org.eclipse.jdt.core.IClasspathEntry;
40 import org.eclipse.jdt.core.ICompilationUnit;
41 import org.eclipse.jdt.core.IElementChangedListener;
42 import org.eclipse.jdt.core.IJavaElement;
43 import org.eclipse.jdt.core.IJavaElementDelta;
44 import org.eclipse.jdt.core.IJavaModel;
45 import org.eclipse.jdt.core.IJavaProject;
46 import org.eclipse.jdt.core.IPackageFragment;
47 import org.eclipse.jdt.core.IPackageFragmentRoot;
48 import org.eclipse.jdt.core.JavaCore;
49 import org.eclipse.jdt.core.JavaModelException;
50
51 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
52
53 import org.eclipse.jdt.ui.PreferenceConstants;
54 import org.eclipse.jdt.ui.StandardJavaElementContentProvider;
55
56 import org.eclipse.jdt.internal.ui.JavaPlugin;
57 import org.eclipse.jdt.internal.ui.workingsets.WorkingSetModel;
58  
59 /**
60  * Content provider for the PackageExplorer.
61  *
62  * <p>
63  * Since 2.1 this content provider can provide the children for flat or hierarchical
64  * layout.
65  * </p>
66  *
67  * @see org.eclipse.jdt.ui.StandardJavaElementContentProvider
68  */

69 public class PackageExplorerContentProvider extends StandardJavaElementContentProvider implements ITreeContentProvider, IElementChangedListener, IPropertyChangeListener {
70     
71     protected static final int ORIGINAL= 0;
72     protected static final int PARENT= 1 << 0;
73     protected static final int GRANT_PARENT= 1 << 1;
74     protected static final int PROJECT= 1 << 2;
75     
76     private TreeViewer fViewer;
77     private Object JavaDoc fInput;
78     private boolean fIsFlatLayout;
79     private boolean fShowLibrariesNode;
80     private boolean fFoldPackages;
81     
82     private Collection JavaDoc fPendingUpdates;
83         
84     /**
85      * Creates a new content provider for Java elements.
86      * @param provideMembers if set, members of compilation units and class files are shown
87      */

88     public PackageExplorerContentProvider(boolean provideMembers) {
89         super(provideMembers);
90         fShowLibrariesNode= false;
91         fIsFlatLayout= false;
92         fFoldPackages= arePackagesFoldedInHierarchicalLayout();
93         fPendingUpdates= null;
94         JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
95     }
96     
97     private boolean arePackagesFoldedInHierarchicalLayout(){
98         return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.APPEARANCE_FOLD_PACKAGES_IN_PACKAGE_EXPLORER);
99     }
100             
101     protected Object JavaDoc getViewerInput() {
102         return fInput;
103     }
104     
105     /* (non-Javadoc)
106      * Method declared on IElementChangedListener.
107      */

108     public void elementChanged(final ElementChangedEvent event) {
109         final ArrayList JavaDoc runnables= new ArrayList JavaDoc();
110         try {
111             // 58952 delete project does not update Package Explorer [package explorer]
112
// if the input to the viewer is deleted then refresh to avoid the display of stale elements
113
if (inputDeleted(runnables))
114                 return;
115
116             processDelta(event.getDelta(), runnables);
117         } catch (JavaModelException e) {
118             JavaPlugin.log(e);
119         } finally {
120             executeRunnables(runnables);
121         }
122     }
123
124     protected final void executeRunnables(final Collection JavaDoc runnables) {
125
126         // now post all collected runnables
127
Control ctrl= fViewer.getControl();
128         if (ctrl != null && !ctrl.isDisposed()) {
129             //Are we in the UIThread? If so spin it until we are done
130
if (ctrl.getDisplay().getThread() == Thread.currentThread()) {
131                 runUpdates(runnables);
132             } else {
133                 synchronized (this) {
134                     if (fPendingUpdates == null) {
135                         fPendingUpdates= runnables;
136                     } else {
137                         fPendingUpdates.addAll(runnables);
138                     }
139                 }
140                 ctrl.getDisplay().asyncExec(new Runnable JavaDoc(){
141                     public void run() {
142                         runPendingUpdates();
143                     }
144                 });
145             }
146         }
147     }
148     
149     /**
150      * Run all of the runnables that are the widget updates. Must be called in the display thread.
151      */

152     public void runPendingUpdates() {
153         Collection JavaDoc pendingUpdates;
154         synchronized (this) {
155             pendingUpdates= fPendingUpdates;
156             fPendingUpdates= null;
157         }
158         if (pendingUpdates != null && fViewer != null) {
159             Control control = fViewer.getControl();
160             if (control != null && !control.isDisposed()) {
161                 runUpdates(pendingUpdates);
162             }
163         }
164     }
165     
166     private void runUpdates(Collection JavaDoc runnables) {
167         Iterator JavaDoc runnableIterator = runnables.iterator();
168         while (runnableIterator.hasNext()){
169             ((Runnable JavaDoc) runnableIterator.next()).run();
170         }
171     }
172     
173
174     private boolean inputDeleted(Collection JavaDoc runnables) {
175         if (fInput == null)
176             return false;
177         if ((fInput instanceof IJavaElement) && ((IJavaElement) fInput).exists())
178             return false;
179         if ((fInput instanceof IResource) && ((IResource) fInput).exists())
180             return false;
181         if (fInput instanceof WorkingSetModel)
182             return false;
183         if (fInput instanceof IWorkingSet) // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=156239
184
return false;
185         postRefresh(fInput, ORIGINAL, fInput, runnables);
186         return true;
187     }
188
189     /* (non-Javadoc)
190      * Method declared on IContentProvider.
191      */

192     public void dispose() {
193         super.dispose();
194         JavaCore.removeElementChangedListener(this);
195         JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
196     }
197
198     /* (non-Javadoc)
199      * @see org.eclipse.jdt.ui.StandardJavaElementContentProvider#getPackageFragmentRootContent(org.eclipse.jdt.core.IPackageFragmentRoot)
200      */

201     protected Object JavaDoc[] getPackageFragmentRootContent(IPackageFragmentRoot root) throws JavaModelException {
202         if (fIsFlatLayout) {
203             return super.getPackageFragmentRootContent(root);
204         }
205         
206         // hierarchical package mode
207
ArrayList JavaDoc result= new ArrayList JavaDoc();
208         getHierarchicalPackageChildren(root, null, result);
209         if (!isProjectPackageFragmentRoot(root)) {
210             Object JavaDoc[] nonJavaResources= root.getNonJavaResources();
211             for (int i= 0; i < nonJavaResources.length; i++) {
212                 result.add(nonJavaResources[i]);
213             }
214         }
215         return result.toArray();
216     }
217     
218     /* (non-Javadoc)
219      * @see org.eclipse.jdt.ui.StandardJavaElementContentProvider#getPackageContent(org.eclipse.jdt.core.IPackageFragment)
220      */

221     protected Object JavaDoc[] getPackageContent(IPackageFragment fragment) throws JavaModelException {
222         if (fIsFlatLayout) {
223             return super.getPackageContent(fragment);
224         }
225         
226         // hierarchical package mode
227
ArrayList JavaDoc result= new ArrayList JavaDoc();
228         
229         getHierarchicalPackageChildren((IPackageFragmentRoot) fragment.getParent(), fragment, result);
230         Object JavaDoc[] nonPackages= super.getPackageContent(fragment);
231         if (result.isEmpty())
232             return nonPackages;
233         for (int i= 0; i < nonPackages.length; i++) {
234             result.add(nonPackages[i]);
235         }
236         return result.toArray();
237     }
238     
239     /* (non-Javadoc)
240      * @see org.eclipse.jdt.ui.StandardJavaElementContentProvider#getFolderContent(org.eclipse.core.resources.IFolder)
241      */

242     protected Object JavaDoc[] getFolderContent(IFolder folder) throws CoreException {
243         if (fIsFlatLayout) {
244             return super.getFolderContent(folder);
245         }
246         
247         // hierarchical package mode
248
ArrayList JavaDoc result= new ArrayList JavaDoc();
249         
250         getHierarchicalPackagesInFolder(folder, result);
251         Object JavaDoc[] others= super.getFolderContent(folder);
252         if (result.isEmpty())
253             return others;
254         for (int i= 0; i < others.length; i++) {
255             result.add(others[i]);
256         }
257         return result.toArray();
258     }
259     
260     
261     public Object JavaDoc[] getChildren(Object JavaDoc parentElement) {
262         try {
263             if (parentElement instanceof IJavaModel)
264                 return concatenate(getJavaProjects((IJavaModel)parentElement), getNonJavaProjects((IJavaModel)parentElement));
265
266             if (parentElement instanceof PackageFragmentRootContainer)
267                 return getContainerPackageFragmentRoots((PackageFragmentRootContainer)parentElement);
268                 
269             if (parentElement instanceof IProject)
270                 return ((IProject)parentElement).members();
271             
272             return super.getChildren(parentElement);
273         } catch (CoreException e) {
274             return NO_CHILDREN;
275         }
276     }
277     
278     /* (non-Javadoc)
279      * @see org.eclipse.jdt.ui.StandardJavaElementContentProvider#getPackageFragmentRoots(org.eclipse.jdt.core.IJavaProject)
280      */

281     protected Object JavaDoc[] getPackageFragmentRoots(IJavaProject project) throws JavaModelException {
282         if (!project.getProject().isOpen())
283             return NO_CHILDREN;
284             
285         List JavaDoc result= new ArrayList JavaDoc();
286
287         boolean addJARContainer= false;
288         
289         IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
290         for (int i= 0; i < roots.length; i++) {
291             IPackageFragmentRoot root= roots[i];
292             IClasspathEntry classpathEntry= root.getRawClasspathEntry();
293             int entryKind= classpathEntry.getEntryKind();
294             if (entryKind == IClasspathEntry.CPE_CONTAINER) {
295                 // all ClassPathContainers are added later
296
} else if (fShowLibrariesNode && (entryKind == IClasspathEntry.CPE_LIBRARY || entryKind == IClasspathEntry.CPE_VARIABLE)) {
297                 addJARContainer= true;
298             } else {
299                 if (isProjectPackageFragmentRoot(root)) {
300                     // filter out package fragments that correspond to projects and
301
// replace them with the package fragments directly
302
Object JavaDoc[] fragments= getPackageFragmentRootContent(root);
303                     for (int j= 0; j < fragments.length; j++) {
304                         result.add(fragments[j]);
305                     }
306                 } else {
307                     result.add(root);
308                 }
309             }
310         }
311         
312         if (addJARContainer) {
313             result.add(new LibraryContainer(project));
314         }
315         
316         // separate loop to make sure all containers are on the classpath
317
IClasspathEntry[] rawClasspath= project.getRawClasspath();
318         for (int i= 0; i < rawClasspath.length; i++) {
319             IClasspathEntry classpathEntry= rawClasspath[i];
320             if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
321                 result.add(new ClassPathContainer(project, classpathEntry));
322             }
323         }
324         Object JavaDoc[] resources= project.getNonJavaResources();
325         for (int i= 0; i < resources.length; i++) {
326             result.add(resources[i]);
327         }
328         return result.toArray();
329     }
330
331     private Object JavaDoc[] getContainerPackageFragmentRoots(PackageFragmentRootContainer container) {
332         return container.getChildren();
333     }
334
335     private Object JavaDoc[] getNonJavaProjects(IJavaModel model) throws JavaModelException {
336         return model.getNonJavaResources();
337     }
338
339     protected Object JavaDoc internalGetParent(Object JavaDoc element) {
340         if (!fIsFlatLayout && element instanceof IPackageFragment) {
341             return getHierarchicalPackageParent((IPackageFragment) element);
342         } else if (element instanceof IPackageFragmentRoot) {
343             // since we insert logical package containers we have to fix
344
// up the parent for package fragment roots so that they refer
345
// to the container and containers refer to the project
346
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
347             
348             try {
349                 IClasspathEntry entry= root.getRawClasspathEntry();
350                 int entryKind= entry.getEntryKind();
351                 if (entryKind == IClasspathEntry.CPE_CONTAINER) {
352                     return new ClassPathContainer(root.getJavaProject(), entry);
353                 } else if (fShowLibrariesNode && (entryKind == IClasspathEntry.CPE_LIBRARY || entryKind == IClasspathEntry.CPE_VARIABLE)) {
354                     return new LibraryContainer(root.getJavaProject());
355                 }
356             } catch (JavaModelException e) {
357                 // fall through
358
}
359         } else if (element instanceof PackageFragmentRootContainer) {
360             return ((PackageFragmentRootContainer)element).getJavaProject();
361         }
362         return super.internalGetParent(element);
363     }
364
365     /* (non-Javadoc)
366      * Method declared on IContentProvider.
367      */

368     public void inputChanged(Viewer viewer, Object JavaDoc oldInput, Object JavaDoc newInput) {
369         super.inputChanged(viewer, oldInput, newInput);
370         fViewer= (TreeViewer)viewer;
371         if (oldInput == null && newInput != null) {
372             JavaCore.addElementChangedListener(this);
373         } else if (oldInput != null && newInput == null) {
374             JavaCore.removeElementChangedListener(this);
375         }
376         fInput= newInput;
377     }
378
379     // hierarchical packages
380
/**
381      * Returns the hierarchical packages inside a given fragment or root.
382      * @param parent The parent package fragment root
383      * @param fragment The package to get the children for or 'null' to get the children of the root.
384      * @param result Collection where the resulting elements are added
385      * @throws JavaModelException
386      */

387     private void getHierarchicalPackageChildren(IPackageFragmentRoot parent, IPackageFragment fragment, Collection JavaDoc result) throws JavaModelException {
388         IJavaElement[] children= parent.getChildren();
389         String JavaDoc prefix= fragment != null ? fragment.getElementName() + '.' : ""; //$NON-NLS-1$
390
int prefixLen= prefix.length();
391         for (int i= 0; i < children.length; i++) {
392             IPackageFragment curr= (IPackageFragment) children[i];
393             String JavaDoc name= curr.getElementName();
394             if (name.startsWith(prefix) && name.length() > prefixLen && name.indexOf('.', prefixLen) == -1) {
395                 if (fFoldPackages) {
396                     curr= getFolded(children, curr);
397                 }
398                 result.add(curr);
399             } else if (fragment == null && curr.isDefaultPackage()) {
400                 result.add(curr);
401             }
402         }
403     }
404     
405     /**
406      * Returns the hierarchical packages inside a given folder.
407      * @param folder The parent folder
408      * @param result Collection where the resulting elements are added
409      * @throws CoreException thrown when elements could not be accessed
410      */

411     private void getHierarchicalPackagesInFolder(IFolder folder, Collection JavaDoc result) throws CoreException {
412         IResource[] resources= folder.members();
413         for (int i= 0; i < resources.length; i++) {
414             IResource resource= resources[i];
415             if (resource instanceof IFolder) {
416                 IFolder curr= (IFolder) resource;
417                 IJavaElement element= JavaCore.create(curr);
418                 if (element instanceof IPackageFragment) {
419                     if (fFoldPackages) {
420                         IPackageFragment fragment= (IPackageFragment) element;
421                         IPackageFragmentRoot root= (IPackageFragmentRoot) fragment.getParent();
422                         element= getFolded(root.getChildren(), fragment);
423                     }
424                     result.add(element);
425                 }
426             }
427         }
428     }
429
430     public Object JavaDoc getHierarchicalPackageParent(IPackageFragment child) {
431         String JavaDoc name= child.getElementName();
432         IPackageFragmentRoot parent= (IPackageFragmentRoot) child.getParent();
433         int index= name.lastIndexOf('.');
434         if (index != -1) {
435             String JavaDoc realParentName= name.substring(0, index);
436             IPackageFragment element= parent.getPackageFragment(realParentName);
437             if (element.exists()) {
438                 try {
439                     if (fFoldPackages && isEmpty(element) && findSinglePackageChild(element, parent.getChildren()) != null) {
440                         return getHierarchicalPackageParent(element);
441                     }
442                 } catch (JavaModelException e) {
443                     // ignore
444
}
445                 return element;
446             } else { // bug 65240
447
IResource resource= element.getResource();
448                 if (resource != null) {
449                     return resource;
450                 }
451             }
452         }
453         if (parent.getResource() instanceof IProject) {
454             return parent.getJavaProject();
455         }
456         return parent;
457     }
458     
459     private static IPackageFragment getFolded(IJavaElement[] children, IPackageFragment pack) throws JavaModelException {
460         while (isEmpty(pack)) {
461             IPackageFragment collapsed= findSinglePackageChild(pack, children);
462             if (collapsed == null) {
463                 return pack;
464             }
465             pack= collapsed;
466         }
467         return pack;
468     }
469         
470     private static boolean isEmpty(IPackageFragment fragment) throws JavaModelException {
471         return !fragment.containsJavaResources() && fragment.getNonJavaResources().length == 0;
472     }
473     
474     private static IPackageFragment findSinglePackageChild(IPackageFragment fragment, IJavaElement[] children) {
475         String JavaDoc prefix= fragment.getElementName() + '.';
476         int prefixLen= prefix.length();
477         IPackageFragment found= null;
478         for (int i= 0; i < children.length; i++) {
479             IJavaElement element= children[i];
480             String JavaDoc name= element.getElementName();
481             if (name.startsWith(prefix) && name.length() > prefixLen && name.indexOf('.', prefixLen) == -1) {
482                 if (found == null) {
483                     found= (IPackageFragment) element;
484                 } else {
485                     return null;
486                 }
487             }
488         }
489         return found;
490     }
491     
492     // ------ delta processing ------
493

494     /**
495      * Processes a delta recursively. When more than two children are affected the
496      * tree is fully refreshed starting at this node.
497      *
498      * @param delta the delta to process
499      * @param runnables the resulting view changes as runnables (type {@link Runnable})
500      * @return true is returned if the conclusion is to refresh a parent of an element. In that case no siblings need
501      * to be processed
502      * @throws JavaModelException thrown when the access to an element failed
503      */

504     private boolean processDelta(IJavaElementDelta delta, Collection JavaDoc runnables) throws JavaModelException {
505     
506         int kind= delta.getKind();
507         int flags= delta.getFlags();
508         IJavaElement element= delta.getElement();
509         int elementType= element.getElementType();
510         
511         
512         if (elementType != IJavaElement.JAVA_MODEL && elementType != IJavaElement.JAVA_PROJECT) {
513             IJavaProject proj= element.getJavaProject();
514             if (proj == null || !proj.getProject().isOpen()) // TODO: Not needed if parent already did the 'open' check!
515
return false;
516         }
517         
518         if (!fIsFlatLayout && elementType == IJavaElement.PACKAGE_FRAGMENT) {
519             if (kind == IJavaElementDelta.REMOVED) {
520                 final Object JavaDoc parent = getHierarchicalPackageParent((IPackageFragment) element);
521                 if (parent instanceof IPackageFragmentRoot) {
522                     postRemove(element, runnables);
523                     return false;
524                 } else {
525                     postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
526                     return true;
527                 }
528             } else if (kind == IJavaElementDelta.ADDED) {
529                 final Object JavaDoc parent = getHierarchicalPackageParent((IPackageFragment) element);
530                 if (parent instanceof IPackageFragmentRoot) {
531                     postAdd(parent, element, runnables);
532                     return false;
533                 } else {
534                     postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
535                     return true;
536                 }
537             }
538             handleAffectedChildren(delta, element, runnables);
539             return false;
540         }
541         
542         if (elementType == IJavaElement.COMPILATION_UNIT) {
543             ICompilationUnit cu= (ICompilationUnit) element;
544             if (!JavaModelUtil.isPrimary(cu)) {
545                 return false;
546             }
547                         
548             if (!getProvideMembers() && cu.isWorkingCopy() && kind == IJavaElementDelta.CHANGED) {
549                 return false;
550             }
551             
552             if ((kind == IJavaElementDelta.CHANGED) && !isStructuralCUChange(flags)) {
553                 return false; // test moved ahead
554
}
555             
556             if (!isOnClassPath(cu)) { // TODO: isOnClassPath expensive! Should be put after all cheap tests
557
return false;
558             }
559             
560         }
561         
562         if (elementType == IJavaElement.JAVA_PROJECT) {
563             // handle open and closing of a project
564
if ((flags & (IJavaElementDelta.F_CLOSED | IJavaElementDelta.F_OPENED)) != 0) {
565                 postRefresh(element, ORIGINAL, element, runnables);
566                 return false;
567             }
568             // if the raw class path has changed we refresh the entire project
569
if ((flags & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0 || isManifestChange(delta)) {
570                 postRefresh(element, ORIGINAL, element, runnables);
571                 return false;
572             }
573             // if added it could be that the corresponding IProject is already shown. Remove it first.
574
// bug 184296
575
if (kind == IJavaElementDelta.ADDED) {
576                 postRemove(element.getResource(), runnables);
577                 postAdd(element.getParent(), element, runnables);
578                 return false;
579             }
580         }
581     
582         if (kind == IJavaElementDelta.REMOVED) {
583             Object JavaDoc parent= internalGetParent(element);
584             if (element instanceof IPackageFragment) {
585                 // refresh package fragment root to allow filtering empty (parent) packages: bug 72923
586
if (fViewer.testFindItem(parent) != null)
587                     postRefresh(parent, PARENT, element, runnables);
588                 return true;
589             }
590             
591             postRemove(element, runnables);
592             if (parent instanceof IPackageFragment)
593                 postUpdateIcon((IPackageFragment)parent, runnables);
594             // we are filtering out empty subpackages, so we
595
// a package becomes empty we remove it from the viewer.
596
if (isPackageFragmentEmpty(element.getParent())) {
597                 if (fViewer.testFindItem(parent) != null)
598                     postRefresh(internalGetParent(parent), GRANT_PARENT, element, runnables);
599                 return true;
600             }
601             return false;
602         }
603     
604         if (kind == IJavaElementDelta.ADDED) {
605             Object JavaDoc parent= internalGetParent(element);
606             // we are filtering out empty subpackages, so we
607
// have to handle additions to them specially.
608
if (parent instanceof IPackageFragment) {
609                 Object JavaDoc grandparent= internalGetParent(parent);
610                 // 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
611
// avoid posting a refresh to an invisible parent
612
if (parent.equals(fInput)) {
613                     postRefresh(parent, PARENT, element, runnables);
614                 } else {
615                     // refresh from grandparent if parent isn't visible yet
616
if (fViewer.testFindItem(parent) == null)
617                         postRefresh(grandparent, GRANT_PARENT, element, runnables);
618                     else {
619                         postRefresh(parent, PARENT, element, runnables);
620                     }
621                 }
622                 return true;
623             } else {
624                 postAdd(parent, element, runnables);
625             }
626         }
627     
628         if (elementType == IJavaElement.COMPILATION_UNIT) {
629             if (kind == IJavaElementDelta.CHANGED) {
630                 // isStructuralCUChange already performed above
631
postRefresh(element, ORIGINAL, element, runnables);
632                 updateSelection(delta, runnables);
633             }
634             return false;
635         }
636         // no changes possible in class files
637
if (elementType == IJavaElement.CLASS_FILE)
638             return false;
639         
640         
641         if (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT) {
642             // the contents of an external JAR has changed
643
if ((flags & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
644                 postRefresh(element, ORIGINAL, element, runnables);
645                 return false;
646             }
647             // the source attachment of a JAR has changed
648
if ((flags & (IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED)) != 0)
649                 postUpdateIcon(element, runnables);
650             
651             if (isClassPathChange(delta)) {
652                  // throw the towel and do a full refresh of the affected java project.
653
postRefresh(element.getJavaProject(), PROJECT, element, runnables);
654                 return true;
655             }
656         }
657         handleAffectedChildren(delta, element, runnables);
658         return false;
659     }
660     
661     private boolean isManifestChange(IJavaElementDelta delta) {
662         // temporary 3.3.1 workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=189987
663
IResourceDelta[] resourceDeltas= delta.getResourceDeltas();
664         if (resourceDeltas != null) {
665             for (int i= 0; i < resourceDeltas.length; i++) {
666                 IResourceDelta rDelta= resourceDeltas[i];
667                 if (rDelta.getResource().getName().equals("META-INF") && rDelta.findMember(new Path("MANIFEST.MF")) != null) { //$NON-NLS-1$//$NON-NLS-2$
668
return true;
669                 }
670             }
671         }
672         return false;
673     }
674
675     private static boolean isStructuralCUChange(int flags) {
676         // No refresh on working copy creation (F_PRIMARY_WORKING_COPY)
677
return ((flags & IJavaElementDelta.F_CHILDREN) != 0) || ((flags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_FINE_GRAINED)) == IJavaElementDelta.F_CONTENT);
678     }
679     
680     /* package */ void handleAffectedChildren(IJavaElementDelta delta, IJavaElement element, Collection JavaDoc runnables) throws JavaModelException {
681         int count= 0;
682         
683         IResourceDelta[] resourceDeltas= delta.getResourceDeltas();
684         if (resourceDeltas != null) {
685             for (int i= 0; i < resourceDeltas.length; i++) {
686                 int kind= resourceDeltas[i].getKind();
687                 if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
688                     count++;
689                 }
690             }
691         }
692         IJavaElementDelta[] affectedChildren= delta.getAffectedChildren();
693         for (int i= 0; i < affectedChildren.length; i++) {
694             int kind= affectedChildren[i].getKind();
695             if (kind == IJavaElementDelta.ADDED || kind == IJavaElementDelta.REMOVED) {
696                 count++;
697             }
698         }
699
700         if (count > 1) {
701             // more than one child changed, refresh from here downwards
702
if (element instanceof IPackageFragment) {
703                 // a package fragment might become non empty refresh from the parent
704
IJavaElement parent= (IJavaElement) internalGetParent(element);
705                 // 1GE8SI6: ITPJUI:WIN98 - Rename is not shown in Packages View
706
// avoid posting a refresh to an invisible parent
707
if (element.equals(fInput)) {
708                     postRefresh(element, ORIGINAL, element, runnables);
709                 } else {
710                     postRefresh(parent, PARENT, element, runnables);
711                 }
712             } else if (element instanceof IPackageFragmentRoot) {
713                 Object JavaDoc toRefresh= internalGetParent(element);
714                 postRefresh(toRefresh, ORIGINAL, toRefresh, runnables);
715             } else {
716                 postRefresh(element, ORIGINAL, element, runnables);
717             }
718             return;
719         }
720         if (resourceDeltas != null) {
721             for (int i= 0; i < resourceDeltas.length; i++) {
722                 if (processResourceDelta(resourceDeltas[i], element, runnables)) {
723                     return; // early return, element got refreshed
724
}
725             }
726         }
727         for (int i= 0; i < affectedChildren.length; i++) {
728             if (processDelta(affectedChildren[i], runnables)) {
729                 return; // early return, element got refreshed
730
}
731         }
732     }
733     
734     protected void processAffectedChildren(IJavaElementDelta[] affectedChildren, Collection JavaDoc runnables) throws JavaModelException {
735         for (int i= 0; i < affectedChildren.length; i++) {
736             processDelta(affectedChildren[i], runnables);
737         }
738     }
739
740     private boolean isOnClassPath(ICompilationUnit element) {
741         IJavaProject project= element.getJavaProject();
742         if (project == null || !project.exists())
743             return false;
744         return project.isOnClasspath(element);
745     }
746
747     /**
748      * Updates the selection. It finds newly added elements
749      * and selects them.
750      * @param delta the delta to process
751      * @param runnables the resulting view changes as runnables (type {@link Runnable})
752      */

753     private void updateSelection(IJavaElementDelta delta, Collection JavaDoc runnables) {
754         final IJavaElement addedElement= findAddedElement(delta);
755         if (addedElement != null) {
756             final StructuredSelection selection= new StructuredSelection(addedElement);
757             runnables.add(new Runnable JavaDoc() {
758                 public void run() {
759                     // 19431
760
// if the item is already visible then select it
761
if (fViewer.testFindItem(addedElement) != null)
762                         fViewer.setSelection(selection);
763                 }
764             });
765         }
766     }
767
768     private IJavaElement findAddedElement(IJavaElementDelta delta) {
769         if (delta.getKind() == IJavaElementDelta.ADDED)
770             return delta.getElement();
771         
772         IJavaElementDelta[] affectedChildren= delta.getAffectedChildren();
773         for (int i= 0; i < affectedChildren.length; i++)
774             return findAddedElement(affectedChildren[i]);
775             
776         return null;
777     }
778
779     /**
780      * Updates the package icon
781      * @param element the element to update
782      * @param runnables the resulting view changes as runnables (type {@link Runnable})
783      */

784      private void postUpdateIcon(final IJavaElement element, Collection JavaDoc runnables) {
785          runnables.add(new Runnable JavaDoc() {
786             public void run() {
787                 // 1GF87WR: ITPUI:ALL - SWTEx + NPE closing a workbench window.
788
fViewer.update(element, new String JavaDoc[]{IBasicPropertyConstants.P_IMAGE});
789             }
790         });
791      }
792
793     /**
794      * Process a resource delta.
795      *
796      * @param delta the delta to process
797      * @param parent the parent
798      * @param runnables the resulting view changes as runnables (type {@link Runnable})
799      * @return true if the parent got refreshed
800      */

801     private boolean processResourceDelta(IResourceDelta delta, Object JavaDoc parent, Collection JavaDoc runnables) {
802         int status= delta.getKind();
803         int flags= delta.getFlags();
804         
805         IResource resource= delta.getResource();
806         // filter out changes affecting the output folder
807
if (resource == null)
808             return false;
809             
810         // this could be optimized by handling all the added children in the parent
811
if ((status & IResourceDelta.REMOVED) != 0) {
812             if (parent instanceof IPackageFragment) {
813                 // refresh one level above to deal with empty package filtering properly
814
postRefresh(internalGetParent(parent), PARENT, parent, runnables);
815                 return true;
816             } else
817                 postRemove(resource, runnables);
818         }
819         if ((status & IResourceDelta.ADDED) != 0) {
820             if (parent instanceof IPackageFragment) {
821                 // refresh one level above to deal with empty package filtering properly
822
postRefresh(internalGetParent(parent), PARENT, parent, runnables);
823                 return true;
824             } else
825                 postAdd(parent, resource, runnables);
826         }
827         // open/close state change of a project
828
if ((flags & IResourceDelta.OPEN) != 0) {
829             postProjectStateChanged(internalGetParent(parent), runnables);
830             return true;
831         }
832         IResourceDelta[] resourceDeltas= delta.getAffectedChildren();
833         for (int i= 0; i < resourceDeltas.length; i++) {
834             if (processResourceDelta(resourceDeltas[i], resource, runnables)) {
835                 return false; // early return, element got refreshed
836
}
837         }
838         return false;
839     }
840     
841     public void setIsFlatLayout(boolean state) {
842         fIsFlatLayout= state;
843     }
844     
845     public void setShowLibrariesNode(boolean state) {
846         fShowLibrariesNode= state;
847     }
848     
849     private void postRefresh(Object JavaDoc root, int relation, Object JavaDoc affectedElement, Collection JavaDoc runnables) {
850         // JFace doesn't refresh when object isn't part of the viewer
851
// Therefore move the refresh start down to the viewer's input
852
if (isParent(root, fInput))
853             root= fInput;
854         List JavaDoc toRefresh= new ArrayList JavaDoc(1);
855         toRefresh.add(root);
856         augmentElementToRefresh(toRefresh, relation, affectedElement);
857         postRefresh(toRefresh, true, runnables);
858     }
859     
860     protected void augmentElementToRefresh(List JavaDoc toRefresh, int relation, Object JavaDoc affectedElement) {
861     }
862
863     private boolean isParent(Object JavaDoc root, Object JavaDoc child) {
864         Object JavaDoc parent= getParent(child);
865         if (parent == null)
866             return false;
867         if (parent.equals(root))
868             return true;
869         return isParent(root, parent);
870     }
871
872     protected void postRefresh(final List JavaDoc toRefresh, final boolean updateLabels, Collection JavaDoc runnables) {
873         runnables.add(new Runnable JavaDoc() {
874             public void run() {
875                 for (Iterator JavaDoc iter= toRefresh.iterator(); iter.hasNext();) {
876                     fViewer.refresh(iter.next(), updateLabels);
877                 }
878             }
879         });
880     }
881
882     protected void postAdd(final Object JavaDoc parent, final Object JavaDoc element, Collection JavaDoc runnables) {
883         runnables.add(new Runnable JavaDoc() {
884             public void run() {
885                 if (fViewer.testFindItem(element) == null)
886                     fViewer.add(parent, element);
887                 }
888         });
889     }
890
891     protected void postRemove(final Object JavaDoc element, Collection JavaDoc runnables) {
892         runnables.add(new Runnable JavaDoc() {
893             public void run() {
894                 fViewer.remove(element);
895             }
896         });
897     }
898
899     protected void postProjectStateChanged(final Object JavaDoc root, Collection JavaDoc runnables) {
900         runnables.add(new Runnable JavaDoc() {
901             public void run() {
902                 fViewer.refresh(root, true);
903                 // trigger a synthetic selection change so that action refresh their
904
// enable state.
905
fViewer.setSelection(fViewer.getSelection());
906             }
907         });
908     }
909     
910     
911     /*
912      * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
913      */

914     public void propertyChange(PropertyChangeEvent event) {
915         if (arePackagesFoldedInHierarchicalLayout() != fFoldPackages){
916             fFoldPackages= arePackagesFoldedInHierarchicalLayout();
917             if (fViewer != null && !fViewer.getControl().isDisposed()) {
918                 fViewer.getControl().setRedraw(false);
919                 Object JavaDoc[] expandedObjects= fViewer.getExpandedElements();
920                 fViewer.refresh();
921                 fViewer.setExpandedElements(expandedObjects);
922                 fViewer.getControl().setRedraw(true);
923             }
924         }
925     }
926 }
927
Popular Tags