1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
21 import net.sourceforge.phpdt.core.ElementChangedEvent;
22 import net.sourceforge.phpdt.core.IClasspathEntry;
23 import net.sourceforge.phpdt.core.IElementChangedListener;
24 import net.sourceforge.phpdt.core.IJavaElement;
25 import net.sourceforge.phpdt.core.IJavaElementDelta;
26 import net.sourceforge.phpdt.core.IJavaModel;
27 import net.sourceforge.phpdt.core.IJavaProject;
28 import net.sourceforge.phpdt.core.JavaCore;
29 import net.sourceforge.phpdt.core.JavaModelException;
30 import net.sourceforge.phpdt.internal.core.util.Util;
31 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
32 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
34 import org.eclipse.core.resources.IFile;
35 import org.eclipse.core.resources.IProject;
36 import org.eclipse.core.resources.IResource;
37 import org.eclipse.core.resources.IResourceChangeEvent;
38 import org.eclipse.core.resources.IResourceChangeListener;
39 import org.eclipse.core.resources.IResourceDelta;
40 import org.eclipse.core.resources.IResourceDeltaVisitor;
41 import org.eclipse.core.resources.IWorkspace;
42 import org.eclipse.core.resources.ResourcesPlugin;
43 import org.eclipse.core.runtime.CoreException;
44 import org.eclipse.core.runtime.IPath;
45 import org.eclipse.core.runtime.ISafeRunnable;
46 import org.eclipse.core.runtime.Platform;
47 import org.eclipse.core.runtime.QualifiedName;
51 * This class is used by <code>JavaModelManager</code> to convert
52 * <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
53 * It also does some processing on the <code>JavaElement</code>s involved
54 * (e.g. closing them or updating classpaths).
56 public class DeltaProcessor implements IResourceChangeListener {
58 final static int IGNORE = 0;
59 final static int SOURCE = 1;
60 final static int BINARY = 2;
62 final static String EXTERNAL_JAR_ADDED = "external jar added"; //$NON-NLS-1$
63 final static String EXTERNAL_JAR_REMOVED = "external jar removed"; //$NON-NLS-1$
64 final static String EXTERNAL_JAR_CHANGED = "external jar changed"; //$NON-NLS-1$
65 final static String EXTERNAL_JAR_UNCHANGED = "external jar unchanged"; //$NON-NLS-1$
66 final static String INTERNAL_JAR_IGNORE = "internal jar ignore"; //$NON-NLS-1$
68 private final static int NON_JAVA_RESOURCE = -1;
69 public static boolean DEBUG = false;
70 public static boolean VERBOSE = false;
72 public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with ElementChangedEvent event masks
74 * The <code>JavaElementDelta</code> corresponding to the <code>IResourceDelta</code> being translated.
76 protected JavaElementDelta currentDelta;
78 // protected IndexManager indexManager = new IndexManager();
80 /* A table from IPath (from a classpath entry) to RootInfo */
83 /* A table from IPath (from a classpath entry) to ArrayList of RootInfo
84 * Used when an IPath corresponds to more than one root */
87 /* Whether the roots tables should be recomputed */
88 public boolean rootsAreStale = true;
90 /* A table from IPath (from a classpath entry) to RootInfo
91 * from the last time the delta processor was invoked. */
94 /* A table from IPath (from a classpath entry) to ArrayList of RootInfo
95 * from the last time the delta processor was invoked.
96 * Used when an IPath corresponds to more than one root */
99 /* A table from IPath (a source attachment path from a classpath entry) to IPath (a root path) */
100 Map sourceAttachments;
102 /* The java element that was last created (see createElement(IResource)).
103 * This is used as a stack of java elements (using getParent() to pop it, and
104 * using the various get*(...) to push it. */
105 Openable currentElement;
107 * Queue of deltas created explicily by the Java Model that
108 * have yet to be fired.
110 public ArrayList javaModelDeltas= new ArrayList();
112 * Queue of reconcile deltas on working copies that have yet to be fired.
113 * This is a table form IWorkingCopy to IJavaElementDelta
115 public HashMap reconcileDeltas = new HashMap();
118 * Turns delta firing on/off. By default it is on.
120 private boolean isFiring= true;
123 public HashMap externalTimeStamps = new HashMap();
124 public HashSet projectsToUpdate = new HashSet();
125 // list of root projects which namelookup caches need to be updated for dependents
126 // TODO: (jerome) is it needed? projectsToUpdate might be sufficient
127 public HashSet projectsForDependentNamelookupRefresh = new HashSet();
130 * The global state of delta processing.
132 private DeltaProcessingState state;
135 * The Java model manager
137 private JavaModelManager manager;
139 /* A table from IJavaProject to an array of IPackageFragmentRoot.
140 * This table contains the pkg fragment roots of the project that are being deleted.
145 * A list of IJavaElement used as a scope for external archives refresh during POST_CHANGE.
146 * This is null if no refresh is needed.
148 HashSet refreshedElements;
154 OutputsInfo(IPath[] paths, int[] traverseModes, int outputCount) {
156 this.traverseModes = traverseModes;
157 this.outputCount = outputCount;
159 public String toString() {
160 if (this.paths == null) return "<none>"; //$NON-NLS-1$
161 StringBuffer buffer = new StringBuffer();
162 for (int i = 0; i < this.outputCount; i++) {
163 buffer.append("path="); //$NON-NLS-1$
164 buffer.append(this.paths[i].toString());
165 buffer.append("\n->traverse="); //$NON-NLS-1$
166 switch (this.traverseModes[i]) {
168 buffer.append("BINARY"); //$NON-NLS-1$
171 buffer.append("IGNORE"); //$NON-NLS-1$
174 buffer.append("SOURCE"); //$NON-NLS-1$
177 buffer.append("<unknown>"); //$NON-NLS-1$
179 if (i+1 < this.outputCount) {
183 return buffer.toString();
187 IJavaProject project;
189 char[][] exclusionPatterns;
190 RootInfo(IJavaProject project, IPath rootPath, char[][] exclusionPatterns) {
191 this.project = project;
192 this.rootPath = rootPath;
193 this.exclusionPatterns = exclusionPatterns;
195 boolean isRootOfProject(IPath path) {
196 return this.rootPath.equals(path) && this.project.getProject().getFullPath().isPrefixOf(path);
198 public String toString() {
199 StringBuffer buffer = new StringBuffer("project="); //$NON-NLS-1$
200 if (this.project == null) {
201 buffer.append("null"); //$NON-NLS-1$
203 buffer.append(this.project.getElementName());
205 buffer.append("\npath="); //$NON-NLS-1$
206 if (this.rootPath == null) {
207 buffer.append("null"); //$NON-NLS-1$
209 buffer.append(this.rootPath.toString());
211 buffer.append("\nexcluding="); //$NON-NLS-1$
212 if (this.exclusionPatterns == null) {
213 buffer.append("null"); //$NON-NLS-1$
215 for (int i = 0, length = this.exclusionPatterns.length; i < length; i++) {
216 buffer.append(new String(this.exclusionPatterns[i]));
218 buffer.append("|"); //$NON-NLS-1$
222 return buffer.toString();
226 // DeltaProcessor(JavaModelManager manager) {
227 // this.manager = manager;
231 * Type of event that should be processed no matter what the real event type is.
233 public int overridenEventType = -1;
235 public DeltaProcessor(DeltaProcessingState state, JavaModelManager manager) {
237 this.manager = manager;
240 * Adds the dependents of the given project to the list of the projects
243 // void addDependentProjects(IPath projectPath, HashSet result) {
245 // IJavaProject[] projects = this.manager.getJavaModel().getJavaProjects();
246 // for (int i = 0, length = projects.length; i < length; i++) {
247 // IJavaProject project = projects[i];
248 // IClasspathEntry[] classpath = ((JavaProject)project).getExpandedClasspath(true);
249 // for (int j = 0, length2 = classpath.length; j < length2; j++) {
250 // IClasspathEntry entry = classpath[j];
251 // if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
252 // && entry.getPath().equals(projectPath)) {
253 // result.add(project);
257 // } catch (JavaModelException e) {
261 * Adds the given element to the list of elements used as a scope for external jars refresh.
263 public void addForRefresh(IJavaElement element) {
264 if (this.refreshedElements == null) {
265 this.refreshedElements = new HashSet();
267 this.refreshedElements.add(element);
270 * Adds the given project and its dependents to the list of the projects
273 void addToProjectsToUpdateWithDependents(IProject project) {
274 this.projectsToUpdate.add(JavaCore.create(project));
275 // this.addDependentProjects(project.getFullPath(), this.projectsToUpdate);
279 * Adds the given child handle to its parent's cache of children.
281 protected void addToParentInfo(Openable child) {
283 Openable parent = (Openable) child.getParent();
284 if (parent != null && parent.isOpen()) {
286 JavaElementInfo info = (JavaElementInfo)parent.getElementInfo();
287 info.addChild(child);
288 } catch (JavaModelException e) {
289 // do nothing - we already checked if open
295 * Check all external archive (referenced by given roots, projects or model) status and issue a corresponding root delta.
296 * Also triggers index updates
298 // public void checkExternalArchiveChanges(IJavaElement[] refreshedElements, IProgressMonitor monitor) throws JavaModelException {
300 // for (int i = 0, length = refreshedElements.length; i < length; i++) {
301 // this.addForRefresh(refreshedElements[i]);
303 // boolean hasDelta = this.createExternalArchiveDelta(monitor);
304 // if (monitor != null && monitor.isCanceled()) return;
306 // // force classpath marker refresh of affected projects
307 // JavaModel.flushExternalFileCache();
308 // IJavaElementDelta[] projectDeltas = this.currentDelta.getAffectedChildren();
309 // for (int i = 0, length = projectDeltas.length; i < length; i++) {
310 // IJavaElementDelta delta = projectDeltas[i];
311 // ((JavaProject)delta.getElement()).getResolvedClasspath(
312 // true, // ignoreUnresolvedEntry
313 // true); // generateMarkerOnError
315 // if (this.currentDelta != null) { // if delta has not been fired while creating markers
316 // this.manager.fire(this.currentDelta, JavaModelManager.DEFAULT_CHANGE_EVENT);
320 // this.currentDelta = null;
321 // if (monitor != null) monitor.done();
325 * Check if external archives have changed and create the corresponding deltas.
326 * Returns whether at least on delta was created.
328 // public boolean createExternalArchiveDelta(IProgressMonitor monitor) throws JavaModelException {
330 // if (this.refreshedElements == null) return false;
332 // HashMap externalArchivesStatus = new HashMap();
333 // boolean hasDelta = false;
335 // // find JARs to refresh
336 // HashSet archivePathsToRefresh = new HashSet();
338 // Iterator iterator = this.refreshedElements.iterator();
339 // while (iterator.hasNext()) {
340 // IJavaElement element = (IJavaElement)iterator.next();
341 // switch(element.getElementType()){
342 // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
343 // archivePathsToRefresh.add(element.getPath());
345 // case IJavaElement.JAVA_PROJECT :
346 // IJavaProject project = (IJavaProject) element;
347 // if (!JavaProject.hasJavaNature(project.getProject())) {
348 // // project is not accessible or has lost its Java nature
351 // IClasspathEntry[] classpath = project.getResolvedClasspath(true);
352 // for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
353 // if (classpath[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
354 // archivePathsToRefresh.add(classpath[j].getPath());
358 // case IJavaElement.JAVA_MODEL :
359 // IJavaProject[] projects = manager.getJavaModel().getOldJavaProjectsList();
360 // for (int j = 0, projectsLength = projects.length; j < projectsLength; j++){
361 // project = projects[j];
362 // if (!JavaProject.hasJavaNature(project.getProject())) {
363 // // project is not accessible or has lost its Java nature
366 // classpath = project.getResolvedClasspath(true);
367 // for (int k = 0, cpLength = classpath.length; k < cpLength; k++){
368 // if (classpath[k].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
369 // archivePathsToRefresh.add(classpath[k].getPath());
377 // this.refreshedElements = null;
380 // // perform refresh
381 // IJavaProject[] projects = manager.getJavaModel().getOldJavaProjectsList();
382 // IWorkspaceRoot wksRoot = ResourcesPlugin.getWorkspace().getRoot();
383 // for (int i = 0, length = projects.length; i < length; i++) {
385 // if (monitor != null && monitor.isCanceled()) break;
387 // IJavaProject project = projects[i];
388 // if (!JavaProject.hasJavaNature(project.getProject())) {
389 // // project is not accessible or has lost its Java nature
392 // IClasspathEntry[] entries = project.getResolvedClasspath(true);
393 // for (int j = 0; j < entries.length; j++){
394 // if (entries[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
396 // IPath entryPath = entries[j].getPath();
398 // if (!archivePathsToRefresh.contains(entryPath)) continue; // not supposed to be refreshed
400 // String status = (String)externalArchivesStatus.get(entryPath);
401 // if (status == null){
403 // // compute shared status
404 // Object targetLibrary = JavaModel.getTarget(wksRoot, entryPath, true);
406 // if (targetLibrary == null){ // missing JAR
407 // if (this.externalTimeStamps.containsKey(entryPath)){
408 // this.externalTimeStamps.remove(entryPath);
409 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
410 // // the jar was physically removed: remove the index
411 // indexManager.removeIndex(entryPath);
414 // } else if (targetLibrary instanceof File){ // external JAR
416 // File externalFile = (File)targetLibrary;
418 // // check timestamp to figure if JAR has changed in some way
419 // Long oldTimestamp =(Long) this.externalTimeStamps.get(entryPath);
420 // long newTimeStamp = getTimeStamp(externalFile);
421 // if (oldTimestamp != null){
423 // if (newTimeStamp == 0){ // file doesn't exist
424 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
425 // this.externalTimeStamps.remove(entryPath);
426 // // remove the index
427 // indexManager.removeIndex(entryPath);
429 // } else if (oldTimestamp.longValue() != newTimeStamp){
430 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_CHANGED);
431 // this.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
432 // // first remove the index so that it is forced to be re-indexed
433 // indexManager.removeIndex(entryPath);
434 // // then index the jar
435 // indexManager.indexLibrary(entryPath, project.getProject());
437 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED);
440 // if (newTimeStamp == 0){ // jar still doesn't exist
441 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED);
443 // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_ADDED);
444 // this.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
445 // // index the new jar
446 // indexManager.indexLibrary(entryPath, project.getProject());
449 // } else { // internal JAR
450 // externalArchivesStatus.put(entryPath, INTERNAL_JAR_IGNORE);
453 // // according to computed status, generate a delta
454 // status = (String)externalArchivesStatus.get(entryPath);
455 // if (status != null){
456 // if (status == EXTERNAL_JAR_ADDED){
457 // PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
459 // System.out.println("- External JAR ADDED, affecting root: "+root.getElementName()); //$NON-NLS-1$
461 // elementAdded(root, null, null);
463 // } else if (status == EXTERNAL_JAR_CHANGED) {
464 // PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
466 // System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$
468 // // reset the corresponding project built state, since the builder would miss this change
469 // this.manager.setLastBuiltState(project.getProject(), null /*no state*/);
470 // contentChanged(root, null);
472 // } else if (status == EXTERNAL_JAR_REMOVED) {
473 // PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
475 // System.out.println("- External JAR REMOVED, affecting root: "+root.getElementName()); //$NON-NLS-1$
477 // elementRemoved(root, null, null);
486 JavaElementDelta currentDelta() {
487 if (this.currentDelta == null) {
488 this.currentDelta = new JavaElementDelta(this.manager.getJavaModel());
490 return this.currentDelta;
494 * Process the given delta and look for projects being added, opened, closed or
495 * with a java nature being added or removed.
496 * Note that projects being deleted are checked in deleting(IProject).
497 * In all cases, add the project's dependents to the list of projects to update
498 * so that the classpath related markers can be updated.
500 // public void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) {
501 // IResource resource = delta.getResource();
502 // switch (resource.getType()) {
503 // case IResource.ROOT :
504 // // workaround for bug 15168 circular errors not reported
505 // if (this.manager.javaProjectsCache == null) {
507 // this.manager.javaProjectsCache = this.manager.getJavaModel().getJavaProjects();
508 // } catch (JavaModelException e) {
512 // IResourceDelta[] children = delta.getAffectedChildren();
513 // for (int i = 0, length = children.length; i < length; i++) {
514 // this.checkProjectsBeingAddedOrRemoved(children[i]);
517 // case IResource.PROJECT :
518 // // NB: No need to check project's nature as if the project is not a java project:
519 // // - if the project is added or changed this is a noop for projectsBeingDeleted
520 // // - if the project is closed, it has already lost its java nature
521 // int deltaKind = delta.getKind();
522 // if (deltaKind == IResourceDelta.ADDED) {
523 // // remember project and its dependents
524 // IProject project = (IProject)resource;
525 // this.addToProjectsToUpdateWithDependents(project);
527 // // workaround for bug 15168 circular errors not reported
528 // if (JavaProject.hasJavaNature(project)) {
529 // this.addToParentInfo((JavaProject)JavaCore.create(project));
532 // } else if (deltaKind == IResourceDelta.CHANGED) {
533 // IProject project = (IProject)resource;
534 // if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
535 // // project opened or closed: remember project and its dependents
536 // this.addToProjectsToUpdateWithDependents(project);
538 // // workaround for bug 15168 circular errors not reported
539 // if (project.isOpen()) {
540 // if (JavaProject.hasJavaNature(project)) {
541 // this.addToParentInfo((JavaProject)JavaCore.create(project));
544 // JavaProject javaProject = (JavaProject)this.manager.getJavaModel().findJavaProject(project);
545 // if (javaProject != null) {
547 // javaProject.close();
548 // } catch (JavaModelException e) {
550 // this.removeFromParentInfo(javaProject);
553 // } else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
554 // boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(project) != null;
555 // boolean isJavaProject = JavaProject.hasJavaNature(project);
556 // if (wasJavaProject != isJavaProject) {
557 // // java nature added or removed: remember project and its dependents
558 // this.addToProjectsToUpdateWithDependents(project);
560 // // workaround for bug 15168 circular errors not reported
561 // if (isJavaProject) {
562 // this.addToParentInfo((JavaProject)JavaCore.create(project));
564 // JavaProject javaProject = (JavaProject)JavaCore.create(project);
566 // // flush classpath markers
568 // flushClasspathProblemMarkers(
569 // true, // flush cycle markers
570 // true //flush classpath format markers
573 // // remove problems and tasks created by the builder
574 // JavaBuilder.removeProblemsAndTasksFor(project);
578 // javaProject.close();
579 // } catch (JavaModelException e) {
581 // this.removeFromParentInfo(javaProject);
584 // // in case the project was removed then added then changed (see bug 19799)
585 // if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
586 // this.addToParentInfo((JavaProject)JavaCore.create(project));
590 // // workaround for bug 15168 circular errors not reported
591 // // in case the project was removed then added then changed
592 // if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
593 // this.addToParentInfo((JavaProject)JavaCore.create(project));
601 // private void checkSourceAttachmentChange(IResourceDelta delta, IResource res) {
602 // IPath rootPath = (IPath)this.sourceAttachments.get(res.getFullPath());
603 // if (rootPath != null) {
604 // RootInfo rootInfo = this.rootInfo(rootPath, delta.getKind());
605 // if (rootInfo != null) {
606 // IJavaProject projectOfRoot = rootInfo.project;
607 // IPackageFragmentRoot root = null;
609 // // close the root so that source attachement cache is flushed
610 // root = projectOfRoot.findPackageFragmentRoot(rootPath);
611 // if (root != null) {
614 // } catch (JavaModelException e) {
616 // if (root == null) return;
617 // switch (delta.getKind()) {
618 // case IResourceDelta.ADDED:
619 // currentDelta().sourceAttached(root);
621 // case IResourceDelta.CHANGED:
622 // currentDelta().sourceDetached(root);
623 // currentDelta().sourceAttached(root);
625 // case IResourceDelta.REMOVED:
626 // currentDelta().sourceDetached(root);
634 * Closes the given element, which removes it from the cache of open elements.
636 // protected static void close(Openable element) {
640 // } catch (JavaModelException e) {
645 * Generic processing for elements with changed contents:<ul>
646 * <li>The element is closed such that any subsequent accesses will re-open
647 * the element reflecting its new structure.
648 * <li>An entry is made in the delta reporting a content change (K_CHANGE with F_CONTENT flag set).
650 * Delta argument could be null if processing an external JAR change
652 // protected void contentChanged(Openable element, IResourceDelta delta) {
655 // int flags = IJavaElementDelta.F_CONTENT;
656 // if (element instanceof JarPackageFragmentRoot){
657 // flags |= IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED;
659 // currentDelta().changed(element, flags);
663 * Creates the openables corresponding to this resource.
664 * Returns null if none was found.
666 // protected Openable createElement(IResource resource, int elementType, RootInfo rootInfo) {
667 // if (resource == null) return null;
669 // IPath path = resource.getFullPath();
670 // IJavaElement element = null;
671 // switch (elementType) {
673 // case IJavaElement.JAVA_PROJECT:
675 // // note that non-java resources rooted at the project level will also enter this code with
676 // // an elementType JAVA_PROJECT (see #elementType(...)).
677 // if (resource instanceof IProject){
679 // this.popUntilPrefixOf(path);
681 // if (this.currentElement != null
682 // && this.currentElement.getElementType() == IJavaElement.JAVA_PROJECT
683 // && ((IJavaProject)this.currentElement).getProject().equals(resource)) {
684 // return this.currentElement;
686 // if (rootInfo != null && rootInfo.project.getProject().equals(resource)){
687 // element = (Openable)rootInfo.project;
690 // IProject proj = (IProject)resource;
691 // if (JavaProject.hasJavaNature(proj)) {
692 // element = JavaCore.create(proj);
694 // // java project may have been been closed or removed (look for
695 // // element amongst old java project s list).
696 // element = (Openable) manager.getJavaModel().findJavaProject(proj);
700 // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
701 // element = rootInfo == null ? JavaCore.create(resource) : rootInfo.project.getPackageFragmentRoot(resource);
703 // case IJavaElement.PACKAGE_FRAGMENT:
704 // // find the element that encloses the resource
705 // this.popUntilPrefixOf(path);
707 // if (this.currentElement == null) {
708 // element = rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
711 // IPackageFragmentRoot root = this.currentElement.getPackageFragmentRoot();
712 // if (root == null) {
713 // element = rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
714 // } else if (((JavaProject)root.getJavaProject()).contains(resource)) {
715 // // create package handle
716 // IPath pkgPath = path.removeFirstSegments(root.getPath().segmentCount());
717 // String pkg = Util.packageName(pkgPath);
718 // if (pkg == null) return null;
719 // element = root.getPackageFragment(pkg);
723 // case IJavaElement.COMPILATION_UNIT:
724 // case IJavaElement.CLASS_FILE:
725 // // find the element that encloses the resource
726 // this.popUntilPrefixOf(path);
728 // if (this.currentElement == null) {
729 // element = rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
731 // // find the package
732 // IPackageFragment pkgFragment = null;
733 // switch (this.currentElement.getElementType()) {
734 // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
735 // IPackageFragmentRoot root = (IPackageFragmentRoot)this.currentElement;
736 // IPath rootPath = root.getPath();
737 // IPath pkgPath = path.removeLastSegments(1);
738 // String pkgName = Util.packageName(pkgPath.removeFirstSegments(rootPath.segmentCount()));
739 // if (pkgName != null) {
740 // pkgFragment = root.getPackageFragment(pkgName);
743 // case IJavaElement.PACKAGE_FRAGMENT:
744 // Openable pkg = (Openable)this.currentElement;
745 // if (pkg.getPath().equals(path.removeLastSegments(1))) {
746 // pkgFragment = (IPackageFragment)pkg;
747 // } // else case of package x which is a prefix of x.y
749 // case IJavaElement.COMPILATION_UNIT:
750 // case IJavaElement.CLASS_FILE:
751 // pkgFragment = (IPackageFragment)this.currentElement.getParent();
754 // if (pkgFragment == null) {
755 // element = rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
757 // if (elementType == IJavaElement.COMPILATION_UNIT) {
758 // // create compilation unit handle
759 // // fileName validation has been done in elementType(IResourceDelta, int, boolean)
760 // String fileName = path.lastSegment();
761 // element = pkgFragment.getCompilationUnit(fileName);
763 // // create class file handle
764 // // fileName validation has been done in elementType(IResourceDelta, int, boolean)
765 // String fileName = path.lastSegment();
766 // element = pkgFragment.getClassFile(fileName);
772 // if (element == null) {
775 // this.currentElement = (Openable)element;
776 // return this.currentElement;
780 * Note that the project is about to be deleted.
782 // public void deleting(IProject project) {
785 // // discard indexing jobs that belong to this project so that the project can be
786 // // deleted without interferences from the index manager
787 // this.indexManager.discardJobs(project.getName());
789 // JavaProject javaProject = (JavaProject)JavaCore.create(project);
791 // // remember roots of this project
792 // if (this.removedRoots == null) {
793 // this.removedRoots = new HashMap();
795 // if (javaProject.isOpen()) {
796 // this.removedRoots.put(javaProject, javaProject.getPackageFragmentRoots());
798 // // compute roots without opening project
799 // this.removedRoots.put(
801 // javaProject.computePackageFragmentRoots(
802 // javaProject.getResolvedClasspath(true),
806 // javaProject.close();
808 // // workaround for bug 15168 circular errors not reported
809 // if (this.manager.javaProjectsCache == null) {
810 // this.manager.javaProjectsCache = this.manager.getJavaModel().getJavaProjects();
812 // this.removeFromParentInfo(javaProject);
814 // } catch (JavaModelException e) {
817 // this.addDependentProjects(project.getFullPath(), this.projectsToUpdate);
822 * Processing for an element that has been added:<ul>
823 * <li>If the element is a project, do nothing, and do not process
824 * children, as when a project is created it does not yet have any
825 * natures - specifically a java nature.
826 * <li>If the elemet is not a project, process it as added (see
827 * <code>basicElementAdded</code>.
829 * Delta argument could be null if processing an external JAR change
831 // protected void elementAdded(Openable element, IResourceDelta delta, RootInfo rootInfo) {
832 // int elementType = element.getElementType();
834 // if (elementType == IJavaElement.JAVA_PROJECT) {
835 // // project add is handled by JavaProject.configure() because
836 // // when a project is created, it does not yet have a java nature
837 // if (delta != null && JavaProject.hasJavaNature((IProject)delta.getResource())) {
838 // addToParentInfo(element);
839 // if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) {
840 // Openable movedFromElement = (Openable)element.getJavaModel().getJavaProject(delta.getMovedFromPath().lastSegment());
841 // currentDelta().movedTo(element, movedFromElement);
843 // currentDelta().added(element);
845 // this.projectsToUpdate.add(element);
846 // this.updateRoots(element.getPath(), delta);
847 // this.projectsForDependentNamelookupRefresh.add((JavaProject) element);
850 // addToParentInfo(element);
852 // // Force the element to be closed as it might have been opened
853 // // before the resource modification came in and it might have a new child
854 // // For example, in an IWorkspaceRunnable:
855 // // 1. create a package fragment p using a java model operation
856 // // 2. open package p
857 // // 3. add file X.java in folder p
858 // // When the resource delta comes in, only the addition of p is notified,
859 // // but the package p is already opened, thus its children are not recomputed
860 // // and it appears empty.
863 // if (delta != null && (delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) {
864 // IPath movedFromPath = delta.getMovedFromPath();
865 // IResource res = delta.getResource();
866 // IResource movedFromRes;
867 // if (res instanceof IFile) {
868 // movedFromRes = res.getWorkspace().getRoot().getFile(movedFromPath);
870 // movedFromRes = res.getWorkspace().getRoot().getFolder(movedFromPath);
873 // // find the element type of the moved from element
874 // RootInfo movedFromInfo = this.enclosingRootInfo(movedFromPath, IResourceDelta.REMOVED);
875 // int movedFromType =
878 // IResourceDelta.REMOVED,
879 // element.getParent().getElementType(),
882 // // reset current element as it might be inside a nested root (popUntilPrefixOf() may use the outer root)
883 // this.currentElement = null;
885 // // create the moved from element
886 // Openable movedFromElement =
887 // elementType != IJavaElement.JAVA_PROJECT && movedFromType == IJavaElement.JAVA_PROJECT ?
888 // null : // outside classpath
889 // this.createElement(movedFromRes, movedFromType, movedFromInfo);
890 // if (movedFromElement == null) {
891 // // moved from outside classpath
892 // currentDelta().added(element);
894 // currentDelta().movedTo(element, movedFromElement);
897 // currentDelta().added(element);
900 // switch (elementType) {
901 // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
902 // // when a root is added, and is on the classpath, the project must be updated
903 // JavaProject project = (JavaProject) element.getJavaProject();
904 // this.projectsToUpdate.add(project);
905 // this.projectsForDependentNamelookupRefresh.add(project);
908 // case IJavaElement.PACKAGE_FRAGMENT :
909 // // get rid of namelookup since it holds onto obsolete cached info
910 // project = (JavaProject) element.getJavaProject();
912 // project.getJavaProjectElementInfo().setNameLookup(null);
913 // this.projectsForDependentNamelookupRefresh.add(project);
914 // } catch (JavaModelException e) {
916 // // add subpackages
917 // if (delta != null){
918 // PackageFragmentRoot root = element.getPackageFragmentRoot();
919 // String name = element.getElementName();
920 // IResourceDelta[] children = delta.getAffectedChildren();
921 // for (int i = 0, length = children.length; i < length; i++) {
922 // IResourceDelta child = children[i];
923 // IResource resource = child.getResource();
924 // if (resource instanceof IFolder) {
925 // String folderName = resource.getName();
926 // if (Util.isValidFolderNameForPackage(folderName)) {
927 // String subpkgName =
928 // name.length() == 0 ?
930 // name + "." + folderName; //$NON-NLS-1$
931 // Openable subpkg = (Openable)root.getPackageFragment(subpkgName);
932 // this.updateIndex(subpkg, child);
933 // this.elementAdded(subpkg, child, rootInfo);
944 * Generic processing for a removed element:<ul>
945 * <li>Close the element, removing its structure from the cache
946 * <li>Remove the element from its parent's cache of children
947 * <li>Add a REMOVED entry in the delta
949 * Delta argument could be null if processing an external JAR change
951 // protected void elementRemoved(Openable element, IResourceDelta delta, RootInfo rootInfo) {
953 // if (element.isOpen()) {
956 // removeFromParentInfo(element);
957 // int elementType = element.getElementType();
958 // if (delta != null && (delta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
959 // IPath movedToPath = delta.getMovedToPath();
960 // IResource res = delta.getResource();
961 // IResource movedToRes;
962 // switch (res.getType()) {
963 // case IResource.PROJECT:
964 // movedToRes = res.getWorkspace().getRoot().getProject(movedToPath.lastSegment());
966 // case IResource.FOLDER:
967 // movedToRes = res.getWorkspace().getRoot().getFolder(movedToPath);
969 // case IResource.FILE:
970 // movedToRes = res.getWorkspace().getRoot().getFile(movedToPath);
976 // // find the element type of the moved from element
977 // RootInfo movedToInfo = this.enclosingRootInfo(movedToPath, IResourceDelta.ADDED);
981 // IResourceDelta.ADDED,
982 // element.getParent().getElementType(),
985 // // reset current element as it might be inside a nested root (popUntilPrefixOf() may use the outer root)
986 // this.currentElement = null;
988 // // create the moved To element
989 // Openable movedToElement =
990 // elementType != IJavaElement.JAVA_PROJECT && movedToType == IJavaElement.JAVA_PROJECT ?
991 // null : // outside classpath
992 // this.createElement(movedToRes, movedToType, movedToInfo);
993 // if (movedToElement == null) {
994 // // moved outside classpath
995 // currentDelta().removed(element);
997 // currentDelta().movedFrom(element, movedToElement);
1000 // currentDelta().removed(element);
1003 // switch (elementType) {
1004 // case IJavaElement.JAVA_MODEL :
1005 // this.indexManager.reset();
1007 // case IJavaElement.JAVA_PROJECT :
1008 // this.manager.removePerProjectInfo(
1009 // (JavaProject) element);
1010 // this.updateRoots(element.getPath(), delta);
1011 // this.projectsForDependentNamelookupRefresh.add((JavaProject) element);
1013 // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
1014 // JavaProject project = (JavaProject) element.getJavaProject();
1015 // this.projectsToUpdate.add(project);
1016 // this.projectsForDependentNamelookupRefresh.add(project);
1018 // case IJavaElement.PACKAGE_FRAGMENT :
1019 // //1G1TW2T - get rid of namelookup since it holds onto obsolete cached info
1020 // project = (JavaProject) element.getJavaProject();
1022 // project.getJavaProjectElementInfo().setNameLookup(null);
1023 // this.projectsForDependentNamelookupRefresh.add(project);
1024 // } catch (JavaModelException e) {
1026 // // remove subpackages
1027 // if (delta != null){
1028 // PackageFragmentRoot root = element.getPackageFragmentRoot();
1029 // String name = element.getElementName();
1030 // IResourceDelta[] children = delta.getAffectedChildren();
1031 // for (int i = 0, length = children.length; i < length; i++) {
1032 // IResourceDelta child = children[i];
1033 // IResource resource = child.getResource();
1034 // if (resource instanceof IFolder) {
1035 // String folderName = resource.getName();
1036 // if (Util.isValidFolderNameForPackage(folderName)) {
1037 // String subpkgName =
1038 // name.length() == 0 ?
1040 // name + "." + folderName; //$NON-NLS-1$
1041 // Openable subpkg = (Openable)root.getPackageFragment(subpkgName);
1042 // this.updateIndex(subpkg, child);
1043 // this.elementRemoved(subpkg, child, rootInfo);
1053 * Returns the type of the java element the given delta matches to.
1054 * Returns NON_JAVA_RESOURCE if unknown (e.g. a non-java resource or excluded .java file)
1056 // private int elementType(IResource res, int kind, int parentType, RootInfo rootInfo) {
1057 // switch (parentType) {
1058 // case IJavaElement.JAVA_MODEL:
1059 // // case of a movedTo or movedFrom project (other cases are handled in processResourceDelta(...)
1060 // return IJavaElement.JAVA_PROJECT;
1061 // case NON_JAVA_RESOURCE:
1062 // case IJavaElement.JAVA_PROJECT:
1063 // if (rootInfo == null) {
1064 // rootInfo = this.enclosingRootInfo(res.getFullPath(), kind);
1066 // if (rootInfo != null && rootInfo.isRootOfProject(res.getFullPath())) {
1067 // return IJavaElement.PACKAGE_FRAGMENT_ROOT;
1069 // return NON_JAVA_RESOURCE; // not yet in a package fragment root or root of another project
1071 // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1072 // case IJavaElement.PACKAGE_FRAGMENT:
1073 // if (rootInfo == null) {
1074 // rootInfo = this.enclosingRootInfo(res.getFullPath(), kind);
1076 // if (rootInfo == null || Util.isExcluded(res, rootInfo.exclusionPatterns)) {
1077 // return NON_JAVA_RESOURCE;
1079 // if (res instanceof IFolder) {
1080 // if (Util.isValidFolderNameForPackage(res.getName())) {
1081 // return IJavaElement.PACKAGE_FRAGMENT;
1083 // return NON_JAVA_RESOURCE;
1086 // String fileName = res.getName();
1087 // if (Util.isValidCompilationUnitName(fileName)) {
1088 // return IJavaElement.COMPILATION_UNIT;
1089 // } else if (Util.isValidClassFileName(fileName)) {
1090 // return IJavaElement.CLASS_FILE;
1091 // } else if (this.rootInfo(res.getFullPath(), kind) != null) {
1092 // // case of proj=src=bin and resource is a jar file on the classpath
1093 // return IJavaElement.PACKAGE_FRAGMENT_ROOT;
1095 // return NON_JAVA_RESOURCE;
1099 // return NON_JAVA_RESOURCE;
1104 * Answer a combination of the lastModified stamp and the size.
1105 * Used for detecting external JAR changes
1107 public static long getTimeStamp(File file) {
1108 return file.lastModified() + file.length();
1111 public void initializeRoots() {
1112 // remember roots infos as old roots infos
1113 this.oldRoots = this.roots == null ? new HashMap() : this.roots;
1114 this.oldOtherRoots = this.otherRoots == null ? new HashMap() : this.otherRoots;
1116 // recompute root infos only if necessary
1117 if (!rootsAreStale) return;
1119 this.roots = new HashMap();
1120 this.otherRoots = new HashMap();
1121 this.sourceAttachments = new HashMap();
1123 IJavaModel model = this.manager.getJavaModel();
1124 IJavaProject[] projects;
1126 projects = model.getJavaProjects();
1127 } catch (JavaModelException e) {
1128 // nothing can be done
1131 for (int i = 0, length = projects.length; i < length; i++) {
1132 IJavaProject project = projects[i];
1133 IClasspathEntry[] classpath;
1135 classpath = project.getResolvedClasspath(true);
1136 } catch (JavaModelException e) {
1137 // continue with next project
1140 for (int j= 0, classpathLength = classpath.length; j < classpathLength; j++) {
1141 IClasspathEntry entry = classpath[j];
1142 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
1145 IPath path = entry.getPath();
1146 if (this.roots.get(path) == null) {
1147 this.roots.put(path, new RootInfo(project, path, ((ClasspathEntry)entry).fullExclusionPatternChars()));
1149 ArrayList rootList = (ArrayList)this.otherRoots.get(path);
1150 if (rootList == null) {
1151 rootList = new ArrayList();
1152 this.otherRoots.put(path, rootList);
1154 rootList.add(new RootInfo(project, path, ((ClasspathEntry)entry).fullExclusionPatternChars()));
1157 // source attachment path
1158 if (entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY) continue;
1159 QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + path.toOSString()); //$NON-NLS-1$;
1160 String propertyString = null;
1162 propertyString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
1163 } catch (CoreException e) {
1166 IPath sourceAttachmentPath;
1167 // if (propertyString != null) {
1168 // int index= propertyString.lastIndexOf(JarPackageFragmentRoot.ATTACHMENT_PROPERTY_DELIMITER);
1169 // sourceAttachmentPath = (index < 0) ? new Path(propertyString) : new Path(propertyString.substring(0, index));
1171 sourceAttachmentPath = entry.getSourceAttachmentPath();
1173 if (sourceAttachmentPath != null) {
1174 this.sourceAttachments.put(sourceAttachmentPath, path);
1178 this.rootsAreStale = false;
1182 * Returns whether a given delta contains some information relevant to the JavaModel,
1183 * in particular it will not consider SYNC or MARKER only deltas.
1185 public boolean isAffectedBy(IResourceDelta rootDelta){
1186 //if (rootDelta == null) System.out.println("NULL DELTA");
1187 //long start = System.currentTimeMillis();
1188 if (rootDelta != null) {
1189 // use local exception to quickly escape from delta traversal
1190 class FoundRelevantDeltaException extends RuntimeException {}
1192 rootDelta.accept(new IResourceDeltaVisitor() {
1193 public boolean visit(IResourceDelta delta) throws CoreException {
1194 switch (delta.getKind()){
1195 case IResourceDelta.ADDED :
1196 case IResourceDelta.REMOVED :
1197 throw new FoundRelevantDeltaException();
1198 case IResourceDelta.CHANGED :
1199 // if any flag is set but SYNC or MARKER, this delta should be considered
1200 if (delta.getAffectedChildren().length == 0 // only check leaf delta nodes
1201 && (delta.getFlags() & ~(IResourceDelta.SYNC | IResourceDelta.MARKERS)) != 0) {
1202 throw new FoundRelevantDeltaException();
1208 } catch(FoundRelevantDeltaException e) {
1209 //System.out.println("RELEVANT DELTA detected in: "+ (System.currentTimeMillis() - start));
1211 } catch(CoreException e) { // ignore delta if not able to traverse
1214 //System.out.println("IGNORE SYNC DELTA took: "+ (System.currentTimeMillis() - start));
1219 * Returns whether the given resource is in one of the given output folders and if
1220 * it is filtered out from this output folder.
1222 private boolean isResFilteredFromOutput(OutputsInfo info, IResource res, int elementType) {
1224 IPath resPath = res.getFullPath();
1225 for (int i = 0; i < info.outputCount; i++) {
1226 if (info.paths[i].isPrefixOf(resPath)) {
1227 if (info.traverseModes[i] != IGNORE) {
1229 if (info.traverseModes[i] == SOURCE && elementType == IJavaElement.CLASS_FILE) {
1232 // case of .class file under project and no source folder
1234 if (elementType == IJavaElement.JAVA_PROJECT
1235 && res instanceof IFile
1236 && PHPFileUtil.isPHPFile((IFile)res)) {
1249 * Merges all awaiting deltas.
1251 private IJavaElementDelta mergeDeltas(Collection deltas) {
1252 if (deltas.size() == 0) return null;
1253 if (deltas.size() == 1) return (IJavaElementDelta)deltas.iterator().next();
1256 System.out.println("MERGING " + deltas.size() + " DELTAS ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1259 Iterator iterator = deltas.iterator();
1260 JavaElementDelta rootDelta = new JavaElementDelta(this.manager.javaModel);
1261 boolean insertedTree = false;
1262 while (iterator.hasNext()) {
1263 JavaElementDelta delta = (JavaElementDelta)iterator.next();
1265 System.out.println(delta.toString());
1267 IJavaElement element = delta.getElement();
1268 if (this.manager.javaModel.equals(element)) {
1269 IJavaElementDelta[] children = delta.getAffectedChildren();
1270 for (int j = 0; j < children.length; j++) {
1271 JavaElementDelta projectDelta = (JavaElementDelta) children[j];
1272 rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta);
1273 insertedTree = true;
1275 IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
1276 if (resourceDeltas != null) {
1277 for (int i = 0, length = resourceDeltas.length; i < length; i++) {
1278 rootDelta.addResourceDelta(resourceDeltas[i]);
1279 insertedTree = true;
1283 rootDelta.insertDeltaTree(element, delta);
1284 insertedTree = true;
1287 if (insertedTree) return rootDelta;
1290 private void notifyListeners(IJavaElementDelta deltaToNotify, int eventType, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) {
1291 final ElementChangedEvent extraEvent = new ElementChangedEvent(deltaToNotify, eventType);
1292 for (int i= 0; i < listenerCount; i++) {
1293 if ((listenerMask[i] & eventType) != 0){
1294 final IElementChangedListener listener = listeners[i];
1297 System.out.print("Listener #" + (i+1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$
1298 start = System.currentTimeMillis();
1300 // wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief
1301 Platform.run(new ISafeRunnable() {
1302 public void handleException(Throwable exception) {
1303 Util.log(exception, "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
1305 public void run() throws Exception {
1306 listener.elementChanged(extraEvent);
1310 System.out.println(" -> " + (System.currentTimeMillis()-start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1316 * Generic processing for elements with changed contents:<ul>
1317 * <li>The element is closed such that any subsequent accesses will re-open
1318 * the element reflecting its new structure.
1319 * <li>An entry is made in the delta reporting a content change (K_CHANGE with F_CONTENT flag set).
1322 // protected void nonJavaResourcesChanged(Openable element, IResourceDelta delta)
1323 // throws JavaModelException {
1325 // // reset non-java resources if element was open
1326 // if (element.isOpen()) {
1327 // JavaElementInfo info = (JavaElementInfo)element.getElementInfo();
1328 // switch (element.getElementType()) {
1329 // case IJavaElement.JAVA_MODEL :
1330 // ((JavaModelInfo) info).nonJavaResources = null;
1331 // currentDelta().addResourceDelta(delta);
1333 // case IJavaElement.JAVA_PROJECT :
1334 // ((JavaProjectElementInfo) info).setNonJavaResources(null);
1336 // // if a package fragment root is the project, clear it too
1337 // JavaProject project = (JavaProject) element;
1338 // PackageFragmentRoot projectRoot =
1339 // (PackageFragmentRoot) project.getPackageFragmentRoot(project.getProject());
1340 // if (projectRoot.isOpen()) {
1341 // ((PackageFragmentRootInfo) projectRoot.getElementInfo()).setNonJavaResources(
1345 // case IJavaElement.PACKAGE_FRAGMENT :
1346 // ((PackageFragmentInfo) info).setNonJavaResources(null);
1348 // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
1349 // ((PackageFragmentRootInfo) info).setNonJavaResources(null);
1353 // JavaElementDelta elementDelta = currentDelta().find(element);
1354 // if (elementDelta == null) {
1355 // currentDelta().changed(element, IJavaElementDelta.F_CONTENT);
1356 // elementDelta = currentDelta().find(element);
1358 // elementDelta.addResourceDelta(delta);
1360 // private OutputsInfo outputsInfo(RootInfo rootInfo, IResource res) {
1362 // IJavaProject proj =
1363 // rootInfo == null ?
1364 // (IJavaProject)this.createElement(res.getProject(), IJavaElement.JAVA_PROJECT, null) :
1365 // rootInfo.project;
1366 // if (proj != null) {
1367 // IPath projectOutput = proj.getOutputLocation();
1368 // int traverseMode = IGNORE;
1369 // if (proj.getProject().getFullPath().equals(projectOutput)){ // case of proj==bin==src
1370 // return new OutputsInfo(new IPath[] {projectOutput}, new int[] {SOURCE}, 1);
1372 // IClasspathEntry[] classpath = proj.getResolvedClasspath(true);
1373 // IPath[] outputs = new IPath[classpath.length+1];
1374 // int[] traverseModes = new int[classpath.length+1];
1375 // int outputCount = 1;
1376 // outputs[0] = projectOutput;
1377 // traverseModes[0] = traverseMode;
1378 // for (int i = 0, length = classpath.length; i < length; i++) {
1379 // IClasspathEntry entry = classpath[i];
1380 // IPath entryPath = entry.getPath();
1381 // IPath output = entry.getOutputLocation();
1382 // if (output != null) {
1383 // outputs[outputCount] = output;
1384 // // check case of src==bin
1385 // if (entryPath.equals(output)) {
1386 // traverseModes[outputCount++] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
1388 // traverseModes[outputCount++] = IGNORE;
1392 // // check case of src==bin
1393 // if (entryPath.equals(projectOutput)) {
1394 // traverseModes[0] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
1397 // return new OutputsInfo(outputs, traverseModes, outputCount);
1400 // } catch (JavaModelException e) {
1406 * Check whether the updated file is affecting some of the properties of a given project (like
1407 * its classpath persisted as a file).
1408 * Also force classpath problems to be refresh if not running in autobuild mode.
1409 * NOTE: It can induce resource changes, and cannot be called during POST_CHANGE notification.
1412 // public void performPreBuildCheck(
1413 // IResourceDelta delta,
1414 // IJavaElement parent) {
1416 // IResource resource = delta.getResource();
1417 // IJavaElement element = null;
1418 // boolean processChildren = false;
1420 // switch (resource.getType()) {
1422 // case IResource.ROOT :
1423 // if (delta.getKind() == IResourceDelta.CHANGED) {
1424 // element = JavaCore.create(resource);
1425 // processChildren = true;
1428 // case IResource.PROJECT :
1429 // int kind = delta.getKind();
1431 // case IResourceDelta.CHANGED:
1432 // // do not visit non-java projects (see bug 16140 Non-java project gets .classpath)
1433 // IProject project = (IProject)resource;
1434 // if (JavaProject.hasJavaNature(project)) {
1435 // element = JavaCore.create(resource);
1436 // processChildren = true;
1437 // } else if (JavaModelManager.getJavaModelManager().getJavaModel().findJavaProject(project) != null) {
1438 // // project had the java nature
1439 // this.rootsAreStale = true;
1441 // // remove classpath cache so that initializeRoots() will not consider the project has a classpath
1442 // this.manager.removePerProjectInfo((JavaProject)JavaCore.create(project));
1445 // case IResourceDelta.ADDED:
1446 // this.rootsAreStale = true;
1448 // case IResourceDelta.REMOVED:
1449 // // remove classpath cache so that initializeRoots() will not consider the project has a classpath
1450 // this.manager.removePerProjectInfo((JavaProject)JavaCore.create(resource));
1452 // this.rootsAreStale = true;
1456 // case IResource.FILE :
1457 // if (parent.getElementType() == IJavaElement.JAVA_PROJECT) {
1458 // IFile file = (IFile) resource;
1459 // JavaProject project = (JavaProject) parent;
1461 // /* check classpath file change */
1462 // if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) {
1463 // reconcileClasspathFileUpdate(delta, file, project);
1464 // this.rootsAreStale = true;
1467 //// /* check custom preference file change */
1468 //// if (file.getName().equals(JavaProject.PREF_FILENAME)) {
1469 //// reconcilePreferenceFileUpdate(delta, file, project);
1475 // if (processChildren) {
1476 // IResourceDelta[] children = delta.getAffectedChildren();
1477 // for (int i = 0; i < children.length; i++) {
1478 // performPreBuildCheck(children[i], element);
1483 // private void popUntilPrefixOf(IPath path) {
1484 // while (this.currentElement != null) {
1485 // IPath currentElementPath = null;
1486 // if (this.currentElement instanceof IPackageFragmentRoot) {
1487 // currentElementPath = ((IPackageFragmentRoot)this.currentElement).getPath();
1489 // IResource currentElementResource = this.currentElement.getResource();
1490 // if (currentElementResource != null) {
1491 // currentElementPath = currentElementResource.getFullPath();
1494 // if (currentElementPath != null) {
1495 // if (this.currentElement instanceof IPackageFragment
1496 // && this.currentElement.getElementName().length() == 0
1497 // && currentElementPath.segmentCount() != path.segmentCount()-1) {
1498 // // default package and path is not a direct child
1499 // this.currentElement = (Openable)this.currentElement.getParent();
1501 // if (currentElementPath.isPrefixOf(path)) {
1505 // this.currentElement = (Openable)this.currentElement.getParent();
1510 * Converts a <code>IResourceDelta</code> rooted in a <code>Workspace</code> into
1511 * the corresponding set of <code>IJavaElementDelta</code>, rooted in the
1512 * relevant <code>JavaModel</code>s.
1514 // public IJavaElementDelta processResourceDelta(IResourceDelta changes) {
1517 // IJavaModel model = this.manager.getJavaModel();
1518 // if (!model.isOpen()) {
1519 // // force opening of java model so that java element delta are reported
1521 // model.open(null);
1522 // } catch (JavaModelException e) {
1524 // e.printStackTrace();
1529 // this.initializeRoots();
1530 // this.currentElement = null;
1532 // // get the workspace delta, and start processing there.
1533 // IResourceDelta[] deltas = changes.getAffectedChildren();
1534 // for (int i = 0; i < deltas.length; i++) {
1535 // IResourceDelta delta = deltas[i];
1536 // IResource res = delta.getResource();
1538 // // find out the element type
1539 // RootInfo rootInfo = null;
1541 // IProject proj = (IProject)res;
1542 // boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(proj) != null;
1543 // boolean isJavaProject = JavaProject.hasJavaNature(proj);
1544 // if (!wasJavaProject && !isJavaProject) {
1545 // elementType = NON_JAVA_RESOURCE;
1547 // rootInfo = this.enclosingRootInfo(res.getFullPath(), delta.getKind());
1548 // if (rootInfo != null && rootInfo.isRootOfProject(res.getFullPath())) {
1549 // elementType = IJavaElement.PACKAGE_FRAGMENT_ROOT;
1551 // elementType = IJavaElement.JAVA_PROJECT;
1555 // // traverse delta
1556 // if (!this.traverseDelta(delta, elementType, rootInfo, null)
1557 // || (wasJavaProject != isJavaProject && (delta.getKind()) == IResourceDelta.CHANGED)) { // project has changed nature (description or open/closed)
1559 // // add child as non java resource
1560 // nonJavaResourcesChanged((JavaModel)model, delta);
1561 // } catch (JavaModelException e) {
1567 // // update package fragment roots of projects that were affected
1568 // Iterator iterator = this.projectsToUpdate.iterator();
1569 // while (iterator.hasNext()) {
1570 // JavaProject project = (JavaProject)iterator.next();
1571 // project.updatePackageFragmentRoots();
1574 // updateDependentNamelookups();
1576 // return this.currentDelta;
1578 // this.currentDelta = null;
1579 // this.projectsToUpdate.clear();
1580 // this.projectsForDependentNamelookupRefresh.clear();
1585 * Update the JavaModel according to a .classpath file change. The file can have changed as a result of a previous
1586 * call to JavaProject#setRawClasspath or as a result of some user update (through repository)
1588 // void reconcileClasspathFileUpdate(IResourceDelta delta, IFile file, JavaProject project) {
1590 // switch (delta.getKind()) {
1591 // case IResourceDelta.REMOVED : // recreate one based on in-memory classpath
1593 // JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
1594 // if (info.classpath != null) { // if there is an in-memory classpath
1595 // project.saveClasspath(info.classpath, info.outputLocation);
1597 // } catch (JavaModelException e) {
1598 // if (project.getProject().isAccessible()) {
1599 // Util.log(e, "Could not save classpath for "+ project.getPath()); //$NON-NLS-1$
1603 // case IResourceDelta.CHANGED :
1604 // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0 // only consider content change
1605 // && (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) // and also move and overide scenario (see http://dev.eclipse.org/bugs/show_bug.cgi?id=21420)
1607 // case IResourceDelta.ADDED :
1608 // // check if any actual difference
1609 // project.flushClasspathProblemMarkers(false, true);
1610 // boolean wasSuccessful = false; // flag recording if .classpath file change got reflected
1612 // // force to (re)read the property file
1613 // IClasspathEntry[] fileEntries = project.readClasspathFile(true/*create markers*/, false/*don't log problems*/);
1614 // if (fileEntries == null)
1615 // break; // could not read, ignore
1616 // JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
1617 // if (info.classpath != null) { // if there is an in-memory classpath
1618 // if (project.isClasspathEqualsTo(info.classpath, info.outputLocation, fileEntries)) {
1619 // wasSuccessful = true;
1624 // // will force an update of the classpath/output location based on the file information
1625 // // extract out the output location
1626 // IPath outputLocation = null;
1627 // if (fileEntries != null && fileEntries.length > 0) {
1628 // IClasspathEntry entry = fileEntries[fileEntries.length - 1];
1629 // if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1630 // outputLocation = entry.getPath();
1631 // IClasspathEntry[] copy = new IClasspathEntry[fileEntries.length - 1];
1632 // System.arraycopy(fileEntries, 0, copy, 0, copy.length);
1633 // fileEntries = copy;
1636 // // restore output location
1637 // if (outputLocation == null) {
1638 // outputLocation = SetClasspathOperation.ReuseOutputLocation;
1639 // // clean mode will also default to reusing current one
1641 // project.setRawClasspath(
1645 // true, // canChangeResource
1646 // project.getResolvedClasspath(true), // ignoreUnresolvedVariable
1647 // true, // needValidation
1648 // false); // no need to save
1650 // // if reach that far, the classpath file change got absorbed
1651 // wasSuccessful = true;
1652 // } catch (RuntimeException e) {
1653 // // setRawClasspath might fire a delta, and a listener may throw an exception
1654 // if (project.getProject().isAccessible()) {
1655 // Util.log(e, "Could not set classpath for "+ project.getPath()); //$NON-NLS-1$
1658 // } catch (JavaModelException e) { // CP failed validation
1659 // if (project.getProject().isAccessible()) {
1660 // if (e.getJavaModelStatus().getException() instanceof CoreException) {
1661 // // happens if the .classpath could not be written to disk
1662 // project.createClasspathProblemMarker(new JavaModelStatus(
1663 // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1664 // Util.bind("classpath.couldNotWriteClasspathFile", project.getElementName(), e.getMessage()))); //$NON-NLS-1$
1666 // project.createClasspathProblemMarker(new JavaModelStatus(
1667 // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1668 // Util.bind("classpath.invalidClasspathInClasspathFile", project.getElementName(), e.getMessage()))); //$NON-NLS-1$
1673 // if (!wasSuccessful) {
1675 // project.setRawClasspath0(JavaProject.INVALID_CLASSPATH);
1676 // project.updatePackageFragmentRoots();
1677 // } catch (JavaModelException e) {
1685 * Update the JavaModel according to a .jprefs file change. The file can have changed as a result of a previous
1686 * call to JavaProject#setOptions or as a result of some user update (through repository)
1687 * Unused until preference file get shared (.jpref)
1689 // void reconcilePreferenceFileUpdate(IResourceDelta delta, IFile file, JavaProject project) {
1691 // switch (delta.getKind()) {
1692 // case IResourceDelta.REMOVED : // flush project custom settings
1693 // project.setOptions(null);
1695 // case IResourceDelta.CHANGED :
1696 // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0 // only consider content change
1697 // && (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) // and also move and overide scenario
1699 // identityCheck : { // check if any actual difference
1700 // // force to (re)read the property file
1701 // Preferences filePreferences = project.loadPreferences();
1702 // if (filePreferences == null){
1703 // project.setOptions(null); // should have got removed delta.
1706 // Preferences projectPreferences = project.getPreferences();
1707 // if (projectPreferences == null) return; // not a Java project
1709 // // compare preferences set to their default
1710 // String[] defaultProjectPropertyNames = projectPreferences.defaultPropertyNames();
1711 // String[] defaultFilePropertyNames = filePreferences.defaultPropertyNames();
1712 // if (defaultProjectPropertyNames.length == defaultFilePropertyNames.length) {
1713 // for (int i = 0; i < defaultProjectPropertyNames.length; i++){
1714 // String propertyName = defaultProjectPropertyNames[i];
1715 // if (!projectPreferences.getString(propertyName).trim().equals(filePreferences.getString(propertyName).trim())){
1716 // break identityCheck;
1719 // } else break identityCheck;
1721 // // compare custom preferences not set to their default
1722 // String[] projectPropertyNames = projectPreferences.propertyNames();
1723 // String[] filePropertyNames = filePreferences.propertyNames();
1724 // if (projectPropertyNames.length == filePropertyNames.length) {
1725 // for (int i = 0; i < projectPropertyNames.length; i++){
1726 // String propertyName = projectPropertyNames[i];
1727 // if (!projectPreferences.getString(propertyName).trim().equals(filePreferences.getString(propertyName).trim())){
1728 // break identityCheck;
1731 // } else break identityCheck;
1733 // // identical - do nothing
1736 // case IResourceDelta.ADDED :
1737 // // not identical, create delta and reset cached preferences
1738 // project.setPreferences(null);
1740 // //fCurrentDelta.changed(project, IJavaElementDelta.F_OPTIONS_CHANGED);
1744 * Registers the given delta with this delta processor.
1746 public void registerJavaModelDelta(IJavaElementDelta delta) {
1747 this.javaModelDeltas.add(delta);
1750 * Removes the given element from its parents cache of children. If the
1751 * element does not have a parent, or the parent is not currently open,
1752 * this has no effect.
1754 protected void removeFromParentInfo(Openable child) {
1756 Openable parent = (Openable) child.getParent();
1757 if (parent != null && parent.isOpen()) {
1759 JavaElementInfo info = (JavaElementInfo)parent.getElementInfo();
1760 info.removeChild(child);
1761 } catch (JavaModelException e) {
1762 // do nothing - we already checked if open
1768 * Notification that some resource changes have happened
1769 * on the platform, and that the Java Model should update any required
1770 * internal structures such that its elements remain consistent.
1771 * Translates <code>IResourceDeltas</code> into <code>IJavaElementDeltas</code>.
1773 * @see IResourceDelta
1776 public void resourceChanged(IResourceChangeEvent event) {
1777 // jsurfer TODO compare 3.0 sources
1778 if (event.getSource() instanceof IWorkspace) {
1779 int eventType = this.overridenEventType == -1 ? event.getType() : this.overridenEventType;
1780 IResource resource = event.getResource();
1781 IResourceDelta delta = event.getDelta();
1784 case IResourceChangeEvent.PRE_DELETE :
1786 if(resource.getType() == IResource.PROJECT
1787 && ((IProject) resource).hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
1788 // TODO jsurfer temp-del
1789 // this.deleting((IProject)resource);
1791 } catch(CoreException e){
1795 case IResourceChangeEvent.PRE_BUILD :
1796 // TODO jsurfer temp-del
1797 // if(isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
1798 // this.checkProjectsBeingAddedOrRemoved(delta);
1800 // // update the classpath related markers
1801 // this.updateClasspathMarkers();
1803 // // the following will close project if affected by the property file change
1805 // // don't fire classpath change deltas right away, but batch them
1806 // this.manager.stopDeltas();
1807 // this.performPreBuildCheck(delta, null);
1809 // this.manager.startDeltas();
1812 // only fire already computed deltas (resource ones will be processed in post change only)
1813 this.manager.fire(null, ElementChangedEvent.PRE_AUTO_BUILD);
1816 case IResourceChangeEvent.POST_BUILD :
1817 // TODO jsurfer temp-del
1818 // JavaBuilder.finishedBuilding(event);
1821 case IResourceChangeEvent.POST_CHANGE :
1822 // TODO jsurfer temp-del
1823 // if (isAffectedBy(delta)) {
1825 // if (this.refreshedElements != null) {
1827 // createExternalArchiveDelta(null);
1828 // } catch (JavaModelException e) {
1829 // e.printStackTrace();
1832 // IJavaElementDelta translatedDelta = this.processResourceDelta(delta);
1833 // if (translatedDelta != null) {
1834 // this.manager.registerJavaModelDelta(translatedDelta);
1836 // this.manager.fire(null, ElementChangedEvent.POST_CHANGE);
1838 // // workaround for bug 15168 circular errors not reported
1839 // this.manager.javaProjectsCache = null;
1840 // this.removedRoots = null;
1847 * Flushes all deltas without firing them.
1849 public void flush() {
1850 this.javaModelDeltas = new ArrayList();
1853 * Finds the root info this path is included in.
1854 * Returns null if not found.
1856 RootInfo enclosingRootInfo(IPath path, int kind) {
1857 while (path != null && path.segmentCount() > 0) {
1858 RootInfo rootInfo = this.rootInfo(path, kind);
1859 if (rootInfo != null) return rootInfo;
1860 path = path.removeLastSegments(1);
1865 * Fire Java Model delta, flushing them after the fact after post_change notification.
1866 * If the firing mode has been turned off, this has no effect.
1868 public void fire(IJavaElementDelta customDelta, int eventType) {
1869 if (!this.isFiring) return;
1872 System.out.println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
1875 IJavaElementDelta deltaToNotify;
1876 if (customDelta == null){
1877 deltaToNotify = this.mergeDeltas(this.javaModelDeltas);
1879 deltaToNotify = customDelta;
1882 // Refresh internal scopes
1883 // if (deltaToNotify != null) {
1884 // Iterator scopes = this.manager.searchScopes.keySet().iterator();
1885 // while (scopes.hasNext()) {
1886 // AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
1887 // scope.processDelta(deltaToNotify);
1893 // Important: if any listener reacts to notification by updating the listeners list or mask, these lists will
1894 // be duplicated, so it is necessary to remember original lists in a variable (since field values may change under us)
1895 IElementChangedListener[] listeners = this.state.elementChangedListeners;
1896 int[] listenerMask = this.state.elementChangedListenerMasks;
1897 int listenerCount = this.state.elementChangedListenerCount;
1899 switch (eventType) {
1900 case DEFAULT_CHANGE_EVENT:
1901 firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount);
1902 fireReconcileDelta(listeners, listenerMask, listenerCount);
1904 case ElementChangedEvent.POST_CHANGE:
1905 firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount);
1906 fireReconcileDelta(listeners, listenerMask, listenerCount);
1911 private void firePostChangeDelta(
1912 IJavaElementDelta deltaToNotify,
1913 IElementChangedListener[] listeners,
1915 int listenerCount) {
1917 // post change deltas
1919 System.out.println("FIRING POST_CHANGE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
1920 System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1922 if (deltaToNotify != null) {
1923 // flush now so as to keep listener reactions to post their own deltas for subsequent iteration
1926 notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE, listeners, listenerMask, listenerCount);
1929 private void fireReconcileDelta(
1930 IElementChangedListener[] listeners,
1932 int listenerCount) {
1935 IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas.values());
1937 System.out.println("FIRING POST_RECONCILE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
1938 System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1940 if (deltaToNotify != null) {
1941 // flush now so as to keep listener reactions to post their own deltas for subsequent iteration
1942 this.reconcileDeltas = new HashMap();
1944 notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE, listeners, listenerMask, listenerCount);
1948 * Returns the root info for the given path. Look in the old roots table if kind is REMOVED.
1950 RootInfo rootInfo(IPath path, int kind) {
1951 if (kind == IResourceDelta.REMOVED) {
1952 return (RootInfo)this.oldRoots.get(path);
1954 return (RootInfo)this.roots.get(path);
1958 * Returns the other root infos for the given path. Look in the old other roots table if kind is REMOVED.
1960 ArrayList otherRootsInfo(IPath path, int kind) {
1961 if (kind == IResourceDelta.REMOVED) {
1962 return (ArrayList)this.oldOtherRoots.get(path);
1964 return (ArrayList)this.otherRoots.get(path);
1969 * Converts an <code>IResourceDelta</code> and its children into
1970 * the corresponding <code>IJavaElementDelta</code>s.
1971 * Return whether the delta corresponds to a java element.
1972 * If it is not a java element, it will be added as a non-java
1973 * resource by the sender of this method.
1975 // protected boolean traverseDelta(
1976 // IResourceDelta delta,
1978 // RootInfo rootInfo,
1979 // OutputsInfo outputsInfo) {
1981 // IResource res = delta.getResource();
1983 // // set stack of elements
1984 // if (this.currentElement == null && rootInfo != null) {
1985 // this.currentElement = (Openable)rootInfo.project;
1988 // // process current delta
1989 // boolean processChildren = true;
1990 // if (res instanceof IProject) {
1991 // processChildren =
1992 // this.updateCurrentDeltaAndIndex(
1994 // elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT ?
1995 // IJavaElement.JAVA_PROJECT : // case of prj=src
1998 // } else if (rootInfo != null) {
1999 // processChildren = this.updateCurrentDeltaAndIndex(delta, elementType, rootInfo);
2001 // // not yet inside a package fragment root
2002 // processChildren = true;
2005 // // get the project's output locations and traverse mode
2006 // if (outputsInfo == null) outputsInfo = this.outputsInfo(rootInfo, res);
2008 // // process children if needed
2009 // if (processChildren) {
2010 // IResourceDelta[] children = delta.getAffectedChildren();
2011 // boolean oneChildOnClasspath = false;
2012 // int length = children.length;
2013 // IResourceDelta[] orphanChildren = null;
2014 // Openable parent = null;
2015 // boolean isValidParent = true;
2016 // for (int i = 0; i < length; i++) {
2017 // IResourceDelta child = children[i];
2018 // IResource childRes = child.getResource();
2020 // // check source attachment change
2021 // this.checkSourceAttachmentChange(child, childRes);
2023 // // find out whether the child is a package fragment root of the current project
2024 // IPath childPath = childRes.getFullPath();
2025 // int childKind = child.getKind();
2026 // RootInfo childRootInfo = this.rootInfo(childPath, childKind);
2027 // if (childRootInfo != null && !childRootInfo.isRootOfProject(childPath)) {
2028 // // package fragment root of another project (dealt with later)
2029 // childRootInfo = null;
2032 // // compute child type
2034 // this.elementType(
2038 // rootInfo == null ? childRootInfo : rootInfo
2041 // // is childRes in the output folder and is it filtered out ?
2042 // boolean isResFilteredFromOutput = this.isResFilteredFromOutput(outputsInfo, childRes, childType);
2044 // boolean isNestedRoot = rootInfo != null && childRootInfo != null;
2045 // if (!isResFilteredFromOutput
2046 // && !isNestedRoot) { // do not treat as non-java rsc if nested root
2047 // if (!this.traverseDelta(child, childType, rootInfo == null ? childRootInfo : rootInfo, outputsInfo)) { // traverse delta for child in the same project
2048 // // it is a non-java resource
2050 // if (rootInfo != null) { // if inside a package fragment root
2051 // if (!isValidParent) continue;
2052 // if (parent == null) {
2053 // // find the parent of the non-java resource to attach to
2054 // if (this.currentElement == null
2055 // || !this.currentElement.getJavaProject().equals(rootInfo.project)) {
2056 // // force the currentProject to be used
2057 // this.currentElement = (Openable)rootInfo.project;
2059 // if (elementType == IJavaElement.JAVA_PROJECT
2060 // || (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT
2061 // && res instanceof IProject)) {
2062 // // NB: attach non-java resource to project (not to its package fragment root)
2063 // parent = (Openable)rootInfo.project;
2065 // parent = this.createElement(res, elementType, rootInfo);
2067 // if (parent == null) {
2068 // isValidParent = false;
2072 // // add child as non java resource
2073 // nonJavaResourcesChanged(parent, child);
2075 // // the non-java resource (or its parent folder) will be attached to the java project
2076 // if (orphanChildren == null) orphanChildren = new IResourceDelta[length];
2077 // orphanChildren[i] = child;
2079 // } catch (JavaModelException e) {
2082 // oneChildOnClasspath = true;
2085 // oneChildOnClasspath = true; // to avoid reporting child delta as non-java resource delta
2088 // // if child is a nested root
2089 // // or if it is not a package fragment root of the current project
2090 // // but it is a package fragment root of another project, traverse delta too
2092 // || (childRootInfo == null && (childRootInfo = this.rootInfo(childPath, childKind)) != null)) {
2093 // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT, childRootInfo, null); // binary output of childRootInfo.project cannot be this root
2094 // // NB: No need to check the return value as the child can only be on the classpath
2097 // // if the child is a package fragment root of one or several other projects
2098 // ArrayList rootList;
2099 // if ((rootList = this.otherRootsInfo(childPath, childKind)) != null) {
2100 // Iterator iterator = rootList.iterator();
2101 // while (iterator.hasNext()) {
2102 // childRootInfo = (RootInfo) iterator.next();
2103 // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT, childRootInfo, null); // binary output of childRootInfo.project cannot be this root
2107 // if (orphanChildren != null
2108 // && (oneChildOnClasspath // orphan children are siblings of a package fragment root
2109 // || res instanceof IProject)) { // non-java resource directly under a project
2111 // // attach orphan children
2112 // IProject rscProject = res.getProject();
2113 // JavaProject adoptiveProject = (JavaProject)JavaCore.create(rscProject);
2114 // if (adoptiveProject != null
2115 // && JavaProject.hasJavaNature(rscProject)) { // delta iff Java project (18698)
2116 // for (int i = 0; i < length; i++) {
2117 // if (orphanChildren[i] != null) {
2119 // nonJavaResourcesChanged(adoptiveProject, orphanChildren[i]);
2120 // } catch (JavaModelException e) {
2125 // } // else resource delta will be added by parent
2126 // return elementType != NON_JAVA_RESOURCE; // TODO: (jerome) do we still need to return? (check could be done by caller)
2128 // return elementType != NON_JAVA_RESOURCE;
2133 * Update the classpath markers and cycle markers for the projects to update.
2135 // void updateClasspathMarkers() {
2137 // if (!ResourcesPlugin.getWorkspace().isAutoBuilding()) {
2138 // Iterator iterator = this.projectsToUpdate.iterator();
2139 // while (iterator.hasNext()) {
2141 // JavaProject project = (JavaProject)iterator.next();
2143 // // force classpath marker refresh
2144 // project.getResolvedClasspath(
2145 // true, // ignoreUnresolvedEntry
2146 // true); // generateMarkerOnError
2148 // } catch (JavaModelException e) {
2152 // if (!this.projectsToUpdate.isEmpty()){
2154 // // update all cycle markers
2155 // JavaProject.updateAllCycleMarkers();
2156 // } catch (JavaModelException e) {
2160 // this.projectsToUpdate = new HashSet();
2165 * Update the current delta (ie. add/remove/change the given element) and update the correponding index.
2166 * Returns whether the children of the given delta must be processed.
2167 * @throws a JavaModelException if the delta doesn't correspond to a java element of the given type.
2169 // private boolean updateCurrentDeltaAndIndex(IResourceDelta delta, int elementType, RootInfo rootInfo) {
2170 // Openable element;
2171 // switch (delta.getKind()) {
2172 // case IResourceDelta.ADDED :
2173 // IResource deltaRes = delta.getResource();
2174 // element = this.createElement(deltaRes, elementType, rootInfo);
2175 // if (element == null) {
2176 // // resource might be containing shared roots (see bug 19058)
2177 // this.updateRoots(deltaRes.getFullPath(), delta);
2180 // this.updateIndex(element, delta);
2181 // this.elementAdded(element, delta, rootInfo);
2183 // case IResourceDelta.REMOVED :
2184 // deltaRes = delta.getResource();
2185 // element = this.createElement(deltaRes, elementType, rootInfo);
2186 // if (element == null) {
2187 // // resource might be containing shared roots (see bug 19058)
2188 // this.updateRoots(deltaRes.getFullPath(), delta);
2191 // this.updateIndex(element, delta);
2192 // this.elementRemoved(element, delta, rootInfo);
2194 // if (deltaRes.getType() == IResource.PROJECT){
2195 // // reset the corresponding project built state, since cannot reuse if added back
2196 // this.manager.setLastBuiltState((IProject)deltaRes, null /*no state*/);
2199 // case IResourceDelta.CHANGED :
2200 // int flags = delta.getFlags();
2201 // if ((flags & IResourceDelta.CONTENT) != 0) {
2202 // // content has changed
2203 // element = this.createElement(delta.getResource(), elementType, rootInfo);
2204 // if (element == null) return false;
2205 // this.updateIndex(element, delta);
2206 // this.contentChanged(element, delta);
2207 // } else if (elementType == IJavaElement.JAVA_PROJECT) {
2208 // if ((flags & IResourceDelta.OPEN) != 0) {
2209 // // project has been opened or closed
2210 // IProject res = (IProject)delta.getResource();
2211 // element = this.createElement(res, elementType, rootInfo);
2212 // if (element == null) {
2213 // // resource might be containing shared roots (see bug 19058)
2214 // this.updateRoots(res.getFullPath(), delta);
2217 // if (res.isOpen()) {
2218 // if (JavaProject.hasJavaNature(res)) {
2219 // this.elementAdded(element, delta, rootInfo);
2220 // this.indexManager.indexAll(res);
2223 // JavaModel javaModel = this.manager.getJavaModel();
2224 // boolean wasJavaProject = javaModel.findJavaProject(res) != null;
2225 // if (wasJavaProject) {
2226 // this.elementRemoved(element, delta, rootInfo);
2227 // this.indexManager.discardJobs(element.getElementName());
2228 // this.indexManager.removeIndexFamily(res.getFullPath());
2232 // return false; // when a project is open/closed don't process children
2234 // if ((flags & IResourceDelta.DESCRIPTION) != 0) {
2235 // IProject res = (IProject)delta.getResource();
2236 // JavaModel javaModel = this.manager.getJavaModel();
2237 // boolean wasJavaProject = javaModel.findJavaProject(res) != null;
2238 // boolean isJavaProject = JavaProject.hasJavaNature(res);
2239 // if (wasJavaProject != isJavaProject) {
2240 // // project's nature has been added or removed
2241 // element = this.createElement(res, elementType, rootInfo);
2242 // if (element == null) return false; // note its resources are still visible as roots to other projects
2243 // if (isJavaProject) {
2244 // this.elementAdded(element, delta, rootInfo);
2245 // this.indexManager.indexAll(res);
2247 // this.elementRemoved(element, delta, rootInfo);
2248 // this.indexManager.discardJobs(element.getElementName());
2249 // this.indexManager.removeIndexFamily(res.getFullPath());
2250 // // reset the corresponding project built state, since cannot reuse if added back
2251 // this.manager.setLastBuiltState(res, null /*no state*/);
2253 // return false; // when a project's nature is added/removed don't process children
2263 * Traverse the set of projects which have changed namespace, and refresh their dependents
2265 // public void updateDependentNamelookups() {
2266 // Iterator iterator;
2267 // // update namelookup of dependent projects
2268 // iterator = this.projectsForDependentNamelookupRefresh.iterator();
2269 // HashSet affectedDependents = new HashSet();
2270 // while (iterator.hasNext()) {
2271 // JavaProject project = (JavaProject)iterator.next();
2272 // addDependentProjects(project.getPath(), affectedDependents);
2274 // iterator = affectedDependents.iterator();
2275 // while (iterator.hasNext()) {
2276 // JavaProject project = (JavaProject) iterator.next();
2277 // if (project.isOpen()){
2279 // ((JavaProjectElementInfo)project.getElementInfo()).setNameLookup(null);
2280 // } catch (JavaModelException e) {
2286 //protected void updateIndex(Openable element, IResourceDelta delta) {
2288 // if (indexManager == null)
2291 // switch (element.getElementType()) {
2292 // case IJavaElement.JAVA_PROJECT :
2293 // switch (delta.getKind()) {
2294 // case IResourceDelta.ADDED :
2295 // this.indexManager.indexAll(element.getJavaProject().getProject());
2297 // case IResourceDelta.REMOVED :
2298 // this.indexManager.removeIndexFamily(element.getJavaProject().getProject().getFullPath());
2299 // // NB: Discarding index jobs belonging to this project was done during PRE_DELETE
2301 // // NB: Update of index if project is opened, closed, or its java nature is added or removed
2302 // // is done in updateCurrentDeltaAndIndex
2305 // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
2306 // if (element instanceof JarPackageFragmentRoot) {
2307 // JarPackageFragmentRoot root = (JarPackageFragmentRoot)element;
2308 // // index jar file only once (if the root is in its declaring project)
2309 // IPath jarPath = root.getPath();
2310 // switch (delta.getKind()) {
2311 // case IResourceDelta.ADDED:
2312 // // index the new jar
2313 // indexManager.indexLibrary(jarPath, root.getJavaProject().getProject());
2315 // case IResourceDelta.CHANGED:
2316 // // first remove the index so that it is forced to be re-indexed
2317 // indexManager.removeIndex(jarPath);
2318 // // then index the jar
2319 // indexManager.indexLibrary(jarPath, root.getJavaProject().getProject());
2321 // case IResourceDelta.REMOVED:
2322 // // the jar was physically removed: remove the index
2323 // this.indexManager.discardJobs(jarPath.toString());
2324 // this.indexManager.removeIndex(jarPath);
2329 // int kind = delta.getKind();
2330 // if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
2331 // IPackageFragmentRoot root = (IPackageFragmentRoot)element;
2332 // this.updateRootIndex(root, root.getPackageFragment(""), delta); //$NON-NLS-1$
2336 // // don't break as packages of the package fragment root can be indexed below
2337 // case IJavaElement.PACKAGE_FRAGMENT :
2338 // switch (delta.getKind()) {
2339 // case IResourceDelta.ADDED:
2340 // case IResourceDelta.REMOVED:
2341 // IPackageFragment pkg = null;
2342 // if (element instanceof IPackageFragmentRoot) {
2343 // IPackageFragmentRoot root = (IPackageFragmentRoot)element;
2344 // pkg = root.getPackageFragment(""); //$NON-NLS-1$
2346 // pkg = (IPackageFragment)element;
2348 // IResourceDelta[] children = delta.getAffectedChildren();
2349 // for (int i = 0, length = children.length; i < length; i++) {
2350 // IResourceDelta child = children[i];
2351 // IResource resource = child.getResource();
2352 // if (resource instanceof IFile) {
2353 // String name = resource.getName();
2354 // if (Util.isJavaFileName(name)) {
2355 // Openable cu = (Openable)pkg.getCompilationUnit(name);
2356 // this.updateIndex(cu, child);
2357 // } else if (Util.isClassFileName(name)) {
2358 // Openable classFile = (Openable)pkg.getClassFile(name);
2359 // this.updateIndex(classFile, child);
2366 // case IJavaElement.CLASS_FILE :
2367 // IFile file = (IFile) delta.getResource();
2368 // IJavaProject project = element.getJavaProject();
2369 // IPath binaryFolderPath = element.getPackageFragmentRoot().getPath();
2370 // // if the class file is part of the binary output, it has been created by
2371 // // the java builder -> ignore
2373 // if (binaryFolderPath.equals(project.getOutputLocation())) {
2376 // } catch (JavaModelException e) {
2378 // switch (delta.getKind()) {
2379 // case IResourceDelta.CHANGED :
2380 // // no need to index if the content has not changed
2381 // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0)
2383 // case IResourceDelta.ADDED :
2384 // indexManager.addBinary(file, binaryFolderPath);
2386 // case IResourceDelta.REMOVED :
2387 // indexManager.remove(file.getFullPath().toString(), binaryFolderPath);
2391 // case IJavaElement.COMPILATION_UNIT :
2392 // file = (IFile) delta.getResource();
2393 // switch (delta.getKind()) {
2394 // case IResourceDelta.CHANGED :
2395 // // no need to index if the content has not changed
2396 // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0)
2398 // case IResourceDelta.ADDED :
2399 // indexManager.addSource(file, file.getProject().getProject().getFullPath());
2401 // case IResourceDelta.REMOVED :
2402 // indexManager.remove(file.getFullPath().toString(), file.getProject().getProject().getFullPath());
2408 * Upadtes the index of the given root (assuming it's an addition or a removal).
2409 * This is done recusively, pkg being the current package.
2411 //private void updateRootIndex(IPackageFragmentRoot root, IPackageFragment pkg, IResourceDelta delta) {
2412 // this.updateIndex((Openable)pkg, delta);
2413 // IResourceDelta[] children = delta.getAffectedChildren();
2414 // String name = pkg.getElementName();
2415 // for (int i = 0, length = children.length; i < length; i++) {
2416 // IResourceDelta child = children[i];
2417 // IResource resource = child.getResource();
2418 // if (resource instanceof IFolder) {
2419 // String subpkgName =
2420 // name.length() == 0 ?
2421 // resource.getName() :
2422 // name + "." + resource.getName(); //$NON-NLS-1$
2423 // IPackageFragment subpkg = root.getPackageFragment(subpkgName);
2424 // this.updateRootIndex(root, subpkg, child);
2429 * Update the roots that are affected by the addition or the removal of the given container resource.
2431 //private void updateRoots(IPath containerPath, IResourceDelta containerDelta) {
2434 // if (containerDelta.getKind() == IResourceDelta.REMOVED) {
2435 // roots = this.oldRoots;
2436 // otherRoots = this.oldOtherRoots;
2438 // roots = this.roots;
2439 // otherRoots = this.otherRoots;
2441 // Iterator iterator = roots.keySet().iterator();
2442 // while (iterator.hasNext()) {
2443 // IPath path = (IPath)iterator.next();
2444 // if (containerPath.isPrefixOf(path) && !containerPath.equals(path)) {
2445 // IResourceDelta rootDelta = containerDelta.findMember(path.removeFirstSegments(1));
2446 // if (rootDelta == null) continue;
2447 // RootInfo rootInfo = (RootInfo)roots.get(path);
2449 // if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider roots that are not included in the container
2450 // this.updateCurrentDeltaAndIndex(rootDelta, IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);
2453 // ArrayList rootList = (ArrayList)otherRoots.get(path);
2454 // if (rootList != null) {
2455 // Iterator otherProjects = rootList.iterator();
2456 // while (otherProjects.hasNext()) {
2457 // rootInfo = (RootInfo)otherProjects.next();
2458 // if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider roots that are not included in the container
2459 // this.updateCurrentDeltaAndIndex(rootDelta, IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);