/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.internal.lookup.workingcopy; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.edt.compiler.core.ast.File; import org.eclipse.edt.compiler.internal.core.builder.BuildException; import org.eclipse.edt.compiler.internal.util.PackageAndPartName; import org.eclipse.edt.ide.core.EDTCoreIDEPlugin; import org.eclipse.edt.ide.core.CoreIDEPluginStrings; import org.eclipse.edt.ide.core.internal.builder.workingcopy.WorkingCopyDuplicatePartManager; import org.eclipse.edt.ide.core.internal.builder.workingcopy.WorkingCopyDuplicatePartRequestor; import org.eclipse.edt.ide.core.internal.compiler.workingcopy.WorkingCopyASTManager; import org.eclipse.edt.ide.core.internal.compiler.workingcopy.WorkingCopyCompiler; import org.eclipse.edt.ide.core.internal.lookup.FileInfoDifferencer; import org.eclipse.edt.ide.core.internal.lookup.IFileInfo; import org.eclipse.edt.ide.core.internal.lookup.IFileInfoDifferenceNotificationRequestor; import org.eclipse.edt.ide.core.internal.lookup.ZipFileBuildPathEntryManager; import org.eclipse.edt.ide.core.internal.model.EGLProject; import org.eclipse.edt.ide.core.internal.utils.Util; import org.eclipse.edt.mof.utils.NameUtile; /** */ public class WorkingCopyResourceChangeProcessor implements IResourceChangeListener { private static final WorkingCopyResourceChangeProcessor INSTANCE = new WorkingCopyResourceChangeProcessor(); protected List listeners = new ArrayList(); private WorkingCopyResourceChangeProcessor(){} public static WorkingCopyResourceChangeProcessor getInstance(){ return INSTANCE; } public void addListener(IWorkingCopyModelUpdateListener listener){ listeners.add(listener); } public void removeListener(IWorkingCopyModelUpdateListener listener){ listeners.remove(listener); } private abstract class Delta{ public static final int ADDED = 0; public static final int REMOVED = 1; public static final int CHANGED = 2; public static final int FILE = 0; public static final int PACKAGE = 1; public static final int PROJECT = 2; private IProject project; private int deltaType; public Delta(IProject project, int deltaType){ this.project = project; this.deltaType = deltaType; } public int getDeltaType(){ return deltaType; } public IProject getProject(){ return project; } public abstract int getResourceType(); } private class ProjectDelta extends Delta { public ProjectDelta(IProject project, int deltaType) { super(project, deltaType); } public int getResourceType() { return PROJECT; } } private class FileDelta extends Delta { private IFile file; private String packageName; public FileDelta(IProject project, int deltaType, String packageName, IFile file) { super(project, deltaType); this.file = file; this.packageName = packageName; } public int getResourceType() { return FILE; } public IFile getFile(){ return file; } public String getPackageName(){ return packageName; } } private class PackageDelta extends Delta { private IResource packageResource; private String packageName; private List removedFiles; public PackageDelta(IProject project, int deltaType, String packageName, List removedFiles, IResource packageResource) { super(project, deltaType); this.packageResource = packageResource; this.packageName = packageName; this.removedFiles = removedFiles; } public int getResourceType() { return PACKAGE; } public String getPackageName(){ return packageName; } public List getRemovedFiles(){ return removedFiles; } public IResource getPackage(){ return packageResource; } } public abstract class WorkingCopyJob extends WorkspaceJob{ public WorkingCopyJob(String jobName) { super(jobName); setSystem(false); setPriority(Job.LONG); setRule(ResourcesPlugin.getWorkspace().getRoot()); } public boolean belongsTo(Object family) { return family == FAMILY_WORKING_COPY_JOB; } public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { WorkingCopyBuildNotifier.getInstance().setCanceled(true); // we are about to rebuild the models return doRun(monitor); } protected abstract IStatus doRun(IProgressMonitor monitor); } /** * This job implementation is used to allow the resource change listener * to schedule operations that need to modify the workspace. */ private class WorkingCopyInitializeJob extends WorkingCopyJob { public WorkingCopyInitializeJob() { super(CoreIDEPluginStrings.WorkingCopyCompiler_InitializeJobName); } public boolean belongsTo(Object family) { return (family == FAMILY_WORKING_COPY_INITIALIZE_JOB || super.belongsTo(family)); } public boolean shouldRun() { return super.shouldRun() && !WorkingCopyFileInfoManager.getInstance().hasValidState(); } protected IStatus doRun(IProgressMonitor monitor){ try{ try{ // TODO: Future - WorkingCopyBuildNotifier.getInstance().setCanceled(true); // a resource has changed, cancel the working copy compiler WorkingCopyCompiler.lock.acquire(); // wait for the working copy compiler resourceChangeJob.clear(); WorkingCopyASTManager.getInstance().clear(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (int i = 0; i < projects.length; i++) { IProject project = projects[i]; // Add the project if it is an EGL Project and the project is open if(project.isOpen() && EGLProject.hasEGLNature(project)){ // Clear out the existing information WorkingCopyDuplicatePartManager.getInstance().clear(project); WorkingCopyFileInfoManager.getInstance().clear(project); WorkingCopyProjectInfoManager.getInstance().clear(project); initialize(project); WorkingCopyDuplicatePartManager.getInstance().saveDuplicatePartList(project); } } WorkingCopyFileInfoManager.getInstance().setState(true); }catch(RuntimeException e){ // For all exceptions, mark the file info manager as having an invalid state WorkingCopyFileInfoManager.getInstance().setState(false); EDTCoreIDEPlugin.getPlugin().log(this.getName() + " Failure", e); //$NON-NLS-1$ }finally{ WorkingCopyCompiler.lock.release(); // release the lock so the WCC can run again } }finally{ if(WorkingCopyFileInfoManager.getInstance().hasValidState()){ } } return Status.OK_STATUS; } public void initialize(final IProject project) { try{ IContainer[] sourceLocations = WorkingCopyProjectBuildPathManager.getInstance().getProjectBuildPath(project).getSourceLocations(); for (int i = 0, l = sourceLocations.length; i < l; i++) { final IContainer sourceLocation = sourceLocations[i]; final int segmentCount = sourceLocation.getFullPath().segmentCount(); IResource[] children = sourceLocation.members(); for (int j = 0; j < children.length; j++) { children[j].accept( new IResourceProxyVisitor() { public boolean visit(IResourceProxy proxy) throws CoreException { IResource resource = proxy.requestResource(); switch(proxy.getType()) { case IResource.FILE : if (org.eclipse.edt.ide.core.internal.model.Util.isEGLFileName(proxy.getName())) { IFile file = (IFile)resource; String packageName = NameUtile.getAsName(Util.pathToQualifiedName(resource.getFullPath().removeFirstSegments(segmentCount).removeLastSegments(1))); try { String fileContents = Util.getFileContents(file); File fileAST = WorkingCopyASTManager.getInstance().getFileAST(file, fileContents); IFileInfo info = new WorkingCopyCompilerResourceFileInfoCreator(WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project), packageName, file, fileAST, fileContents, new WorkingCopyDuplicatePartRequestor(project, packageName, file), true).getASTInfo(); WorkingCopyProjectInfo projectInfo = WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project); Iterator iter = info.getPartNames().iterator(); while (iter.hasNext()){ String partName = (String)iter.next(); PackageAndPartName ppName = new PackageAndPartName(info.getCaseSensitivePackageName(), info.getCaseSensitivePartName(partName)); projectInfo.partAdded(packageName,partName, info.getPartType(partName), file, ppName); } WorkingCopyFileInfoManager.getInstance().saveFileInfo(project, file.getProjectRelativePath(), info); }catch(Exception e){ throw new RuntimeException("Error initializing file: " + file.getProjectRelativePath(), e); } } return false; } return true; } }, IResource.NONE ); } } }catch(CoreException e){ throw new BuildException(e); } } } /** * This job implementation is used to allow the resource change listener * to schedule operations that need to modify the workspace. */ private class WorkingCopyResourceChangeJob extends WorkingCopyJob { private List asyncChanges = new ArrayList(); public WorkingCopyResourceChangeJob() { super(CoreIDEPluginStrings.WorkingCopyCompiler_ResourceChangeJobName); } public void clear() { synchronized(asyncChanges) { asyncChanges.clear(); } } public void addChanges(List newChanges) { if (newChanges.isEmpty()){ return; } synchronized (asyncChanges) { asyncChanges.addAll(newChanges); asyncChanges.notify(); } schedule(); } public Delta getNextChange() { synchronized (asyncChanges) { return asyncChanges.isEmpty() ? null : (Delta) asyncChanges.remove(0); } } protected IStatus doRun(IProgressMonitor monitor) { try{ try{ // TODO: Future - WorkingCopyBuildNotifier.getInstance().setCanceled(true); // a resource has changed, cancel the working copy compiler WorkingCopyCompiler.lock.acquire(); // wait for the working copy compiler WorkingCopyASTManager.getInstance().clear(); // flush the AST manager List changedProjects = new ArrayList(); Delta delta; while ((delta = getNextChange()) != null) { IProject project = delta.getProject(); int resourceType = delta.getResourceType(); int deltaType = delta.getDeltaType(); if(resourceType == Delta.FILE || resourceType == Delta.PACKAGE){ // Make sure that this project wasn't removed or closed already if(project.exists() && project.isOpen()){ changedProjects.add(project); // keep track of which projects we've changed if(resourceType == Delta.FILE){ switch(deltaType){ case Delta.ADDED: processAddedFile(delta.getProject(), ((FileDelta)delta).getPackageName(), ((FileDelta)delta).getFile()); break; case Delta.REMOVED: processRemovedFile(delta.getProject(), ((FileDelta)delta).getPackageName(), ((FileDelta)delta).getFile()); break; case Delta.CHANGED: processChangedFile(delta.getProject(), ((FileDelta)delta).getPackageName(), ((FileDelta)delta).getFile()); break; } }else{ switch(deltaType){ case Delta.ADDED: processAddedPackage(delta.getProject(), ((PackageDelta)delta).getPackageName(), ((PackageDelta)delta).getPackage()); break; case Delta.REMOVED: processRemovedPackage(delta.getProject(), ((PackageDelta)delta).getPackageName(), ((PackageDelta)delta).getPackage(), ((PackageDelta)delta).getRemovedFiles()); break; } } } }else if(resourceType == Delta.PROJECT){ switch(deltaType){ case Delta.REMOVED: processRemovedProject(delta.getProject()); break; } } } // Save the duplicate parts list for these projects for (Iterator iter = changedProjects.iterator(); iter.hasNext();) { IProject project = (IProject) iter.next(); WorkingCopyDuplicatePartManager.getInstance().saveDuplicatePartList(project); } changedProjects.clear(); }catch(RuntimeException e){ // For all exceptions, mark the file info manager as having an invalid state WorkingCopyFileInfoManager.getInstance().setState(false); EDTCoreIDEPlugin.getPlugin().log(this.getName() + " Failure", e); //$NON-NLS-1$ }finally{ WorkingCopyCompiler.lock.release(); // release the lock so the WCC can start up again } }finally{ if(WorkingCopyFileInfoManager.getInstance().hasValidState()){ notifyListeners(); } } return Status.OK_STATUS; } private void notifyListeners(){ for (Iterator iter = listeners.iterator(); iter.hasNext();) { IWorkingCopyModelUpdateListener listener = (IWorkingCopyModelUpdateListener) iter.next(); listener.modelChanged(); } } /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#shouldRun() */ public boolean shouldRun() { synchronized (asyncChanges) { return !asyncChanges.isEmpty(); } } public boolean belongsTo(Object family) { return (family == FAMILY_WORKING_COPY_RESOURCE_CHANGE_JOB || super.belongsTo(family)); } private void processRemovedProject(IProject project){ ZipFileBuildPathEntryManager.getWCCInstance().clear(project); WorkingCopyFileInfoManager.getInstance().removeProject(project); // Cached FileInfos WorkingCopyProjectEnvironmentManager.getInstance().remove(project); // Environment WorkingCopyProjectBuildPathEntryManager.getInstance().remove(project); WorkingCopyProjectInfoManager.getInstance().remove(project); // ProjectInfo WorkingCopyDuplicatePartManager.getInstance().remove(project); // Duplicate Parts WorkingCopyProjectBuildPathManager.getInstance().remove(project); } private void processAddedPackage(IProject project, String packageName, IResource packageResource) { // Make sure that the resource wasn't removed before we could process this add if(packageResource.exists()){ WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project).packageAdded(NameUtile.getAsName(packageName)); } } private void processRemovedPackage(IProject project, String packageName, IResource packageResource, List removedFiles) { WorkingCopyProjectInfo projectInfo = WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project); // Make sure that the package exists in our model - it may have been added and quickly removed, which caused us to throw away the add event if(projectInfo.hasPackage(packageName)){ projectInfo.packageRemoved(packageName); processRemovedPackageHelper(project, removedFiles); WorkingCopyFileInfoManager.getInstance().removePackage(project, packageResource.getProjectRelativePath()); } } private void processRemovedPackageHelper(IProject project, List removedFiles) { for (Iterator iter = removedFiles.iterator(); iter.hasNext();) { FileDelta fileDelta = (FileDelta) iter.next(); HashSet otherFilesToProcess = new HashSet(); IPath filePath = fileDelta.getFile().getProjectRelativePath(); if (org.eclipse.edt.ide.core.internal.model.Util.isEGLFileName(filePath.lastSegment())){ IFileInfo fileInfo = WorkingCopyFileInfoManager.getInstance().getFileInfo(project, filePath); Set partNames = fileInfo.getPartNames(); for (Iterator partNameIter = partNames.iterator(); partNameIter.hasNext();) { String partName = (String) partNameIter.next(); locateDuplicateFile(project, otherFilesToProcess, fileDelta.getPackageName(), partName); } processDuplicateFiles(project, fileDelta.getPackageName(), otherFilesToProcess); WorkingCopyFileInfoManager.getInstance().removeFile(project, filePath); } } } private void processAddedFile(IProject project, String packageName, IFile addedFile) { // Make sure this file wasn't removed before we have a chance to process this add if(addedFile.exists()){ try { String fileContents = Util.getFileContents(addedFile); File fileAST = WorkingCopyASTManager.getInstance().getFileAST(addedFile, fileContents); IFileInfo fileInfo = new WorkingCopyCompilerResourceFileInfoCreator(WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project), packageName, addedFile, fileAST, fileContents, new WorkingCopyDuplicatePartRequestor(project, packageName, addedFile), true).getASTInfo(); Set partNames = fileInfo.getPartNames(); for (Iterator iter = partNames.iterator(); iter.hasNext();) { String partName = (String) iter.next(); PackageAndPartName ppName = new PackageAndPartName(fileInfo.getCaseSensitivePackageName(), fileInfo.getCaseSensitivePartName(partName), packageName); WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project).partAdded(packageName, partName, fileInfo.getPartType(partName), addedFile, ppName); } WorkingCopyFileInfoManager.getInstance().saveFileInfo(project, addedFile.getProjectRelativePath(), fileInfo); }catch(Exception e){ throw new RuntimeException("Error processing added file: " + addedFile.getProjectRelativePath(), e); } } } private void processRemovedFile(IProject project, String packageName, IFile removedFile) { WorkingCopyProjectInfo projectInfo = WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project); IFileInfo fileInfo = WorkingCopyFileInfoManager.getInstance().getFileInfo(project, removedFile.getProjectRelativePath()); // Make sure we have this file in our model - we may have skipped the add event because the file had already been deleted if(fileInfo != null){ HashSet otherFilesToProcess = new HashSet(); Set partNames = fileInfo.getPartNames(); for (Iterator iter = partNames.iterator(); iter.hasNext();) { String partName = (String) iter.next(); projectInfo.partRemoved(packageName, partName, removedFile); locateDuplicateFile(project, otherFilesToProcess, packageName, partName); } WorkingCopyFileInfoManager.getInstance().removeFile(project, removedFile.getProjectRelativePath()); processDuplicateFiles(project, packageName, otherFilesToProcess); WorkingCopyDuplicatePartManager.getInstance().getDuplicatePartList(project).remove(removedFile); } } private void processChangedFile(final IProject project, final String packageName, final IFile changedFile) { // Make sure that the changed file hasn't been removed if(changedFile.exists()){ try { String fileContents = Util.getFileContents(changedFile); final HashSet duplicateFlies = new HashSet(); File fileAST = WorkingCopyASTManager.getInstance().getFileAST(changedFile, fileContents); final IFileInfo newInfo = new WorkingCopyCompilerResourceFileInfoCreator(WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project), packageName, changedFile, fileAST, fileContents, new WorkingCopyDuplicatePartRequestor(project, packageName, changedFile), true).getASTInfo(); final IFileInfo oldFileInfo = WorkingCopyFileInfoManager.getInstance().getFileInfo(project, changedFile.getProjectRelativePath()); final WorkingCopyProjectInfo projectInfo = WorkingCopyProjectInfoManager.getInstance().getProjectInfo(project); IFileInfoDifferenceNotificationRequestor requestor = new IFileInfoDifferenceNotificationRequestor(){ public void partAdded(String partName) { PackageAndPartName ppName = new PackageAndPartName(newInfo.getCaseSensitivePackageName(), newInfo.getCaseSensitivePartName(partName)); projectInfo.partAdded(packageName, partName, newInfo.getPartType(partName), changedFile, ppName); } public void partRemoved(String partName){ projectInfo.partRemoved(packageName, partName, changedFile); locateDuplicateFile(project, duplicateFlies, packageName, partName); } public void partChanged(String partName){ // noop } }; FileInfoDifferencer differ = new FileInfoDifferencer( requestor ); differ.findDifferences(oldFileInfo, newInfo); WorkingCopyFileInfoManager.getInstance().saveFileInfo(project, changedFile.getProjectRelativePath(), newInfo); processDuplicateFiles(project, packageName, duplicateFlies); }catch(Exception e){ throw new RuntimeException("Error processing changed file: " + changedFile.getProjectRelativePath(), e); } } } private void processDuplicateFiles(IProject project, String packageName, HashSet otherFilesToProcess) { for (Iterator iter = otherFilesToProcess.iterator(); iter.hasNext();) { IFile file = (IFile) iter.next(); processChangedFile(project, packageName, file); } } protected void locateDuplicateFile(IProject project, HashSet otherFilesToProcess, String packageName, String partName) { Set filesForDuplicatePart = WorkingCopyDuplicatePartManager.getInstance().getDuplicatePartList(project).getFilesForDuplicatePart(packageName, partName); if(filesForDuplicatePart != null){ for (Iterator filesIter = filesForDuplicatePart.iterator(); filesIter.hasNext();) { IFile file = (IFile) filesIter.next(); if(file.exists()){ // this file may have been removed in the same delta otherFilesToProcess.add(file); break; } } } } } private class ResourceChangeProcessor{ private IContainer[] sourceLocations; private IProject project; private List changes = new ArrayList(); public ResourceChangeProcessor(IProject project){ this.project = project; this.sourceLocations = WorkingCopyProjectBuildPathManager.getInstance().getProjectBuildPath(project).getSourceLocations(); } public boolean processDeltas(IResourceDelta delta) { for (int i = 0, l = sourceLocations.length; i < l; i++) { IContainer sourceLocation = sourceLocations[i]; if (sourceLocation.equals(project)) { // skip nested source & output folders when the project is a source folder int segmentCount = delta.getFullPath().segmentCount(); IResourceDelta[] children = delta.getAffectedChildren(); for (int j = 0, m = children.length; j < m; j++) processDeltas(children[j], segmentCount); } else { IResourceDelta sourceDelta = delta.findMember(sourceLocation.getProjectRelativePath()); if (sourceDelta != null) { // TODO Remove this check, or throw exception, since we should never get here... if (sourceDelta.getKind() == IResourceDelta.REMOVED) { System.out.println("ABORTING incremental build... found removed source folder"); //$NON-NLS-1$ return false; // removed source folder should not make it here, but handle anyways (ADDED is supported) } int segmentCount = sourceDelta.getFullPath().segmentCount(); IResourceDelta[] children = sourceDelta.getAffectedChildren(); for (int j = 0, m = children.length; j < m; j++) processDeltas(children[j], segmentCount); } } } resourceChangeJob.addChanges(changes); return true; } private void processDeltas(IResourceDelta sourceDelta, int segmentCount){ IResource resource = sourceDelta.getResource(); switch(resource.getType()) { case IResource.FOLDER : switch (sourceDelta.getKind()) { case IResourceDelta.ADDED : IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount); changes.add(new PackageDelta(project, Delta.ADDED, NameUtile.getAsName(Util.pathToQualifiedName(addedPackagePath)), Collections.EMPTY_LIST, resource)); // fall thru & collect all the source files case IResourceDelta.CHANGED : IResourceDelta[] children = sourceDelta.getAffectedChildren(); for (int i = 0, l = children.length; i < l; i++){ processDeltas(children[i], segmentCount); } return; case IResourceDelta.REMOVED : IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount); if (sourceLocations.length > 1) { for (int i = 0, l = sourceLocations.length; i < l; i++) { if (sourceLocations[i].getFolder(removedPackagePath).exists()) { // a package was removed from one source folder, but there is the same package in another folder // Technically this is no longer a removed package IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren(); for (int j = 0, m = removedChildren.length; j < m; j++) processDeltas(removedChildren[j], segmentCount); return; } } } List removedFiles = new ArrayList(); processRemovedPackageHelper(NameUtile.getAsName(Util.pathToQualifiedName(removedPackagePath)), sourceDelta.getAffectedChildren(), removedFiles); changes.add(new PackageDelta(project, Delta.REMOVED, NameUtile.getAsName(Util.pathToQualifiedName(removedPackagePath)), removedFiles, resource)); return; } case IResource.FILE : String resourceName = resource.getName(); // TODO Remove dependency on TModel if (org.eclipse.edt.ide.core.internal.model.Util.isEGLFileName(resourceName)) { IPath packagePath = resource.getFullPath().removeFirstSegments(segmentCount).removeLastSegments(1); switch (sourceDelta.getKind()) { case IResourceDelta.ADDED : changes.add(new FileDelta(project, Delta.ADDED, NameUtile.getAsName(Util.pathToQualifiedName(packagePath)), (IFile)resource)); return; case IResourceDelta.REMOVED : changes.add(new FileDelta(project, Delta.REMOVED, NameUtile.getAsName(Util.pathToQualifiedName(packagePath)), (IFile)resource)); return; case IResourceDelta.CHANGED : if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0){ return; // skip it since it really isn't changed } changes.add(new FileDelta(project, Delta.CHANGED, NameUtile.getAsName(Util.pathToQualifiedName(packagePath)), (IFile)resource)); return; } return; } return; } } private void processRemovedPackageHelper(String packageName, IResourceDelta[] children, List removedFiles){ for (int i = 0; i < children.length; i++) { IResource resource = children[i].getResource(); switch(resource.getType()) { case IResource.FOLDER : String subPackageName = org.eclipse.edt.ide.core.internal.utils.Util.appendToQualifiedName(packageName, resource.getName(), "."); processRemovedPackageHelper(NameUtile.getAsName(subPackageName), children[i].getAffectedChildren(), removedFiles); break; case IResource.FILE : removedFiles.add(new FileDelta(project, Delta.REMOVED, packageName, (IFile)resource)); break; } } } } public static final Object FAMILY_WORKING_COPY_JOB = new Object(); public static final Object FAMILY_WORKING_COPY_RESOURCE_CHANGE_JOB = new Object(); public static final Object FAMILY_WORKING_COPY_INITIALIZE_JOB = new Object(); protected WorkingCopyResourceChangeJob resourceChangeJob = new WorkingCopyResourceChangeJob(); protected WorkingCopyInitializeJob initializeJob = new WorkingCopyInitializeJob(); public void resourceChanged(IResourceChangeEvent event) { final boolean projectDeleting = event.getType() == IResourceChangeEvent.PRE_DELETE; final boolean projectClosing = event.getType() == IResourceChangeEvent.PRE_CLOSE; final boolean postChange = event.getType() == IResourceChangeEvent.POST_CHANGE; if (projectDeleting || projectClosing){ this.processProjectDelete((IProject)event.getResource()); }else if(postChange){ // We use post change because we know that the builder models that we use are now up to date this.processPostChange(event.getDelta()); } } public void processPostChange(IResourceDelta delta) { if(delta == null || !WorkingCopyFileInfoManager.getInstance().hasValidState()){ initializeWorkingCopyIndex(); }else{ IResourceDelta[] affectedChildren = delta.getAffectedChildren(); for (int i = 0; i < affectedChildren.length; i++) { IResource child = affectedChildren[i].getResource(); if(child.getType() == IResource.PROJECT && EGLProject.hasEGLNature((IProject)child)) { ResourceChangeProcessor processor = new ResourceChangeProcessor((IProject)child); processor.processDeltas(affectedChildren[i]); } } } } public void initializeWorkingCopyIndex(){ WorkingCopyFileInfoManager.getInstance().setState(false); // invalidate the current state resourceChangeJob.cancel(); // stop processing incremental deltas, because we are going to rebuild everything initializeJob.schedule(); } private void processProjectDelete(IProject project){ if (EGLProject.hasEGLNature(project)) { ArrayList changes = new ArrayList(1); changes.add(new ProjectDelta(project, Delta.REMOVED)); resourceChangeJob.addChanges(changes); } } }