Changes:
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElementDelta.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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 package net.sourceforge.phpdt.internal.core;
12
13 import java.util.ArrayList;
14
15 import net.sourceforge.phpdt.core.IJavaElement;
16 import net.sourceforge.phpdt.core.IJavaElementDelta;
17 import net.sourceforge.phpdt.core.IJavaProject;
18
19 import org.eclipse.core.resources.IResourceDelta;
20
21
22 /**
23  * @see IJavaElementDelta
24  */
25 public class JavaElementDelta implements IJavaElementDelta {
26         /**
27          * The element that this delta describes the change to.
28          * @see #getElement()
29          */
30         protected IJavaElement fChangedElement;
31         /**
32          * @see #getKind()
33          */
34         private int fKind = 0;
35         /**
36          * @see #getFlags()
37          */
38         private int fChangeFlags = 0;
39         /**
40          * @see #getAffectedChildren()
41          */
42         protected IJavaElementDelta[] fAffectedChildren = fgEmptyDelta;
43
44         /**
45          * Collection of resource deltas that correspond to non java resources deltas.
46          */
47         protected IResourceDelta[] resourceDeltas = null;
48
49         /**
50          * Counter of resource deltas
51          */
52         protected int resourceDeltasCounter;
53         /**
54          * @see #getMovedFromHandle()
55          */
56         protected IJavaElement fMovedFromHandle = null;
57         /**
58          * @see #getMovedToHandle()
59          */
60         protected IJavaElement fMovedToHandle = null;
61         /**
62          * Empty array of IJavaElementDelta
63          */
64         protected static  IJavaElementDelta[] fgEmptyDelta= new IJavaElementDelta[] {};
65 /**
66  * Creates the root delta. To create the nested delta
67  * hierarchies use the following convenience methods. The root
68  * delta can be created at any level (for example: project, package root,
69  * package fragment...).
70  * <ul>
71  * <li><code>added(IJavaElement)</code>
72  * <li><code>changed(IJavaElement)</code>
73  * <li><code>moved(IJavaElement, IJavaElement)</code>
74  * <li><code>removed(IJavaElement)</code>
75  * <li><code>renamed(IJavaElement, IJavaElement)</code>
76  * </ul>
77  */
78 public JavaElementDelta(IJavaElement element) {
79         super();
80         fChangedElement = element;
81 }
82 /**
83  * Adds the child delta to the collection of affected children.  If the
84  * child is already in the collection, walk down the hierarchy.
85  */
86 protected void addAffectedChild(JavaElementDelta child) {
87         switch (fKind) {
88                 case ADDED:
89                 case REMOVED:
90                         // no need to add a child if this parent is added or removed
91                         return;
92                 case CHANGED:
93                         fChangeFlags |= F_CHILDREN;
94                         break;
95                 default:
96                         fKind = CHANGED;
97                         fChangeFlags |= F_CHILDREN;
98         }
99
100         // if a child delta is added to a compilation unit delta or below, 
101         // it's a fine grained delta
102         if (fChangedElement.getElementType() >= IJavaElement.COMPILATION_UNIT) {
103                 this.fineGrained();
104         }
105         
106         if (fAffectedChildren.length == 0) {
107                 fAffectedChildren = new IJavaElementDelta[] {child};
108                 return;
109         }
110         IJavaElementDelta existingChild = null;
111         int existingChildIndex = -1;
112         if (fAffectedChildren != null) {
113                 for (int i = 0; i < fAffectedChildren.length; i++) {
114                         if (this.equalsAndSameParent(fAffectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
115                                 existingChild = fAffectedChildren[i];
116                                 existingChildIndex = i;
117                                 break;
118                         }
119                 }
120         }
121         if (existingChild == null) { //new affected child
122                 fAffectedChildren= growAndAddToArray(fAffectedChildren, child);
123         } else {
124                 switch (existingChild.getKind()) {
125                         case ADDED:
126                                 switch (child.getKind()) {
127                                         case ADDED: // child was added then added -> it is added
128                                         case CHANGED: // child was added then changed -> it is added
129                                                 return;
130                                         case REMOVED: // child was added then removed -> noop
131                                                 fAffectedChildren = this.removeAndShrinkArray(fAffectedChildren, existingChildIndex);
132                                                 return;
133                                 }
134                                 break;
135                         case REMOVED:
136                                 switch (child.getKind()) {
137                                         case ADDED: // child was removed then added -> it is changed
138                                                 child.fKind = CHANGED;
139                                                 fAffectedChildren[existingChildIndex] = child;
140                                                 return;
141                                         case CHANGED: // child was removed then changed -> it is removed
142                                         case REMOVED: // child was removed then removed -> it is removed
143                                                 return;
144                                 }
145                                 break;
146                         case CHANGED:
147                                 switch (child.getKind()) {
148                                         case ADDED: // child was changed then added -> it is added
149                                         case REMOVED: // child was changed then removed -> it is removed
150                                                 fAffectedChildren[existingChildIndex] = child;
151                                                 return;
152                                         case CHANGED: // child was changed then changed -> it is changed
153                                                 IJavaElementDelta[] children = child.getAffectedChildren();
154                                                 for (int i = 0; i < children.length; i++) {
155                                                         JavaElementDelta childsChild = (JavaElementDelta) children[i];
156                                                         ((JavaElementDelta) existingChild).addAffectedChild(childsChild);
157                                                 }
158                                                 
159                                                 // update flags if needed
160                                                 switch (((JavaElementDelta) existingChild).fChangeFlags) {
161                                                         case F_ADDED_TO_CLASSPATH:
162                                                         case F_REMOVED_FROM_CLASSPATH:
163                                                         case F_SOURCEATTACHED:
164                                                         case F_SOURCEDETACHED:
165                                                                 ((JavaElementDelta) existingChild).fChangeFlags |= ((JavaElementDelta) child).fChangeFlags;
166                                                                 break;
167                                                 }
168                                                 
169                                                 // add the non-java resource deltas if needed
170                                                 // note that the child delta always takes precedence over this existing child delta
171                                                 // as non-java resource deltas are always created last (by the DeltaProcessor)
172                                                 IResourceDelta[] resDeltas = child.getResourceDeltas();
173                                                 if (resDeltas != null) {
174                                                         ((JavaElementDelta)existingChild).resourceDeltas = resDeltas;
175                                                         ((JavaElementDelta)existingChild).resourceDeltasCounter = child.resourceDeltasCounter;
176                                                 }
177                                                 return;
178                                 }
179                                 break;
180                         default: 
181                                 // unknown -> existing child becomes the child with the existing child's flags
182                                 int flags = existingChild.getFlags();
183                                 fAffectedChildren[existingChildIndex] = child;
184                                 child.fChangeFlags |= flags;
185                 }
186         }
187 }
188 /**
189  * Creates the nested deltas resulting from an add operation.
190  * Convenience method for creating add deltas.
191  * The constructor should be used to create the root delta 
192  * and then an add operation should call this method.
193  */
194 public void added(IJavaElement element) {
195         JavaElementDelta addedDelta = new JavaElementDelta(element);
196         addedDelta.fKind = ADDED;
197         insertDeltaTree(element, addedDelta);
198 }
199 /**
200  * Adds the child delta to the collection of affected children.  If the
201  * child is already in the collection, walk down the hierarchy.
202  */
203 protected void addResourceDelta(IResourceDelta child) {
204         switch (fKind) {
205                 case ADDED:
206                 case REMOVED:
207                         // no need to add a child if this parent is added or removed
208                         return;
209                 case CHANGED:
210                         fChangeFlags |= F_CONTENT;
211                         break;
212                 default:
213                         fKind = CHANGED;
214                         fChangeFlags |= F_CONTENT;
215         }
216         if (resourceDeltas == null) {
217                 resourceDeltas = new IResourceDelta[5];
218                 resourceDeltas[resourceDeltasCounter++] = child;
219                 return;
220         }
221         if (resourceDeltas.length == resourceDeltasCounter) {
222                 // need a resize
223                 System.arraycopy(resourceDeltas, 0, (resourceDeltas = new IResourceDelta[resourceDeltasCounter * 2]), 0, resourceDeltasCounter);
224         }
225         resourceDeltas[resourceDeltasCounter++] = child;
226 }
227 /**
228  * Creates the nested deltas resulting from a change operation.
229  * Convenience method for creating change deltas.
230  * The constructor should be used to create the root delta 
231  * and then a change operation should call this method.
232  */
233 public void changed(IJavaElement element, int changeFlag) {
234         JavaElementDelta changedDelta = new JavaElementDelta(element);
235         changedDelta.fKind = CHANGED;
236         changedDelta.fChangeFlags |= changeFlag;
237         insertDeltaTree(element, changedDelta);
238 }
239 /**
240  * Mark this delta as a content changed delta.
241  */
242 public void contentChanged() {
243         fChangeFlags |= F_CONTENT;
244 }
245 /**
246  * Clone this delta so that its elements are rooted at the given project.
247  */
248 public IJavaElementDelta clone(IJavaProject project) {
249         JavaElementDelta clone = 
250                 new JavaElementDelta(((JavaElement)fChangedElement).rootedAt(project));
251         if (fAffectedChildren != fgEmptyDelta) {
252                 int length = fAffectedChildren.length;
253                 IJavaElementDelta[] cloneChildren = new IJavaElementDelta[length];
254                 for (int i= 0; i < length; i++) {
255                         cloneChildren[i] = ((JavaElementDelta)fAffectedChildren[i]).clone(project);
256                 }
257                 clone.fAffectedChildren = cloneChildren;
258         }       
259         clone.fChangeFlags = fChangeFlags;
260         clone.fKind = fKind;
261         if (fMovedFromHandle != null) {
262                 clone.fMovedFromHandle = ((JavaElement)fMovedFromHandle).rootedAt(project);
263         }
264         if (fMovedToHandle != null) {
265                 clone.fMovedToHandle = ((JavaElement)fMovedToHandle).rootedAt(project);
266         }
267         clone.resourceDeltas = this.resourceDeltas;
268         clone.resourceDeltasCounter = this.resourceDeltasCounter;
269         return clone;
270 }
271
272 /**
273  * Creates the nested deltas for a closed element.
274  */
275 public void closed(IJavaElement element) {
276         JavaElementDelta delta = new JavaElementDelta(element);
277         delta.fKind = CHANGED;
278         delta.fChangeFlags |= F_CLOSED;
279         insertDeltaTree(element, delta);
280 }
281 /**
282  * Creates the nested delta deltas based on the affected element
283  * its delta, and the root of this delta tree. Returns the root
284  * of the created delta tree.
285  */
286 protected JavaElementDelta createDeltaTree(IJavaElement element, JavaElementDelta delta) {
287         JavaElementDelta childDelta = delta;
288         ArrayList ancestors= getAncestors(element);
289         if (ancestors == null) {
290                 if (this.equalsAndSameParent(delta.getElement(), getElement())) { // handle case of two jars that can be equals but not in the same project
291                         // the element being changed is the root element
292                         fKind= delta.fKind;
293                         fChangeFlags = delta.fChangeFlags;
294                         fMovedToHandle = delta.fMovedToHandle;
295                         fMovedFromHandle = delta.fMovedFromHandle;
296                 }
297         } else {
298                 for (int i = 0, size = ancestors.size(); i < size; i++) {
299                         IJavaElement ancestor = (IJavaElement) ancestors.get(i);
300                         JavaElementDelta ancestorDelta = new JavaElementDelta(ancestor);
301                         ancestorDelta.addAffectedChild(childDelta);
302                         childDelta = ancestorDelta;
303                 }
304         }
305         return childDelta;
306 }
307 /**
308  * Returns whether the two java elements are equals and have the same parent.
309  */
310 protected boolean equalsAndSameParent(IJavaElement e1, IJavaElement e2) {
311         IJavaElement parent1;
312         return e1.equals(e2) && ((parent1 = e1.getParent()) != null) && parent1.equals(e2.getParent());
313 }
314 /**
315  * Returns the <code>JavaElementDelta</code> for the given element
316  * in the delta tree, or null, if no delta for the given element is found.
317  */
318 protected JavaElementDelta find(IJavaElement e) {
319         if (this.equalsAndSameParent(fChangedElement, e)) { // handle case of two jars that can be equals but not in the same project
320                 return this;
321         } else {
322                 for (int i = 0; i < fAffectedChildren.length; i++) {
323                         JavaElementDelta delta = ((JavaElementDelta)fAffectedChildren[i]).find(e);
324                         if (delta != null) {
325                                 return delta;
326                         }
327                 }
328         }
329         return null;
330 }
331 /**
332  * Mark this delta as a fine-grained delta.
333  */
334 public void fineGrained() {
335         if (fKind == 0) { // if not set yet
336                 fKind = CHANGED;
337         }
338         fChangeFlags |= F_FINE_GRAINED;
339 }
340 /**
341  * @see IJavaElementDelta
342  */
343 public IJavaElementDelta[] getAddedChildren() {
344         return getChildrenOfType(ADDED);
345 }
346 /**
347  * @see IJavaElementDelta
348  */
349 public IJavaElementDelta[] getAffectedChildren() {
350         return fAffectedChildren;
351 }
352 /**
353  * Returns a collection of all the parents of this element up to (but
354  * not including) the root of this tree in bottom-up order. If the given
355  * element is not a descendant of the root of this tree, <code>null</code>
356  * is returned.
357  */
358 private ArrayList getAncestors(IJavaElement element) {
359         IJavaElement parent = element.getParent();
360         if (parent == null) {
361                 return null;
362         }
363         ArrayList parents = new ArrayList();
364         while (!parent.equals(fChangedElement)) {
365                 parents.add(parent);
366                 parent = parent.getParent();
367                 if (parent == null) {
368                         return null;
369                 }
370         }
371         parents.trimToSize();
372         return parents;
373 }
374 /**
375  * @see IJavaElementDelta
376  */
377 public IJavaElementDelta[] getChangedChildren() {
378         return getChildrenOfType(CHANGED);
379 }
380 /**
381  * @see IJavaElementDelta
382  */
383 protected IJavaElementDelta[] getChildrenOfType(int type) {
384         int length = fAffectedChildren.length;
385         if (length == 0) {
386                 return new IJavaElementDelta[] {};
387         }
388         ArrayList children= new ArrayList(length);
389         for (int i = 0; i < length; i++) {
390                 if (fAffectedChildren[i].getKind() == type) {
391                         children.add(fAffectedChildren[i]);
392                 }
393         }
394
395         IJavaElementDelta[] childrenOfType = new IJavaElementDelta[children.size()];
396         children.toArray(childrenOfType);
397         
398         return childrenOfType;
399 }
400 /**
401  * Returns the delta for a given element.  Only looks below this
402  * delta.
403  */
404 protected JavaElementDelta getDeltaFor(IJavaElement element) {
405         if (this.equalsAndSameParent(getElement(), element)) // handle case of two jars that can be equals but not in the same project
406                 return this;
407         if (fAffectedChildren.length == 0)
408                 return null;
409         int childrenCount = fAffectedChildren.length;
410         for (int i = 0; i < childrenCount; i++) {
411                 JavaElementDelta delta = (JavaElementDelta)fAffectedChildren[i];
412                 if (this.equalsAndSameParent(delta.getElement(), element)) { // handle case of two jars that can be equals but not in the same project
413                         return delta;
414                 } else {
415                         delta = ((JavaElementDelta)delta).getDeltaFor(element);
416                         if (delta != null)
417                                 return delta;
418                 }
419         }
420         return null;
421 }
422 /**
423  * @see IJavaElementDelta
424  */
425 public IJavaElement getElement() {
426         return fChangedElement;
427 }
428 /**
429  * @see IJavaElementDelta
430  */
431 public int getFlags() {
432         return fChangeFlags;
433 }
434 /**
435  * @see IJavaElementDelta
436  */
437 public int getKind() {
438         return fKind;
439 }
440 /**
441  * @see IJavaElementDelta
442  */
443 public IJavaElement getMovedFromElement() {
444         return fMovedFromHandle;
445 }
446 /**
447  * @see IJavaElementDelta
448  */
449 public IJavaElement getMovedToElement() {
450         return fMovedToHandle;
451 }
452 /**
453  * @see IJavaElementDelta
454  */
455 public IJavaElementDelta[] getRemovedChildren() {
456         return getChildrenOfType(REMOVED);
457 }
458 /**
459  * Return the collection of resource deltas. Return null if none.
460  */
461 public IResourceDelta[] getResourceDeltas() {
462         if (resourceDeltas == null) return null;
463         if (resourceDeltas.length != resourceDeltasCounter) {
464                 System.arraycopy(resourceDeltas, 0, resourceDeltas = new IResourceDelta[resourceDeltasCounter], 0, resourceDeltasCounter);
465         }
466         return resourceDeltas;
467 }
468 /**
469  * Adds the new element to a new array that contains all of the elements of the old array.
470  * Returns the new array.
471  */
472 protected IJavaElementDelta[] growAndAddToArray(IJavaElementDelta[] array, IJavaElementDelta addition) {
473         IJavaElementDelta[] old = array;
474         array = new IJavaElementDelta[old.length + 1];
475         System.arraycopy(old, 0, array, 0, old.length);
476         array[old.length] = addition;
477         return array;
478 }
479 /**
480  * Creates the delta tree for the given element and delta, and then
481  * inserts the tree as an affected child of this node.
482  */
483 protected void insertDeltaTree(IJavaElement element, JavaElementDelta delta) {
484         JavaElementDelta childDelta= createDeltaTree(element, delta);
485         if (!this.equalsAndSameParent(element, getElement())) { // handle case of two jars that can be equals but not in the same project
486                 addAffectedChild(childDelta);
487         }
488 }
489 /**
490  * Creates the nested deltas resulting from an move operation.
491  * Convenience method for creating the "move from" delta.
492  * The constructor should be used to create the root delta 
493  * and then the move operation should call this method.
494  */
495 public void movedFrom(IJavaElement movedFromElement, IJavaElement movedToElement) {
496         JavaElementDelta removedDelta = new JavaElementDelta(movedFromElement);
497         removedDelta.fKind = REMOVED;
498         removedDelta.fChangeFlags |= F_MOVED_TO;
499         removedDelta.fMovedToHandle = movedToElement;
500         insertDeltaTree(movedFromElement, removedDelta);
501 }
502 /**
503  * Creates the nested deltas resulting from an move operation.
504  * Convenience method for creating the "move to" delta.
505  * The constructor should be used to create the root delta 
506  * and then the move operation should call this method.
507  */
508 public void movedTo(IJavaElement movedToElement, IJavaElement movedFromElement) {
509         JavaElementDelta addedDelta = new JavaElementDelta(movedToElement);
510         addedDelta.fKind = ADDED;
511         addedDelta.fChangeFlags |= F_MOVED_FROM;
512         addedDelta.fMovedFromHandle = movedFromElement;
513         insertDeltaTree(movedToElement, addedDelta);
514 }
515 /**
516  * Creates the nested deltas for an opened element.
517  */
518 public void opened(IJavaElement element) {
519         JavaElementDelta delta = new JavaElementDelta(element);
520         delta.fKind = CHANGED;
521         delta.fChangeFlags |= F_OPENED;
522         insertDeltaTree(element, delta);
523 }
524 /**
525  * Removes the child delta from the collection of affected children.
526  */
527 protected void removeAffectedChild(JavaElementDelta child) {
528         int index = -1;
529         if (fAffectedChildren != null) {
530                 for (int i = 0; i < fAffectedChildren.length; i++) {
531                         if (this.equalsAndSameParent(fAffectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
532                                 index = i;
533                                 break;
534                         }
535                 }
536         }
537         if (index >= 0) {
538                 fAffectedChildren= removeAndShrinkArray(fAffectedChildren, index);
539         }
540 }
541 /**
542  * Removes the element from the array.
543  * Returns the a new array which has shrunk.
544  */
545 protected IJavaElementDelta[] removeAndShrinkArray(IJavaElementDelta[] old, int index) {
546         IJavaElementDelta[] array = new IJavaElementDelta[old.length - 1];
547         if (index > 0)
548                 System.arraycopy(old, 0, array, 0, index);
549         int rest = old.length - index - 1;
550         if (rest > 0)
551                 System.arraycopy(old, index + 1, array, index, rest);
552         return array;
553 }
554 /**
555  * Creates the nested deltas resulting from an delete operation.
556  * Convenience method for creating removed deltas.
557  * The constructor should be used to create the root delta 
558  * and then the delete operation should call this method.
559  */
560 public void removed(IJavaElement element) {
561         JavaElementDelta removedDelta= new JavaElementDelta(element);
562         insertDeltaTree(element, removedDelta);
563         JavaElementDelta actualDelta = getDeltaFor(element);
564         if (actualDelta != null) {
565                 actualDelta.fKind = REMOVED;
566                 actualDelta.fChangeFlags = 0;
567                 actualDelta.fAffectedChildren = fgEmptyDelta;
568         }
569 }
570 /**
571  * Creates the nested deltas resulting from a change operation.
572  * Convenience method for creating change deltas.
573  * The constructor should be used to create the root delta 
574  * and then a change operation should call this method.
575  */
576 public void sourceAttached(IJavaElement element) {
577         JavaElementDelta attachedDelta = new JavaElementDelta(element);
578         attachedDelta.fKind = CHANGED;
579         attachedDelta.fChangeFlags |= F_SOURCEATTACHED;
580         insertDeltaTree(element, attachedDelta);
581 }
582 /**
583  * Creates the nested deltas resulting from a change operation.
584  * Convenience method for creating change deltas.
585  * The constructor should be used to create the root delta 
586  * and then a change operation should call this method.
587  */
588 public void sourceDetached(IJavaElement element) {
589         JavaElementDelta detachedDelta = new JavaElementDelta(element);
590         detachedDelta.fKind = CHANGED;
591         detachedDelta.fChangeFlags |= F_SOURCEDETACHED;
592         insertDeltaTree(element, detachedDelta);
593 }
594 /** 
595  * Returns a string representation of this delta's
596  * structure suitable for debug purposes.
597  *
598  * @see #toString()
599  */
600 public String toDebugString(int depth) {
601         StringBuffer buffer = new StringBuffer();
602         for (int i= 0; i < depth; i++) {
603                 buffer.append('\t');
604         }
605         buffer.append(((JavaElement)getElement()).toDebugString());
606         buffer.append("["); //$NON-NLS-1$
607         switch (getKind()) {
608                 case IJavaElementDelta.ADDED :
609                         buffer.append('+');
610                         break;
611                 case IJavaElementDelta.REMOVED :
612                         buffer.append('-');
613                         break;
614                 case IJavaElementDelta.CHANGED :
615                         buffer.append('*');
616                         break;
617                 default :
618                         buffer.append('?');
619                         break;
620         }
621         buffer.append("]: {"); //$NON-NLS-1$
622         int changeFlags = getFlags();
623         boolean prev = false;
624         if ((changeFlags & IJavaElementDelta.F_CHILDREN) != 0) {
625                 if (prev)
626                         buffer.append(" | "); //$NON-NLS-1$
627                 buffer.append("CHILDREN"); //$NON-NLS-1$
628                 prev = true;
629         }
630         if ((changeFlags & IJavaElementDelta.F_CONTENT) != 0) {
631                 if (prev)
632                         buffer.append(" | "); //$NON-NLS-1$
633                 buffer.append("CONTENT"); //$NON-NLS-1$
634                 prev = true;
635         }
636         if ((changeFlags & IJavaElementDelta.F_MOVED_FROM) != 0) {
637                 if (prev)
638                         buffer.append(" | "); //$NON-NLS-1$
639                 buffer.append("MOVED_FROM(" + ((JavaElement)getMovedFromElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
640                 prev = true;
641         }
642         if ((changeFlags & IJavaElementDelta.F_MOVED_TO) != 0) {
643                 if (prev)
644                         buffer.append(" | "); //$NON-NLS-1$
645                 buffer.append("MOVED_TO(" + ((JavaElement)getMovedToElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
646                 prev = true;
647         }
648         if ((changeFlags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) {
649                 if (prev)
650                         buffer.append(" | "); //$NON-NLS-1$
651                 buffer.append("ADDED TO CLASSPATH"); //$NON-NLS-1$
652                 prev = true;
653         }
654         if ((changeFlags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) {
655                 if (prev)
656                         buffer.append(" | "); //$NON-NLS-1$
657                 buffer.append("REMOVED FROM CLASSPATH"); //$NON-NLS-1$
658                 prev = true;
659         }
660         if ((changeFlags & IJavaElementDelta.F_REORDER) != 0) {
661                 if (prev)
662                         buffer.append(" | "); //$NON-NLS-1$
663                 buffer.append("REORDERED"); //$NON-NLS-1$
664                 prev = true;
665         }
666         if ((changeFlags & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
667                 if (prev)
668                         buffer.append(" | "); //$NON-NLS-1$
669                 buffer.append("ARCHIVE CONTENT CHANGED"); //$NON-NLS-1$
670                 prev = true;
671         }
672         if ((changeFlags & IJavaElementDelta.F_SOURCEATTACHED) != 0) {
673                 if (prev)
674                         buffer.append(" | "); //$NON-NLS-1$
675                 buffer.append("SOURCE ATTACHED"); //$NON-NLS-1$
676                 prev = true;
677         }
678         if ((changeFlags & IJavaElementDelta.F_SOURCEDETACHED) != 0) {
679                 if (prev)
680                         buffer.append(" | "); //$NON-NLS-1$
681                 buffer.append("SOURCE DETACHED"); //$NON-NLS-1$
682                 prev = true;
683         }
684         if ((changeFlags & IJavaElementDelta.F_MODIFIERS) != 0) {
685                 if (prev)
686                         buffer.append(" | "); //$NON-NLS-1$
687                 buffer.append("MODIFIERS CHANGED"); //$NON-NLS-1$
688                 prev = true;
689         }
690         if ((changeFlags & IJavaElementDelta.F_SUPER_TYPES) != 0) {
691                 if (prev)
692                         buffer.append(" | "); //$NON-NLS-1$
693                 buffer.append("SUPER TYPES CHANGED"); //$NON-NLS-1$
694                 prev = true;
695         }
696         if ((changeFlags & IJavaElementDelta.F_FINE_GRAINED) != 0) {
697                 if (prev)
698                         buffer.append(" | "); //$NON-NLS-1$
699                 buffer.append("FINE GRAINED"); //$NON-NLS-1$
700                 prev = true;
701         }
702         buffer.append("}"); //$NON-NLS-1$
703         IJavaElementDelta[] children = getAffectedChildren();
704         if (children != null) {
705                 for (int i = 0; i < children.length; ++i) {
706                         buffer.append("\n"); //$NON-NLS-1$
707                         buffer.append(((JavaElementDelta) children[i]).toDebugString(depth + 1));
708                 }
709         }
710         for (int i = 0; i < resourceDeltasCounter; i++) {
711                 buffer.append("\n");//$NON-NLS-1$
712                 for (int j = 0; j < depth+1; j++) {
713                         buffer.append('\t');
714                 }
715                 IResourceDelta resourceDelta = resourceDeltas[i];
716                 buffer.append(resourceDelta.toString());
717                 buffer.append("["); //$NON-NLS-1$
718                 switch (resourceDelta.getKind()) {
719                         case IResourceDelta.ADDED :
720                                 buffer.append('+');
721                                 break;
722                         case IResourceDelta.REMOVED :
723                                 buffer.append('-');
724                                 break;
725                         case IResourceDelta.CHANGED :
726                                 buffer.append('*');
727                                 break;
728                         default :
729                                 buffer.append('?');
730                                 break;
731                 }
732                 buffer.append("]"); //$NON-NLS-1$
733         }
734         return buffer.toString();
735 }
736 /** 
737  * Returns a string representation of this delta's
738  * structure suitable for debug purposes.
739  */
740 public String toString() {
741         return toDebugString(0);
742 }
743 }