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