/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core; import java.util.ArrayList; import net.sourceforge.phpdt.core.IJavaElement; import net.sourceforge.phpdt.core.IJavaElementDelta; import org.eclipse.core.resources.IResourceDelta; /** * @see IJavaElementDelta */ public class JavaElementDelta extends SimpleDelta implements IJavaElementDelta { /** * The element that this delta describes the change to. * * @see #getElement() */ protected IJavaElement fChangedElement; /** * @see #getKind() */ private int fKind = 0; /** * @see #getFlags() */ private int fChangeFlags = 0; /** * @see #getAffectedChildren() */ protected IJavaElementDelta[] fAffectedChildren = fgEmptyDelta; /** * Collection of resource deltas that correspond to non java resources * deltas. */ protected IResourceDelta[] resourceDeltas = null; /** * Counter of resource deltas */ protected int resourceDeltasCounter; /** * @see #getMovedFromHandle() */ protected IJavaElement fMovedFromHandle = null; /** * @see #getMovedToHandle() */ protected IJavaElement fMovedToHandle = null; /** * Empty array of IJavaElementDelta */ protected static IJavaElementDelta[] fgEmptyDelta = new IJavaElementDelta[] {}; /** * Creates the root delta. To create the nested delta hierarchies use the * following convenience methods. The root delta can be created at any level * (for example: project, package root, package fragment...). *
added(IJavaElement)
* changed(IJavaElement)
* moved(IJavaElement, IJavaElement)
* removed(IJavaElement)
* renamed(IJavaElement, IJavaElement)
* JavaElementDelta
for the given element in the
* delta tree, or null, if no delta for the given element is found.
*/
protected JavaElementDelta find(IJavaElement e) {
if (this.equalsAndSameParent(fChangedElement, e)) { // handle case of
// two jars that can
// be equals but not
// in the same
// project
return this;
} else {
for (int i = 0; i < fAffectedChildren.length; i++) {
JavaElementDelta delta = ((JavaElementDelta) fAffectedChildren[i])
.find(e);
if (delta != null) {
return delta;
}
}
}
return null;
}
/**
* Mark this delta as a fine-grained delta.
*/
public void fineGrained() {
if (fKind == 0) { // if not set yet
fKind = CHANGED;
}
fChangeFlags |= F_FINE_GRAINED;
}
/**
* @see IJavaElementDelta
*/
public IJavaElementDelta[] getAddedChildren() {
return getChildrenOfType(ADDED);
}
/**
* @see IJavaElementDelta
*/
public IJavaElementDelta[] getAffectedChildren() {
return fAffectedChildren;
}
/**
* Returns a collection of all the parents of this element up to (but not
* including) the root of this tree in bottom-up order. If the given element
* is not a descendant of the root of this tree, null
is
* returned.
*/
private ArrayList getAncestors(IJavaElement element) {
IJavaElement parent = element.getParent();
if (parent == null) {
return null;
}
ArrayList parents = new ArrayList();
while (!parent.equals(fChangedElement)) {
parents.add(parent);
parent = parent.getParent();
if (parent == null) {
return null;
}
}
parents.trimToSize();
return parents;
}
/**
* @see IJavaElementDelta
*/
public IJavaElementDelta[] getChangedChildren() {
return getChildrenOfType(CHANGED);
}
/**
* @see IJavaElementDelta
*/
protected IJavaElementDelta[] getChildrenOfType(int type) {
int length = fAffectedChildren.length;
if (length == 0) {
return new IJavaElementDelta[] {};
}
ArrayList children = new ArrayList(length);
for (int i = 0; i < length; i++) {
if (fAffectedChildren[i].getKind() == type) {
children.add(fAffectedChildren[i]);
}
}
IJavaElementDelta[] childrenOfType = new IJavaElementDelta[children
.size()];
children.toArray(childrenOfType);
return childrenOfType;
}
/**
* Returns the delta for a given element. Only looks below this delta.
*/
protected JavaElementDelta getDeltaFor(IJavaElement element) {
if (this.equalsAndSameParent(getElement(), element)) // handle case
// of two jars
// that can be
// equals but
// not in the
// same project
return this;
if (fAffectedChildren.length == 0)
return null;
int childrenCount = fAffectedChildren.length;
for (int i = 0; i < childrenCount; i++) {
JavaElementDelta delta = (JavaElementDelta) fAffectedChildren[i];
if (this.equalsAndSameParent(delta.getElement(), element)) { // handle
// case
// of
// two
// jars
// that
// can
// be
// equals
// but
// not
// in
// the
// same
// project
return delta;
} else {
delta = ((JavaElementDelta) delta).getDeltaFor(element);
if (delta != null)
return delta;
}
}
return null;
}
/**
* @see IJavaElementDelta
*/
public IJavaElement getElement() {
return fChangedElement;
}
/**
* @see IJavaElementDelta
*/
public int getFlags() {
return fChangeFlags;
}
/**
* @see IJavaElementDelta
*/
public int getKind() {
return fKind;
}
/**
* @see IJavaElementDelta
*/
public IJavaElement getMovedFromElement() {
return fMovedFromHandle;
}
/**
* @see IJavaElementDelta
*/
public IJavaElement getMovedToElement() {
return fMovedToHandle;
}
/**
* @see IJavaElementDelta
*/
public IJavaElementDelta[] getRemovedChildren() {
return getChildrenOfType(REMOVED);
}
/**
* Return the collection of resource deltas. Return null if none.
*/
public IResourceDelta[] getResourceDeltas() {
if (resourceDeltas == null)
return null;
if (resourceDeltas.length != resourceDeltasCounter) {
System.arraycopy(resourceDeltas, 0,
resourceDeltas = new IResourceDelta[resourceDeltasCounter],
0, resourceDeltasCounter);
}
return resourceDeltas;
}
/**
* Adds the new element to a new array that contains all of the elements of
* the old array. Returns the new array.
*/
protected IJavaElementDelta[] growAndAddToArray(IJavaElementDelta[] array,
IJavaElementDelta addition) {
IJavaElementDelta[] old = array;
array = new IJavaElementDelta[old.length + 1];
System.arraycopy(old, 0, array, 0, old.length);
array[old.length] = addition;
return array;
}
/**
* Creates the delta tree for the given element and delta, and then inserts
* the tree as an affected child of this node.
*/
protected void insertDeltaTree(IJavaElement element, JavaElementDelta delta) {
JavaElementDelta childDelta = createDeltaTree(element, delta);
if (!this.equalsAndSameParent(element, getElement())) { // handle case
// of two jars
// that can be
// equals but
// not in the
// same project
addAffectedChild(childDelta);
}
}
/**
* Creates the nested deltas resulting from an move operation. Convenience
* method for creating the "move from" delta. The constructor should be used
* to create the root delta and then the move operation should call this
* method.
*/
public void movedFrom(IJavaElement movedFromElement,
IJavaElement movedToElement) {
JavaElementDelta removedDelta = new JavaElementDelta(movedFromElement);
removedDelta.fKind = REMOVED;
removedDelta.fChangeFlags |= F_MOVED_TO;
removedDelta.fMovedToHandle = movedToElement;
insertDeltaTree(movedFromElement, removedDelta);
}
/**
* Creates the nested deltas resulting from an move operation. Convenience
* method for creating the "move to" delta. The constructor should be used
* to create the root delta and then the move operation should call this
* method.
*/
public void movedTo(IJavaElement movedToElement,
IJavaElement movedFromElement) {
JavaElementDelta addedDelta = new JavaElementDelta(movedToElement);
addedDelta.fKind = ADDED;
addedDelta.fChangeFlags |= F_MOVED_FROM;
addedDelta.fMovedFromHandle = movedFromElement;
insertDeltaTree(movedToElement, addedDelta);
}
/**
* Creates the nested deltas for an opened element.
*/
// public void opened(IJavaElement element) {
// JavaElementDelta delta = new JavaElementDelta(element);
// delta.fKind = CHANGED;
// delta.fChangeFlags |= F_OPENED;
// insertDeltaTree(element, delta);
// }
/**
* Removes the child delta from the collection of affected children.
*/
protected void removeAffectedChild(JavaElementDelta child) {
int index = -1;
if (fAffectedChildren != null) {
for (int i = 0; i < fAffectedChildren.length; i++) {
if (this.equalsAndSameParent(fAffectedChildren[i].getElement(),
child.getElement())) { // handle case of two jars that
// can be equals but not in the
// same project
index = i;
break;
}
}
}
if (index >= 0) {
fAffectedChildren = removeAndShrinkArray(fAffectedChildren, index);
}
}
/**
* Removes the element from the array. Returns the a new array which has
* shrunk.
*/
protected IJavaElementDelta[] removeAndShrinkArray(IJavaElementDelta[] old,
int index) {
IJavaElementDelta[] array = new IJavaElementDelta[old.length - 1];
if (index > 0)
System.arraycopy(old, 0, array, 0, index);
int rest = old.length - index - 1;
if (rest > 0)
System.arraycopy(old, index + 1, array, index, rest);
return array;
}
/**
* Creates the nested deltas resulting from an delete operation. Convenience
* method for creating removed deltas. The constructor should be used to
* create the root delta and then the delete operation should call this
* method.
*/
public void removed(IJavaElement element) {
removed(element, 0);
}
public void removed(IJavaElement element, int flags) {
JavaElementDelta removedDelta = new JavaElementDelta(element);
insertDeltaTree(element, removedDelta);
JavaElementDelta actualDelta = getDeltaFor(element);
if (actualDelta != null) {
actualDelta.removed();
actualDelta.changeFlags |= flags;
actualDelta.fAffectedChildren = fgEmptyDelta;
}
}
/**
* Creates the nested deltas resulting from a change operation. Convenience
* method for creating change deltas. The constructor should be used to
* create the root delta and then a change operation should call this
* method.
*/
// public void sourceAttached(IJavaElement element) {
// JavaElementDelta attachedDelta = new JavaElementDelta(element);
// attachedDelta.fKind = CHANGED;
// attachedDelta.fChangeFlags |= F_SOURCEATTACHED;
// insertDeltaTree(element, attachedDelta);
// }
/**
* Creates the nested deltas resulting from a change operation. Convenience
* method for creating change deltas. The constructor should be used to
* create the root delta and then a change operation should call this
* method.
*/
// public void sourceDetached(IJavaElement element) {
// JavaElementDelta detachedDelta = new JavaElementDelta(element);
// detachedDelta.fKind = CHANGED;
// detachedDelta.fChangeFlags |= F_SOURCEDETACHED;
// insertDeltaTree(element, detachedDelta);
// }
/**
* Returns a string representation of this delta's structure suitable for
* debug purposes.
*
* @see #toString()
*/
public String toDebugString(int depth) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < depth; i++) {
buffer.append('\t');
}
buffer.append(((JavaElement) getElement()).toDebugString());
buffer.append("["); //$NON-NLS-1$
switch (getKind()) {
case IJavaElementDelta.ADDED:
buffer.append('+');
break;
case IJavaElementDelta.REMOVED:
buffer.append('-');
break;
case IJavaElementDelta.CHANGED:
buffer.append('*');
break;
default:
buffer.append('?');
break;
}
buffer.append("]: {"); //$NON-NLS-1$
int changeFlags = getFlags();
boolean prev = false;
if ((changeFlags & IJavaElementDelta.F_CHILDREN) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CHILDREN"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_CONTENT) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CONTENT"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_MOVED_FROM) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer
.append("MOVED_FROM(" + ((JavaElement) getMovedFromElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_MOVED_TO) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer
.append("MOVED_TO(" + ((JavaElement) getMovedToElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("ADDED TO CLASSPATH"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("REMOVED FROM CLASSPATH"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_REORDER) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("REORDERED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("ARCHIVE CONTENT CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_SOURCEATTACHED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("SOURCE ATTACHED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_SOURCEDETACHED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("SOURCE DETACHED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_MODIFIERS) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("MODIFIERS CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_SUPER_TYPES) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("SUPER TYPES CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((changeFlags & IJavaElementDelta.F_FINE_GRAINED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("FINE GRAINED"); //$NON-NLS-1$
prev = true;
}
buffer.append("}"); //$NON-NLS-1$
IJavaElementDelta[] children = getAffectedChildren();
if (children != null) {
for (int i = 0; i < children.length; ++i) {
buffer.append("\n"); //$NON-NLS-1$
buffer.append(((JavaElementDelta) children[i])
.toDebugString(depth + 1));
}
}
for (int i = 0; i < resourceDeltasCounter; i++) {
buffer.append("\n");//$NON-NLS-1$
for (int j = 0; j < depth + 1; j++) {
buffer.append('\t');
}
IResourceDelta resourceDelta = resourceDeltas[i];
buffer.append(resourceDelta.toString());
buffer.append("["); //$NON-NLS-1$
switch (resourceDelta.getKind()) {
case IResourceDelta.ADDED:
buffer.append('+');
break;
case IResourceDelta.REMOVED:
buffer.append('-');
break;
case IResourceDelta.CHANGED:
buffer.append('*');
break;
default:
buffer.append('?');
break;
}
buffer.append("]"); //$NON-NLS-1$
}
return buffer.toString();
}
/**
* Returns a string representation of this delta's structure suitable for
* debug purposes.
*/
public String toString() {
return toDebugString(0);
}
}