| /******************************************************************************* |
| * Copyright (c) 2009, 2019 Xored Software Inc 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 |
| * https://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Xored Software Inc - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.rcptt.internal.core.model.deltas; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| 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.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.SafeRunner; |
| |
| import org.eclipse.rcptt.core.model.IElementChangedListener; |
| import org.eclipse.rcptt.core.model.IQ7Element; |
| import org.eclipse.rcptt.core.model.IQ7Element.HandleType; |
| import org.eclipse.rcptt.core.model.IQ7ElementDelta; |
| import org.eclipse.rcptt.core.model.IQ7Folder; |
| import org.eclipse.rcptt.core.model.IQ7Model; |
| import org.eclipse.rcptt.core.model.IQ7NamedElement; |
| import org.eclipse.rcptt.core.model.IQ7Project; |
| import org.eclipse.rcptt.core.model.ModelException; |
| import org.eclipse.rcptt.core.model.Q7ElementChangedEvent; |
| import org.eclipse.rcptt.core.workspace.RcpttCore; |
| import org.eclipse.rcptt.internal.core.model.ModelInfo; |
| import org.eclipse.rcptt.internal.core.model.ModelManager; |
| import org.eclipse.rcptt.internal.core.model.Openable; |
| import org.eclipse.rcptt.internal.core.model.Q7ElementInfo; |
| import org.eclipse.rcptt.internal.core.model.Q7FolderInfo; |
| import org.eclipse.rcptt.internal.core.model.Q7Model; |
| import org.eclipse.rcptt.internal.core.model.Q7NamedElement; |
| import org.eclipse.rcptt.internal.core.model.Q7Project; |
| import org.eclipse.rcptt.internal.core.model.Q7ProjectInfo; |
| import org.eclipse.rcptt.internal.core.model.index.IndexManager; |
| import org.eclipse.rcptt.internal.core.model.index.ProjectIndexerManager; |
| |
| public class DeltaProcessor { |
| public static boolean DEBUG = false; |
| public static boolean VERBOSE = false; |
| public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with |
| |
| // ElementChangedEvent |
| // event masks |
| |
| public static long getTimeStamp(IFile file) { |
| long lmodif = 0; |
| lmodif = file.getModificationStamp(); |
| return lmodif; |
| } |
| |
| /* |
| * The global state of delta processing. |
| */ |
| private final DeltaProcessingState state; |
| /* |
| * The q7 model manager |
| */ |
| ModelManager manager; |
| /* |
| * The <code>ModelElementDelta</code> corresponding to the |
| * <code>IResourceDelta</code> being translated. |
| */ |
| private Q7ElementDelta currentDelta; |
| /* |
| * The model element that was last created (see createElement(IResource)). |
| * This is used as a stack of model elements (using getParent() to pop it, |
| * and using the various get(...) to push it. |
| */ |
| private Openable currentElement; |
| /* |
| * Queue of deltas created explicily by the q7 Model that have yet to be |
| * fired. |
| */ |
| public ArrayList<IQ7ElementDelta> modelDeltas = new ArrayList<IQ7ElementDelta>(); |
| /* |
| * Queue of reconcile deltas on working copies that have yet to be fired. |
| * This is a table form IWorkingCopy to IQ7ElementDelta |
| */ |
| @SuppressWarnings("rawtypes") |
| public HashMap reconcileDeltas = new HashMap(); |
| /* |
| * Turns delta firing on/off. By default it is on. |
| */ |
| private boolean isFiring = true; |
| /* |
| * Used to update the Model for <code>IQ7ElementDelta</code>s. |
| */ |
| private final ModelUpdater modelUpdater = new ModelUpdater(); |
| /* A set of IDLTKProject whose caches need to be reset */ |
| private final HashSet<IQ7Project> projectCachesToReset = new HashSet<IQ7Project>(); |
| /* |
| * A list of IQ7Element used as a scope for external archives refresh during |
| * POST_CHANGE. This is null if no refresh is needed. |
| */ |
| private HashSet<IQ7Element> refreshedElements; |
| |
| /* A set of IDylanProject whose package fragment roots need to be refreshed */ |
| private final HashSet<IQ7Project> rootsToRefresh = new HashSet<IQ7Project>(); |
| /** {@link Runnable}s that should be called after model is updated */ |
| private final ArrayList<Runnable> postActions = new ArrayList<Runnable>(); |
| /* |
| * Type of event that should be processed no matter what the real event type |
| * is. |
| */ |
| public int overridenEventType = -1; |
| |
| // /* |
| // * Map from IProject to BuildpathChange |
| // */ |
| // public HashMap buildpathChanges = new HashMap(); |
| |
| public DeltaProcessor(DeltaProcessingState state, ModelManager manager) { |
| this.state = state; |
| this.manager = manager; |
| } |
| |
| /* |
| * Adds the dependents of the given project to the list of the projects to |
| * update. |
| */ |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| private void addDependentProjects(IQ7Project project, HashMap projectDependencies, |
| HashSet result) { |
| IQ7Project[] dependents = (IQ7Project[]) projectDependencies.get(project); |
| if (dependents == null) { |
| return; |
| } |
| for (int i = 0, length = dependents.length; i < length; i++) { |
| IQ7Project dependent = dependents[i]; |
| if (result.contains(dependent)) { |
| continue; // no need to go further as the project is already |
| } |
| // known |
| result.add(dependent); |
| this.addDependentProjects(dependent, projectDependencies, result); |
| } |
| } |
| |
| /* |
| * Adds the given element to the list of elements used as a scope for |
| * external jars refresh. |
| */ |
| public void addForRefresh(IQ7Element element) { |
| if (this.refreshedElements == null) { |
| this.refreshedElements = new HashSet<IQ7Element>(); |
| } |
| this.refreshedElements.add(element); |
| } |
| |
| /* |
| * Adds the given child handle to its parent's cache of children. |
| */ |
| private void addToParentInfo(Openable child) { |
| Openable parent = (Openable) child.getParent(); |
| if (parent != null && parent.isOpen()) { |
| try { |
| Q7ElementInfo info = (Q7ElementInfo) parent.getElementInfo(); |
| info.addChild(child); |
| } catch (ModelException e) { |
| // do nothing - we already checked if open |
| } |
| } |
| } |
| |
| /* |
| * Adds the given project and its dependents to the list of the roots to |
| * refresh. |
| */ |
| private void addToRootsToRefreshWithDependents(IQ7Project q7Project) { |
| this.rootsToRefresh.add(q7Project); |
| this.addDependentProjects(q7Project, this.state.projectDependencies, |
| this.rootsToRefresh); |
| } |
| |
| private void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) { |
| IResource resource = delta.getResource(); |
| IResourceDelta[] children = null; |
| |
| switch (resource.getType()) { |
| case IResource.ROOT: |
| // workaround for bug 15168 circular errors not reported |
| this.state.getOldProjectNames(); // force list to be computed |
| children = delta.getAffectedChildren(); |
| break; |
| case IResource.PROJECT: |
| // NB: No need to check project's nature as if the project is not a |
| // q7 project: |
| // - if the project is added or changed this is a noop for |
| // projectsBeingDeleted |
| // - if the project is closed, it has already lost its q7 nature |
| IProject project = (IProject) resource; |
| Q7Project q7Project = (Q7Project) RcpttCore.create(project); |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| // remember project and its dependents |
| this.addToRootsToRefreshWithDependents(q7Project); |
| |
| // workaround for bug 15168 circular errors not reported |
| if (RcpttCore.hasRcpttNature(project)) { |
| this.addToParentInfo(q7Project); |
| } |
| break; |
| |
| case IResourceDelta.CHANGED: |
| if ((delta.getFlags() & IResourceDelta.OPEN) != 0) { |
| // project opened or closed: remember project and its |
| // dependents |
| this.addToRootsToRefreshWithDependents(q7Project); |
| |
| // workaround for bug 15168 circular errors not reported |
| if (project.isOpen()) { |
| if (RcpttCore.hasRcpttNature(project)) { |
| this.addToParentInfo(q7Project); |
| // readRawBuildpath(q7Project); |
| // ensure project references are updated |
| } |
| } else { |
| try { |
| q7Project.close(); |
| } catch (ModelException e) { |
| // q7 project doesn't exist: ignore |
| } |
| this.removeFromParentInfo(q7Project); |
| } |
| } else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) { |
| boolean isQ7Project = RcpttCore.hasRcpttNature(project); |
| // q7 nature added or removed: remember project and |
| // its dependents |
| this.addToRootsToRefreshWithDependents(q7Project); |
| |
| // workaround for bug 15168 circular errors not reported |
| if (isQ7Project) { |
| this.addToParentInfo(q7Project); |
| } else { |
| // close project |
| try { |
| q7Project.close(); |
| } catch (ModelException e) { |
| // q7 project doesn't exist: ignore |
| } |
| this.removeFromParentInfo(q7Project); |
| } |
| } else { |
| if (RcpttCore.hasRcpttNature(project)) { // need |
| this.addToParentInfo(q7Project); |
| children = delta.getAffectedChildren(); |
| } |
| } |
| break; |
| |
| case IResourceDelta.REMOVED: |
| break; |
| } |
| |
| // in all cases, refresh the external jars for this project |
| this.addForRefresh(q7Project); |
| |
| break; |
| // case IResource.FILE: |
| // IFile file = (IFile) resource; |
| // break; |
| } |
| if (children != null) { |
| for (int i = 0; i < children.length; i++) { |
| this.checkProjectsBeingAddedOrRemoved(children[i]); |
| } |
| } |
| } |
| |
| private void close(Openable element) { |
| try { |
| element.close(); |
| } catch (ModelException e) { |
| // do nothing |
| } |
| } |
| |
| private void contentChanged(Openable element) { |
| boolean isPrimaryWorkingCopy = false; |
| if (element.getElementType().equals(HandleType.Context) |
| || element.getElementType().equals(HandleType.Verification) |
| || element.getElementType().equals(HandleType.TestCase) |
| || element.getElementType().equals(HandleType.TestSuite)) { |
| Q7NamedElement cu = (Q7NamedElement) element; |
| isPrimaryWorkingCopy = cu.isWorkingCopy(); |
| } |
| if (element.getElementType().equals(HandleType.ProjectMetadata)) { |
| this.currentDelta().changed(element.getQ7Project(), |
| IQ7ElementDelta.F_DESCRIPTION); |
| } |
| if (isPrimaryWorkingCopy) { |
| this.currentDelta().changed(element, IQ7ElementDelta.F_PRIMARY_RESOURCE); |
| } else { |
| this.currentDelta().changed(element, IQ7ElementDelta.F_CONTENT); |
| } |
| } |
| |
| /* |
| * Creates the openables corresponding to this resource. Returns null if |
| * none was found. |
| */ |
| private Openable createElement(IResource resource, HandleType elementType, |
| Q7Project rootInfo) { |
| if (resource == null) { |
| return null; |
| } |
| |
| IPath path = resource.getFullPath(); |
| IQ7Element element = null; |
| switch (elementType) { |
| case Project: |
| // note that non-q7 resources rooted at the project level will |
| // also enter this code with |
| // an elementType SCRIPT_PROJECT (see #elementType(...)). |
| if (resource instanceof IProject) { |
| this.popUntilPrefixOf(path); |
| if (this.currentElement != null |
| && this.currentElement.getElementType() |
| .equals(HandleType.Project) |
| && ((IQ7Project) this.currentElement).getProject().equals( |
| resource)) { |
| return this.currentElement; |
| } |
| if (rootInfo != null && rootInfo.getProject().equals(resource)) { |
| element = rootInfo; |
| break; |
| } |
| IProject proj = (IProject) resource; |
| if (RcpttCore.hasRcpttNature(proj)) { |
| element = RcpttCore.create(proj); |
| } else { |
| element = this.state.findProject(proj.getName()); |
| } |
| } |
| break; |
| case Folder: |
| if (rootInfo != null) { |
| if (rootInfo.contains(resource)) { |
| // create package handle |
| IPath pkgPath = path.removeFirstSegments(rootInfo.getPath() |
| .segmentCount()); |
| element = rootInfo.getFolder(pkgPath); |
| } |
| } else { |
| // find the element that encloses the resource |
| this.popUntilPrefixOf(path); |
| if (this.currentElement == null) { |
| element = RcpttCore.create(resource); |
| } else { |
| rootInfo = (Q7Project) currentElement.getQ7Project(); |
| if (((Q7Project) rootInfo.getProject()).contains(resource)) { |
| // create package handle |
| IPath pkgPath = path.removeFirstSegments(rootInfo.getPath() |
| .segmentCount()); |
| element = rootInfo.getFolder(pkgPath); |
| } |
| } |
| } |
| break; |
| case TestCase: |
| case Context: |
| case TestSuite: |
| case ProjectMetadata: |
| case Verification: |
| // find the element that encloses the resource |
| this.popUntilPrefixOf(path); |
| if (this.currentElement == null) { |
| element = rootInfo == null ? RcpttCore.create(resource) : ModelManager |
| .create(resource, rootInfo); |
| } else { |
| // find the package |
| IQ7Folder pkgFragment = null; |
| switch (this.currentElement.getElementType()) { |
| case Folder: |
| Openable pkg = this.currentElement; |
| if (pkg.getPath().equals(path.removeLastSegments(1))) { |
| pkgFragment = (IQ7Folder) pkg; |
| } // else case of package x which is a prefix of |
| // x.y |
| break; |
| case TestCase: |
| case Context: |
| case TestSuite: |
| case ProjectMetadata: |
| case Verification: |
| pkgFragment = (IQ7Folder) this.currentElement.getParent(); |
| break; |
| } |
| if (pkgFragment == null) { |
| element = rootInfo == null ? RcpttCore.create(resource) : ModelManager |
| .create(resource, rootInfo); |
| } else { |
| if (elementType.equals(HandleType.Context) |
| || elementType.equals(HandleType.Verification) |
| || elementType.equals(HandleType.TestCase) |
| || elementType.equals(HandleType.TestSuite) |
| || elementType.equals(HandleType.TestSuite)) { |
| String fileName = path.lastSegment(); |
| element = pkgFragment.getNamedElement(fileName); |
| } |
| } |
| } |
| break; |
| } |
| if (element == null) { |
| return null; |
| } |
| this.currentElement = (Openable) element; |
| return this.currentElement; |
| } |
| |
| private Q7ElementDelta currentDelta() { |
| if (this.currentDelta == null) { |
| this.currentDelta = new Q7ElementDelta(this.manager.getModel()); |
| } |
| return this.currentDelta; |
| } |
| |
| /* |
| * Note that the project is about to be deleted. |
| */ |
| private void deleting(IProject project) { |
| |
| try { |
| // discard indexing jobs that belong to this project so that the |
| // project can be |
| // deleted without interferences from the index manager |
| this.manager.getIndexManager().discardJobs(project.getName()); |
| |
| Q7Project q7Project = (Q7Project) RcpttCore.create(project); |
| |
| q7Project.close(); |
| |
| // workaround for bug 15168 circular errors not reported |
| this.state.getOldProjectNames(); // foce list to be computed |
| |
| this.removeFromParentInfo(q7Project); |
| } catch (ModelException e) { |
| // q7 project doesn't exist: ignore |
| } |
| } |
| |
| private void elementAdded(Openable element, IResourceDelta delta) { |
| HandleType elementType = element.getElementType(); |
| if (elementType.equals(HandleType.Project)) { |
| // project add is handled by DylanProject.configure() because |
| // when a project is created, it does not yet have a q7 nature |
| if (delta != null && RcpttCore.hasRcpttNature((IProject) delta.getResource())) { |
| this.addToParentInfo(element); |
| if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) { |
| Openable movedFromElement = (Openable) element.getModel().getProject( |
| delta.getMovedFromPath().lastSegment()); |
| this.currentDelta().movedTo(element, movedFromElement); |
| } else { |
| this.close(element); |
| |
| this.currentDelta().added(element); |
| } |
| final IQ7Project project = (IQ7Project) element; |
| this.rootsToRefresh.add(project); |
| this.projectCachesToReset.add(project); |
| } |
| } else { |
| if (delta == null || (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) { |
| // regular element addition |
| if (this.isWorkingCopy(element, elementType)) { |
| this.currentDelta().changed(element, |
| IQ7ElementDelta.F_PRIMARY_RESOURCE); |
| } else { |
| this.addToParentInfo(element); |
| this.close(element); |
| this.currentDelta().added(element); |
| } |
| } else { |
| // element is moved |
| this.addToParentInfo(element); |
| this.close(element); |
| IPath movedFromPath = delta.getMovedFromPath(); |
| IResource res = delta.getResource(); |
| IResource movedFromRes; |
| if (res instanceof IFile) { |
| movedFromRes = res.getWorkspace().getRoot().getFile(movedFromPath); |
| } else { |
| movedFromRes = res.getWorkspace().getRoot().getFolder(movedFromPath); |
| } |
| // find the element type of the moved from element |
| Q7Project movedFromInfo = (Q7Project) RcpttCore.create(movedFromRes |
| .getProject()); |
| HandleType movedFromType = element.getParent().getElementType(); |
| // reset current element as it might be inside a nested root |
| // (popUntilPrefixOf() may use the outer root) |
| this.currentElement = null; |
| // create the moved from element |
| Openable movedFromElement = this.createElement(movedFromRes, |
| movedFromType, movedFromInfo); |
| if (movedFromElement == null) { |
| // moved from outside buildpath |
| this.currentDelta().added(element); |
| } else { |
| this.currentDelta().movedTo(element, movedFromElement); |
| } |
| } |
| switch (elementType) { |
| case Folder: |
| // reset project's package fragment cache |
| Q7Project project = (Q7Project) element.getQ7Project(); |
| this.projectCachesToReset.add(project); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Generic processing for a removed element:<ul> <li>Close the element, |
| * removing its structure from the cache <li>Remove the element from its |
| * parent's cache of children <li>Add a REMOVED entry in the delta </ul> |
| * Delta argument could be null if processing an external ZIP change |
| */ |
| private void elementRemoved(Openable element, IResourceDelta delta, Q7Project rootInfo) { |
| HandleType elementType = element.getElementType(); |
| if (delta == null || (delta.getFlags() & IResourceDelta.MOVED_TO) == 0) { |
| // regular element removal |
| if (this.isWorkingCopy(element, elementType)) { |
| // filter out changes to primary compilation unit in working |
| // copy mode |
| // just report a change to the resource (see |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=59500) |
| this.currentDelta().changed(element, IQ7ElementDelta.F_PRIMARY_RESOURCE); |
| } else { |
| this.close(element); |
| this.removeFromParentInfo(element); |
| this.currentDelta().removed(element); |
| } |
| } else { |
| // element is moved |
| this.close(element); |
| this.removeFromParentInfo(element); |
| IPath movedToPath = delta.getMovedToPath(); |
| IResource res = delta.getResource(); |
| IResource movedToRes; |
| switch (res.getType()) { |
| case IResource.PROJECT: |
| movedToRes = res.getWorkspace().getRoot() |
| .getProject(movedToPath.lastSegment()); |
| break; |
| case IResource.FOLDER: |
| movedToRes = res.getWorkspace().getRoot().getFolder(movedToPath); |
| break; |
| case IResource.FILE: |
| movedToRes = res.getWorkspace().getRoot().getFile(movedToPath); |
| break; |
| default: |
| return; |
| } |
| // find the element type of the moved from element |
| Q7Project movedToInfo = (Q7Project) RcpttCore.create(movedToRes.getProject()); |
| HandleType movedToType = element.getElementType(); |
| // reset current element as it might be inside a nested root |
| // (popUntilPrefixOf() may use the outer root) |
| this.currentElement = null; |
| // create the moved To element |
| Openable movedToElement = this.createElement(movedToRes, movedToType, |
| movedToInfo); |
| if (movedToElement == null) { |
| // moved outside buildpath |
| this.currentDelta().removed(element); |
| } else { |
| this.currentDelta().movedFrom(element, movedToElement); |
| } |
| } |
| switch (elementType) { |
| case Model: |
| this.manager.getIndexManager().reset(); |
| break; |
| case Project: { |
| final IQ7Project project = (IQ7Project) element; |
| this.rootsToRefresh.add(project); |
| this.projectCachesToReset.add(project); |
| break; |
| } |
| case Folder: { |
| // reset package fragment cache |
| IQ7Project project = element.getQ7Project(); |
| this.projectCachesToReset.add(project); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Flushes all deltas without firing them. |
| */ |
| public void flush() { |
| this.modelDeltas = new ArrayList<IQ7ElementDelta>(); |
| } |
| |
| /* |
| * Fire q7 Model delta, flushing them after the fact after post_change |
| * notification. If the firing mode has been turned off, this has no effect. |
| */ |
| public void fire(IQ7ElementDelta customDelta, int eventType) { |
| if (!this.isFiring) { |
| return; |
| } |
| if (DEBUG) { |
| System.out |
| .println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$ |
| } |
| IQ7ElementDelta deltaToNotify; |
| if (customDelta == null) { |
| deltaToNotify = this.mergeDeltas(this.modelDeltas); |
| } else { |
| deltaToNotify = customDelta; |
| } |
| // Notification |
| // Important: if any listener reacts to notification by updating the |
| // listeners list or mask, these lists will |
| // be duplicated, so it is necessary to remember original lists in a |
| // variable (since field values may change under us) |
| IElementChangedListener[] listeners; |
| int[] listenerMask; |
| int listenerCount; |
| synchronized (this.state) { |
| listeners = this.state.elementChangedListeners; |
| listenerMask = this.state.elementChangedListenerMasks; |
| listenerCount = this.state.elementChangedListenerCount; |
| } |
| switch (eventType) { |
| case DEFAULT_CHANGE_EVENT: |
| this.firePostChangeDelta(deltaToNotify, listeners, listenerMask, |
| listenerCount); |
| this.fireReconcileDelta(listeners, listenerMask, listenerCount); |
| break; |
| case Q7ElementChangedEvent.POST_CHANGE: |
| this.firePostChangeDelta(deltaToNotify, listeners, listenerMask, |
| listenerCount); |
| this.fireReconcileDelta(listeners, listenerMask, listenerCount); |
| break; |
| } |
| } |
| |
| private void firePostChangeDelta(IQ7ElementDelta deltaToNotify, |
| IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { |
| // post change deltas |
| if (DEBUG) { |
| System.out |
| .println("FIRING POST_CHANGE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$ |
| System.out |
| .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$ |
| } |
| if (deltaToNotify != null) { |
| // flush now so as to keep listener reactions to post their own |
| // deltas for subsequent iteration |
| this.flush(); |
| this.notifyListeners(deltaToNotify, Q7ElementChangedEvent.POST_CHANGE, |
| listeners, listenerMask, listenerCount); |
| } |
| } |
| |
| @SuppressWarnings("rawtypes") |
| private void fireReconcileDelta(IElementChangedListener[] listeners, |
| int[] listenerMask, int listenerCount) { |
| IQ7ElementDelta deltaToNotify = this.mergeDeltas(this.reconcileDeltas.values()); |
| if (DEBUG) { |
| System.out |
| .println("FIRING POST_RECONCILE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$ |
| System.out |
| .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$ |
| } |
| if (deltaToNotify != null) { |
| // flush now so as to keep listener reactions to post their own |
| // deltas for subsequent iteration |
| this.reconcileDeltas = new HashMap(); |
| this.notifyListeners(deltaToNotify, Q7ElementChangedEvent.POST_RECONCILE, |
| listeners, listenerMask, listenerCount); |
| } |
| } |
| |
| /* |
| * Returns whether a given delta contains some information relevant to the |
| * Model, in particular it will not consider SYNC or MARKER only deltas. |
| */ |
| private boolean isAffectedBy(IResourceDelta rootDelta) { |
| // if (rootDelta == null) System.out.println("NULL DELTA"); |
| // long start = System.currentTimeMillis(); |
| if (rootDelta != null) { |
| // use local exception to quickly escape from delta traversal |
| class FoundRelevantDeltaException extends RuntimeException { |
| private static final long serialVersionUID = 7137113252936111022L; // backward |
| // compatible |
| // only the class name is used (to differenciate from other |
| // RuntimeExceptions) |
| } |
| try { |
| rootDelta.accept(new IResourceDeltaVisitor() { |
| public boolean visit(IResourceDelta delta) /* |
| * throws |
| * CoreException |
| */{ |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| case IResourceDelta.REMOVED: |
| throw new FoundRelevantDeltaException(); |
| case IResourceDelta.CHANGED: |
| // if any flag is set but SYNC or MARKER, this |
| // delta |
| // should be considered |
| if (delta.getAffectedChildren().length == 0 // only |
| // check |
| // leaf |
| // delta |
| // nodes |
| && (delta.getFlags() & ~(IResourceDelta.SYNC | IResourceDelta.MARKERS)) != 0) { |
| throw new FoundRelevantDeltaException(); |
| } |
| } |
| return true; |
| } |
| }); |
| } catch (FoundRelevantDeltaException e) { |
| // System.out.println("RELEVANT DELTA detected in: "+ |
| // (System.currentTimeMillis() - start)); |
| return true; |
| } catch (CoreException e) { // ignore delta if not able to traverse |
| } |
| } |
| // System.out.println("IGNORE SYNC DELTA took: "+ |
| // (System.currentTimeMillis() - start)); |
| return false; |
| } |
| |
| /* |
| * Returns whether the given element is a primary compilation unit in |
| * working copy mode. |
| */ |
| private boolean isWorkingCopy(IQ7Element element, HandleType elementType) { |
| if (elementType.equals(HandleType.Context) |
| || elementType.equals(HandleType.Verification) |
| || elementType.equals(HandleType.TestCase) |
| || elementType.equals(HandleType.TestSuite)) { |
| IQ7NamedElement cu = (IQ7NamedElement) element; |
| return cu.isWorkingCopy(); |
| } |
| return false; |
| } |
| |
| /* |
| * Merges all awaiting deltas. |
| */ |
| @SuppressWarnings("rawtypes") |
| private IQ7ElementDelta mergeDeltas(Collection deltas) { |
| if (deltas.size() == 0) { |
| return null; |
| } |
| if (deltas.size() == 1) { |
| return (IQ7ElementDelta) deltas.iterator().next(); |
| } |
| if (VERBOSE) { |
| System.out |
| .println("MERGING " + deltas.size() + " DELTAS [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| Iterator iterator = deltas.iterator(); |
| Q7ElementDelta rootDelta = new Q7ElementDelta(this.manager.getModel()); |
| boolean insertedTree = false; |
| while (iterator.hasNext()) { |
| Q7ElementDelta delta = (Q7ElementDelta) iterator.next(); |
| if (VERBOSE) { |
| System.out.println(delta.toString()); |
| } |
| IQ7Element element = delta.getElement(); |
| if (this.manager.getModel().equals(element)) { |
| IQ7ElementDelta[] children = delta.getAffectedChildren(); |
| for (int j = 0; j < children.length; j++) { |
| Q7ElementDelta projectDelta = (Q7ElementDelta) children[j]; |
| rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta); |
| insertedTree = true; |
| } |
| IResourceDelta[] resourceDeltas = delta.getResourceDeltas(); |
| if (resourceDeltas != null) { |
| for (int i = 0, length = resourceDeltas.length; i < length; i++) { |
| rootDelta.addResourceDelta(resourceDeltas[i]); |
| insertedTree = true; |
| } |
| } |
| } else { |
| rootDelta.insertDeltaTree(element, delta); |
| insertedTree = true; |
| } |
| } |
| if (insertedTree) { |
| return rootDelta; |
| } |
| return null; |
| } |
| |
| private void notifyListeners(IQ7ElementDelta deltaToNotify, int eventType, |
| IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { |
| final Q7ElementChangedEvent extraEvent = new Q7ElementChangedEvent(deltaToNotify, |
| eventType); |
| for (int i = 0; i < listenerCount; i++) { |
| if ((listenerMask[i] & eventType) != 0) { |
| final IElementChangedListener listener = listeners[i]; |
| long start = -1; |
| if (VERBOSE) { |
| System.out.print("Listener #" + (i + 1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$ |
| start = System.currentTimeMillis(); |
| } |
| // wrap callbacks with Safe runnable for subsequent listeners to |
| // be called when some are causing grief |
| SafeRunner.run(new ISafeRunnable() { |
| public void handleException(Throwable exception) { |
| exception.printStackTrace(); |
| } |
| |
| public void run() throws Exception { |
| listener.elementChanged(extraEvent); |
| } |
| }); |
| if (VERBOSE) { |
| System.out |
| .println(" -> " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| } |
| |
| /* |
| * Generic processing for elements with changed contents:<ul> <li>The |
| * element is closed such that any subsequent accesses will re-open the |
| * element reflecting its new structure. <li>An entry is made in the delta |
| * reporting a content change (K_CHANGE with F_CONTENT flag set). </ul> |
| */ |
| private void nonQ7ResourcesChanged(Openable element, IResourceDelta delta) |
| throws ModelException { |
| // reset non-q7 resources if element was open |
| if (element.isOpen()) { |
| Q7ElementInfo info = (Q7ElementInfo) element.getElementInfo(); |
| switch (element.getElementType()) { |
| case Model: |
| ((ModelInfo) info).foreignResources = null; |
| this.currentDelta().addResourceDelta(delta); |
| return; |
| case Project: |
| ((Q7ProjectInfo) info).setForeignResources(null); |
| // if a package fragment root is the project, clear it too |
| break; |
| case Folder: |
| ((Q7FolderInfo) info).setForeignResources(null); |
| break; |
| } |
| } |
| Q7ElementDelta current = this.currentDelta(); |
| Q7ElementDelta elementDelta = current.find(element); |
| if (elementDelta == null) { |
| // don't use find after creating the delta as it can be null (see |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=63434) |
| elementDelta = current.changed(element, IQ7ElementDelta.F_CONTENT); |
| } |
| elementDelta.addResourceDelta(delta); |
| } |
| |
| private void popUntilPrefixOf(IPath path) { |
| while (this.currentElement != null) { |
| IPath currentElementPath = null; |
| IResource currentElementResource = this.currentElement.getResource(); |
| if (currentElementResource != null) { |
| currentElementPath = currentElementResource.getFullPath(); |
| } |
| if (currentElementPath != null) { |
| if (this.currentElement instanceof IQ7Folder |
| && ((IQ7Folder) this.currentElement).isRootFolder() |
| && currentElementPath.segmentCount() != path.segmentCount() - 1) { |
| // default package and path is not a direct child |
| this.currentElement = (Openable) this.currentElement.getParent(); |
| } |
| if (currentElementPath.isPrefixOf(path)) { |
| return; |
| } |
| } |
| this.currentElement = (Openable) this.currentElement.getParent(); |
| } |
| } |
| |
| private IQ7ElementDelta processResourceDelta(IResourceDelta changes) { |
| try { |
| IQ7Model model = this.manager.getModel(); |
| if (!model.isOpen()) { |
| // force opening of q7 model so that model element delta are |
| // reported |
| try { |
| model.open(null); |
| } catch (ModelException e) { |
| if (VERBOSE) { |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| } |
| this.currentElement = null; |
| // get the workspace delta, and start processing there. |
| IResourceDelta[] deltas = changes.getAffectedChildren(); |
| for (int i = 0; i < deltas.length; i++) { |
| IResourceDelta delta = deltas[i]; |
| IResource res = delta.getResource(); |
| // find out the element type |
| Q7Project rootInfo = null; |
| HandleType elementType; |
| IProject proj = (IProject) res; |
| boolean wasQ7Project = this.state.findProject(proj.getName()) != null; |
| boolean isDylanProject = RcpttCore.hasRcpttNature(proj); |
| if (!wasQ7Project && !isDylanProject) { |
| elementType = HandleType.NonQ7; |
| } else { |
| rootInfo = (Q7Project) RcpttCore.create(res.getProject()); |
| elementType = HandleType.Project; |
| } |
| // traverse delta |
| Set<IQ7NamedElement> toIndex = new HashSet<IQ7NamedElement>(); |
| this.traverseDelta(delta, elementType, rootInfo, toIndex); |
| if (toIndex.size() > 0) { |
| ProjectIndexerManager.indexNamedElements(toIndex); |
| } |
| |
| if (elementType.equals(HandleType.NonQ7) |
| || (wasQ7Project != isDylanProject && (delta.getKind()) == IResourceDelta.CHANGED)) { |
| /* |
| * project has changed nature (deq7ion or open/closed) |
| */ |
| try { |
| // add child as non q7 resource |
| this.nonQ7ResourcesChanged((Q7Model) model, delta); |
| } catch (ModelException e) { |
| // q7 model could not be opened |
| } |
| } |
| } |
| this.resetProjectCaches(); |
| this.executePostActions(); |
| return this.currentDelta; |
| } finally { |
| this.currentDelta = null; |
| this.rootsToRefresh.clear(); |
| this.projectCachesToReset.clear(); |
| this.postActions.clear(); |
| } |
| } |
| |
| private void executePostActions() { |
| if (postActions.size() == 0) { |
| return; |
| } |
| for (Iterator<Runnable> i = postActions.iterator(); i.hasNext();) { |
| i.next().run(); |
| } |
| } |
| |
| /* |
| * Traverse the set of projects which have changed namespace, and reset |
| * their caches and their dependents |
| */ |
| @SuppressWarnings("rawtypes") |
| private void resetProjectCaches() { |
| if (this.projectCachesToReset.size() == 0) { |
| return; |
| } |
| Iterator iterator = this.projectCachesToReset.iterator(); |
| HashMap projectDepencies = this.state.projectDependencies; |
| HashSet affectedDependents = new HashSet(); |
| while (iterator.hasNext()) { |
| Q7Project project = (Q7Project) iterator.next(); |
| project.resetCaches(); |
| this.addDependentProjects(project, projectDepencies, affectedDependents); |
| } |
| // reset caches of dependent projects |
| iterator = affectedDependents.iterator(); |
| while (iterator.hasNext()) { |
| Q7Project project = (Q7Project) iterator.next(); |
| project.resetCaches(); |
| } |
| } |
| |
| /* |
| * Registers the given delta with this delta processor. |
| */ |
| public void registerModelDelta(IQ7ElementDelta delta) { |
| this.modelDeltas.add(delta); |
| } |
| |
| /* |
| * Removes the given element from its parents cache of children. If the |
| * element does not have a parent, or the parent is not currently open, this |
| * has no effect. |
| */ |
| private void removeFromParentInfo(Openable child) { |
| Openable parent = (Openable) child.getParent(); |
| if (parent != null && parent.isOpen()) { |
| try { |
| Q7ElementInfo info = (Q7ElementInfo) parent.getElementInfo(); |
| info.removeChild(child); |
| } catch (ModelException e) { |
| // do nothing - we already checked if open |
| } |
| } |
| } |
| |
| /* |
| * Notification that some resource changes have happened on the platform, |
| * and that the q7 Model should update any required internal structures such |
| * that its elements remain consistent. Translates |
| * <code>IResourceDeltas</code> into <code>IQ7ElementDeltas</code>. |
| * |
| * @see IResourceDelta |
| * |
| * @see IResource |
| */ |
| @SuppressWarnings("unused") |
| public void resourceChanged(IResourceChangeEvent event) { |
| int eventType = this.overridenEventType == -1 ? event.getType() |
| : this.overridenEventType; |
| IResource resource = event.getResource(); |
| IResourceDelta delta = event.getDelta(); |
| |
| switch (eventType) { |
| case IResourceChangeEvent.PRE_DELETE: |
| if (resource.getType() == IResource.PROJECT |
| && RcpttCore.hasRcpttNature((IProject) resource)) { |
| |
| this.deleting((IProject) resource); |
| } |
| return; |
| |
| case IResourceChangeEvent.POST_CHANGE: |
| if (this.isAffectedBy(delta)) { // avoid populating for SYNC or |
| // MARKER |
| // deltas |
| try { |
| try { |
| this.stopDeltas(); |
| this.checkProjectsBeingAddedOrRemoved(delta); |
| // generate external archive change deltas |
| if (this.refreshedElements != null) { |
| Set<IQ7Element> refreshedElementsCopy = null; |
| if (refreshedElements != null) { |
| refreshedElementsCopy = new HashSet<IQ7Element>(); |
| refreshedElementsCopy.addAll(refreshedElements); |
| // To avoid concurrent modifications |
| this.refreshedElements = null; |
| } |
| |
| } |
| IQ7ElementDelta translatedDelta = this |
| .processResourceDelta(delta); |
| if (translatedDelta != null) { |
| this.registerModelDelta(translatedDelta); |
| } |
| } finally { |
| this.startDeltas(); |
| } |
| // Call update for model |
| updateModel(null); |
| IElementChangedListener[] listeners; |
| // int listenerCount; |
| synchronized (this.state) { |
| listeners = this.state.elementChangedListeners; |
| // listenerCount = |
| // this.state.elementChangedListenerCount; |
| } |
| this.fire(null, Q7ElementChangedEvent.POST_CHANGE); |
| |
| } finally { |
| // workaround for bug 15168 circular errors not reported |
| this.state.resetOldProjectNames(); |
| } |
| } |
| return; |
| |
| case IResourceChangeEvent.PRE_BUILD: |
| if (!this.isAffectedBy(delta)) { |
| return; // avoid populating for SYNC or MARKER deltas |
| } |
| // does not fire any deltas |
| return; |
| |
| case IResourceChangeEvent.POST_BUILD: |
| return; |
| } |
| } |
| |
| /* |
| * Turns the firing mode to on. That is, deltas that are/have been |
| * registered will be fired. |
| */ |
| private void startDeltas() { |
| this.isFiring = true; |
| } |
| |
| /* |
| * Turns the firing mode to off. That is, deltas that are/have been |
| * registered will not be fired until deltas are started again. |
| */ |
| private void stopDeltas() { |
| this.isFiring = false; |
| } |
| |
| private void traverseDelta(IResourceDelta delta, HandleType elementType, |
| Q7Project rootInfo, Set<IQ7NamedElement> toIndex) { |
| |
| IResource res = delta.getResource(); |
| // set stack of elements |
| if (this.currentElement == null && rootInfo != null) { |
| this.currentElement = rootInfo; |
| } |
| // process current delta |
| boolean processChildren = true; |
| if (res instanceof IProject) { |
| processChildren = this.updateCurrentDeltaAndIndex(delta, elementType, |
| rootInfo, toIndex); |
| } else if (rootInfo != null) { |
| processChildren = this.updateCurrentDeltaAndIndex(delta, elementType, |
| rootInfo, toIndex); |
| } else { |
| // not yet inside a package fragment root |
| processChildren = true; |
| } |
| // process children if needed |
| if (processChildren) { |
| IResourceDelta[] children = delta.getAffectedChildren(); |
| int length = children.length; |
| for (int i = 0; i < length; i++) { |
| IResourceDelta child = children[i]; |
| IResource childRes = child.getResource(); |
| // find out whether the child is a package fragment root of the |
| // current project |
| int childKind = childRes.getType(); |
| // compute child type |
| HandleType childType = elementType(childRes, childKind, rootInfo); |
| this.traverseDelta(child, childType, rootInfo, toIndex); |
| } |
| |
| } |
| } |
| |
| private HandleType elementType(IResource childRes, int childKind, Q7Project rootInfo) { |
| switch (childKind) { |
| case IResource.FOLDER: |
| return HandleType.Folder; |
| case IResource.PROJECT: |
| return HandleType.Project; |
| case IResource.ROOT: |
| return HandleType.Model; |
| case IResource.FILE: |
| IPath childPath = childRes.getFullPath(); |
| if (RcpttCore.isQ7File(childPath)) { |
| if (RcpttCore.isQ7Context(childPath)) |
| return HandleType.Context; |
| else if (RcpttCore.isQ7Verification(childPath)) |
| return HandleType.Verification; |
| else if (RcpttCore.isQ7TestSuite(childPath)) |
| return HandleType.TestSuite; |
| else if (RcpttCore.isQ7ProjectMetadata(childPath)) |
| return HandleType.ProjectMetadata; |
| else |
| return HandleType.TestCase; |
| } |
| } |
| return HandleType.NonQ7; |
| } |
| |
| public boolean updateCurrentDeltaAndIndex(IResourceDelta delta, |
| HandleType elementType, Q7Project rootInfo, Set<IQ7NamedElement> toIndex) { |
| Openable element; |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| IResource deltaRes = delta.getResource(); |
| element = this.createElement(deltaRes, elementType, rootInfo); |
| if (element == null) { |
| return true; |
| } |
| this.updateIndex(element, delta, toIndex); |
| this.elementAdded(element, delta); |
| return elementType.equals(HandleType.Folder); |
| case IResourceDelta.REMOVED: |
| deltaRes = delta.getResource(); |
| element = this.createElement(deltaRes, elementType, rootInfo); |
| if (element == null) { |
| // resource might be containing shared roots (see bug 19058) |
| return true; |
| } |
| this.updateIndex(element, delta, toIndex); |
| this.elementRemoved(element, delta, rootInfo); |
| |
| return elementType.equals(HandleType.Folder); |
| case IResourceDelta.CHANGED: |
| int flags = delta.getFlags(); |
| if ((flags & IResourceDelta.CONTENT) != 0 |
| || (flags & IResourceDelta.ENCODING) != 0) { |
| // content or encoding has changed |
| element = this.createElement(delta.getResource(), elementType, rootInfo); |
| if (element == null) { |
| return false; |
| } |
| this.updateIndex(element, delta, toIndex); |
| this.contentChanged(element); |
| } else if (elementType.equals(HandleType.Project)) { |
| if ((flags & IResourceDelta.OPEN) != 0) { |
| // project has been opened or closed |
| final IProject res = (IProject) delta.getResource(); |
| element = this.createElement(res, elementType, rootInfo); |
| if (element == null) { |
| return false; |
| } |
| if (res.isOpen()) { |
| if (RcpttCore.hasRcpttNature(res)) { |
| this.addToParentInfo(element); |
| this.currentDelta().opened(element); |
| // refresh pkg fragment roots and caches of the |
| // project (and its dependents) |
| final IQ7Project project = (IQ7Project) element; |
| this.rootsToRefresh.add(project); |
| this.projectCachesToReset.add(project); |
| this.postActions.add(new Runnable() { |
| public void run() { |
| ProjectIndexerManager.indexProject(res); |
| } |
| }); |
| } |
| } else { |
| if (this.state.findProject(res.getName()) != null) { |
| this.close(element); |
| this.removeFromParentInfo(element); |
| this.currentDelta().closed(element); |
| this.manager.getIndexManager().discardJobs(element.getName()); |
| final IPath projectPath = res.getFullPath(); |
| this.manager.getIndexManager().removeIndex(projectPath); |
| ProjectIndexerManager.removeProject(projectPath); |
| } |
| } |
| return false; // when a project is open/closed don't |
| // process children |
| } |
| if ((flags & IResourceDelta.DESCRIPTION) != 0) { |
| IProject res = (IProject) delta.getResource(); |
| boolean isQ7Project = RcpttCore.hasRcpttNature(res); |
| element = this.createElement(res, elementType, rootInfo); |
| if (element == null) { |
| return false; // note its resources are still |
| } |
| // project's nature has been added or removed |
| // visible as roots to other |
| // projects |
| if (isQ7Project) { |
| this.elementAdded(element, delta); |
| ProjectIndexerManager.indexProject(res); |
| } else { |
| this.elementRemoved(element, delta, rootInfo); |
| this.manager.getIndexManager().discardJobs(element.getName()); |
| final IPath projectPath = res.getFullPath(); |
| this.manager.getIndexManager().removeIndex(projectPath); |
| ProjectIndexerManager.removeProject(projectPath); |
| } |
| return false; // when a project's nature is |
| // added/removed don't process children |
| } |
| } |
| return true; |
| } |
| return true; |
| } |
| |
| private void updateIndex(Openable element, IResourceDelta delta, |
| Set<IQ7NamedElement> toIndex) { |
| IndexManager indexManager = this.manager.getIndexManager(); |
| if (indexManager == null) { |
| return; |
| } |
| switch (element.getElementType()) { |
| case Project: |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| final IQ7Project q7Project = element.getQ7Project(); |
| this.postActions.add(new Runnable() { |
| public void run() { |
| ProjectIndexerManager.indexProject(q7Project); |
| } |
| }); |
| break; |
| case IResourceDelta.REMOVED: |
| final IPath projectPath = element.getQ7Project().getProject() |
| .getFullPath(); |
| indexManager.removeIndex(projectPath); |
| ProjectIndexerManager.removeProject(projectPath); |
| // NB: Discarding index jobs belonging to this project |
| // was done |
| // during PRE_DELETE |
| break; |
| // NB: Update of index if project is opened, closed, or its |
| // q7 |
| // nature is added or removed |
| // is done in updateCurrentDeltaAndIndex |
| } |
| break; |
| case Folder: |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED: |
| case IResourceDelta.REMOVED: |
| IQ7Folder pkg = null; |
| if (element instanceof IQ7Project) { |
| IQ7Project root = (IQ7Project) element; |
| pkg = root.getFolder(Path.EMPTY); |
| } else { |
| pkg = (IQ7Folder) element; |
| } |
| IResourceDelta[] children = delta.getAffectedChildren(); |
| for (int i = 0, length = children.length; i < length; i++) { |
| IResourceDelta child = children[i]; |
| IResource resource = child.getResource(); |
| // TODO (philippe) Why do this? Every child is added |
| // anyway |
| // as the delta is walked |
| if (resource instanceof IFile) { |
| String name = resource.getName(); |
| if (RcpttCore.isQ7File(resource.getFullPath())) { |
| Openable cu = (Openable) pkg.getNamedElement(name); |
| this.updateIndex(cu, child, toIndex); |
| } |
| } |
| } |
| } |
| break; |
| case TestCase: |
| case TestSuite: |
| case Context: |
| case Verification: |
| case ProjectMetadata: |
| IFile file = (IFile) delta.getResource(); |
| switch (delta.getKind()) { |
| case IResourceDelta.CHANGED: |
| // no need to index if the content has not changed |
| int flags = delta.getFlags(); |
| if ((flags & IResourceDelta.CONTENT) == 0 |
| && (flags & IResourceDelta.ENCODING) == 0) { |
| break; |
| } |
| case IResourceDelta.ADDED: |
| if (ProjectIndexerManager.isIndexerEnabled(file.getProject())) { |
| // ProjectIndexerManager |
| // .indexNamedElement((IQ7NamedElement) element); |
| toIndex.add((IQ7NamedElement) element); |
| } |
| // Clean file from secondary types cache but do not |
| // update |
| // indexing secondary type cache as it will be updated |
| // through |
| // indexing itself |
| // this.manager.secondaryTypesRemoving(file, false); |
| break; |
| case IResourceDelta.REMOVED: |
| final IProject project = file.getProject(); |
| /* remove project segment */ |
| final String path = file.getFullPath().removeFirstSegments(1).toString(); |
| ProjectIndexerManager.removeNamedElement(RcpttCore.create(project), path); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Update Model given some delta |
| */ |
| public void updateModel(IQ7ElementDelta customDelta) { |
| if (customDelta == null) { |
| for (int i = 0, length = this.modelDeltas.size(); i < length; i++) { |
| IQ7ElementDelta delta = this.modelDeltas.get(i); |
| this.modelUpdater.processDelta(delta); |
| } |
| } else { |
| this.modelUpdater.processDelta(customDelta); |
| } |
| } |
| } |