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