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