9d3c1bb2544128f3240576d9889efb64e53190ce
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / ModelUpdater.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.internal.core;
13
14 import java.util.HashSet;
15 import java.util.Iterator;
16
17 import net.sourceforge.phpdt.core.IJavaElement;
18 import net.sourceforge.phpdt.core.IJavaElementDelta;
19 import net.sourceforge.phpdt.core.IJavaProject;
20 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
21 import net.sourceforge.phpdt.core.JavaModelException;
22
23 /**
24  * This class is used by <code>JavaModelManager</code> to update the JavaModel
25  * based on some <code>IJavaElementDelta</code>s.
26  */
27 public class ModelUpdater {
28
29         HashSet projectsToUpdate = new HashSet();
30
31         /**
32          * Adds the given child handle to its parent's cache of children.
33          */
34         protected void addToParentInfo(Openable child) {
35
36                 Openable parent = (Openable) child.getParent();
37                 if (parent != null && parent.isOpen()) {
38                         try {
39                                 JavaElementInfo info = (JavaElementInfo) parent
40                                                 .getElementInfo();
41                                 info.addChild(child);
42                         } catch (JavaModelException e) {
43                                 // do nothing - we already checked if open
44                         }
45                 }
46         }
47
48         /**
49          * Closes the given element, which removes it from the cache of open
50          * elements.
51          */
52         protected static void close(Openable element) {
53
54                 try {
55                         element.close();
56                 } catch (JavaModelException e) {
57                         // do nothing
58                 }
59         }
60
61         /**
62          * Processing for an element that has been added:
63          * <ul>
64          * <li>If the element is a project, do nothing, and do not process
65          * children, as when a project is created it does not yet have any natures -
66          * specifically a java nature.
67          * <li>If the elemet is not a project, process it as added (see
68          * <code>basicElementAdded</code>.
69          * </ul>
70          */
71         protected void elementAdded(Openable element) {
72
73                 int elementType = element.getElementType();
74                 if (elementType == IJavaElement.JAVA_PROJECT) {
75                         // project add is handled by JavaProject.configure() because
76                         // when a project is created, it does not yet have a java nature
77                         addToParentInfo(element);
78                         this.projectsToUpdate.add(element);
79                 } else {
80                         addToParentInfo(element);
81
82                         // Force the element to be closed as it might have been opened
83                         // before the resource modification came in and it might have a new
84                         // child
85                         // For example, in an IWorkspaceRunnable:
86                         // 1. create a package fragment p using a java model operation
87                         // 2. open package p
88                         // 3. add file X.java in folder p
89                         // When the resource delta comes in, only the addition of p is
90                         // notified,
91                         // but the package p is already opened, thus its children are not
92                         // recomputed
93                         // and it appears empty.
94                         close(element);
95                 }
96
97                 switch (elementType) {
98                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
99                         // when a root is added, and is on the classpath, the project must
100                         // be updated
101                         this.projectsToUpdate.add(element.getJavaProject());
102                         break;
103                 case IJavaElement.PACKAGE_FRAGMENT:
104                         // get rid of package fragment cache
105                         JavaProject project = (JavaProject) element.getJavaProject();
106                         // project.resetCaches();
107                         break;
108                 }
109         }
110
111         /**
112          * Generic processing for elements with changed contents:
113          * <ul>
114          * <li>The element is closed such that any subsequent accesses will re-open
115          * the element reflecting its new structure.
116          * </ul>
117          */
118         protected void elementChanged(Openable element) {
119
120                 close(element);
121         }
122
123         /**
124          * Generic processing for a removed element:
125          * <ul>
126          * <li>Close the element, removing its structure from the cache
127          * <li>Remove the element from its parent's cache of children
128          * <li>Add a REMOVED entry in the delta
129          * </ul>
130          */
131         protected void elementRemoved(Openable element) {
132
133                 if (element.isOpen()) {
134                         close(element);
135                 }
136                 removeFromParentInfo(element);
137                 int elementType = element.getElementType();
138
139                 switch (elementType) {
140                 case IJavaElement.JAVA_MODEL:
141                         // JavaModelManager.getJavaModelManager().getIndexManager().reset();
142                         break;
143                 case IJavaElement.JAVA_PROJECT:
144                         JavaModelManager.getJavaModelManager().removePerProjectInfo(
145                                         (JavaProject) element);
146                         break;
147                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
148                         this.projectsToUpdate.add(element.getJavaProject());
149                         break;
150                 case IJavaElement.PACKAGE_FRAGMENT:
151                         // get rid of package fragment cache
152                         JavaProject project = (JavaProject) element.getJavaProject();
153                         // project.resetCaches();
154                         break;
155                 }
156         }
157
158         /**
159          * Converts a <code>IResourceDelta</code> rooted in a
160          * <code>Workspace</code> into the corresponding set of
161          * <code>IJavaElementDelta</code>, rooted in the relevant
162          * <code>JavaModel</code>s.
163          */
164         public void processJavaDelta(IJavaElementDelta delta) {
165
166                 // if (DeltaProcessor.VERBOSE){
167                 // System.out.println("UPDATING Model with Delta:
168                 // ["+Thread.currentThread()+":" + delta +
169                 // "]:");//$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
170                 // }
171
172                 try {
173                         this.traverseDelta(delta, null, null); // traverse delta
174
175                         // update package fragment roots of projects that were affected
176                         Iterator iterator = this.projectsToUpdate.iterator();
177                         while (iterator.hasNext()) {
178                                 JavaProject project = (JavaProject) iterator.next();
179                                 project.updatePackageFragmentRoots();
180                         }
181                 } finally {
182                         this.projectsToUpdate = new HashSet();
183                 }
184         }
185
186         /**
187          * Removes the given element from its parents cache of children. If the
188          * element does not have a parent, or the parent is not currently open, this
189          * has no effect.
190          */
191         protected void removeFromParentInfo(Openable child) {
192
193                 Openable parent = (Openable) child.getParent();
194                 if (parent != null && parent.isOpen()) {
195                         try {
196                                 JavaElementInfo info = (JavaElementInfo) parent
197                                                 .getElementInfo();
198                                 info.removeChild(child);
199                         } catch (JavaModelException e) {
200                                 // do nothing - we already checked if open
201                         }
202                 }
203         }
204
205         /**
206          * Converts an <code>IResourceDelta</code> and its children into the
207          * corresponding <code>IJavaElementDelta</code>s. Return whether the
208          * delta corresponds to a resource on the classpath. If it is not a resource
209          * on the classpath, it will be added as a non-java resource by the sender
210          * of this method.
211          */
212         protected void traverseDelta(IJavaElementDelta delta,
213                         IPackageFragmentRoot root, IJavaProject project) {
214
215                 boolean processChildren = true;
216
217                 Openable element = (Openable) delta.getElement();
218                 switch (element.getElementType()) {
219                 case IJavaElement.JAVA_PROJECT:
220                         project = (IJavaProject) element;
221                         break;
222                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
223                         root = (IPackageFragmentRoot) element;
224                         break;
225                 case IJavaElement.COMPILATION_UNIT:
226                         // filter out working copies that are not primary (we don't want to
227                         // add/remove them to/from the package fragment
228                         CompilationUnit cu = (CompilationUnit) element;
229                         if (cu.isWorkingCopy() && !cu.isPrimary()) {
230                                 return;
231                         }
232                 case IJavaElement.CLASS_FILE:
233                         processChildren = false;
234                         break;
235                 }
236
237                 switch (delta.getKind()) {
238                 case IJavaElementDelta.ADDED:
239                         elementAdded(element);
240                         break;
241                 case IJavaElementDelta.REMOVED:
242                         elementRemoved(element);
243                         break;
244                 case IJavaElementDelta.CHANGED:
245                         if ((delta.getFlags() & IJavaElementDelta.F_CONTENT) != 0) {
246                                 elementChanged(element);
247                         }
248                         break;
249                 }
250                 if (processChildren) {
251                         IJavaElementDelta[] children = delta.getAffectedChildren();
252                         for (int i = 0; i < children.length; i++) {
253                                 IJavaElementDelta childDelta = children[i];
254                                 this.traverseDelta(childDelta, root, project);
255                         }
256                 }
257         }
258 }