blob: a2960a2a77b1f4a752eb5f44f6f3582e752ba987 [file] [log] [blame]
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
package org.eclipse.compare.structuremergeviewer;
import java.text.MessageFormat;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.compare.*;
import org.eclipse.compare.internal.Utilities;
/**
* Diff node are used as the compare result of the differencing engine.
* Since it implements the <code>ITypedElement</code> and <code>ICompareInput</code>
* interfaces it can be used directly to display the
* compare result in a <code>DiffTreeViewer</code> and as the input to any other
* compare/merge viewer.
* <p>
* <code>DiffNode</code>s are typically created as the result of performing
* a compare with the <code>Differencer</code>.
* <p>
* Clients typically use this class as is, but may subclass if required.
*
* @see DiffTreeViewer
* @see Differencer
*/
public class DiffNode extends DiffContainer implements ITypedElement, ICompareInput {
private ITypedElement fAncestor;
private ITypedElement fLeft;
private ITypedElement fRight;
private boolean fDontExpand;
private ListenerList fListener;
private boolean fSwapSides;
/**
* Creates a new <code>DiffNode</code> and initializes with the given values.
*
* @param parent under which the new container is added as a child or <code>null</code>
* @param kind of difference (defined in <code>Differencer</code>)
* @param ancestor the common ancestor input to a compare
* @param left the left input to a compare
* @param right the right input to a compare
*/
public DiffNode(IDiffContainer parent, int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right) {
this(parent, kind);
fAncestor= ancestor;
fLeft= left;
fRight= right;
}
/**
* Creates a new <code>DiffNode</code> with diff kind <code>Differencer.CHANGE</code>
* and initializes with the given values.
*
* @param left the left input to a compare
* @param right the right input to a compare
*/
public DiffNode(ITypedElement left, ITypedElement right) {
this(null, Differencer.CHANGE, null, left, right);
}
/**
* Creates a new <code>DiffNode</code> and initializes with the given values.
*
* @param kind of difference (defined in <code>Differencer</code>)
* @param ancestor the common ancestor input to a compare
* @param left the left input to a compare
* @param right the right input to a compare
*/
public DiffNode(int kind, ITypedElement ancestor, ITypedElement left, ITypedElement right) {
this(null, kind, ancestor, left, right);
}
/**
* Creates a new <code>DiffNode</code> with the given diff kind.
*
* @param kind of difference (defined in <code>Differencer</code>)
*/
public DiffNode(int kind) {
super(null, kind);
}
/**
* Creates a new <code>DiffNode</code> and initializes with the given values.
*
* @param parent under which the new container is added as a child or <code>null</code>
* @param kind of difference (defined in <code>Differencer</code>)
*/
public DiffNode(IDiffContainer parent, int kind) {
super(parent, kind);
}
/**
* Registers a listener for changes of this <code>ICompareInput</code>.
* Has no effect if an identical listener is already registered.
*
* @param listener the listener to add
*/
public void addCompareInputChangeListener(ICompareInputChangeListener listener) {
if (fListener == null)
fListener= new ListenerList();
fListener.add(listener);
}
/**
* Unregisters a <code>ICompareInput</code> listener.
* Has no effect if listener is not registered.
*
* @param listener the listener to remove
*/
public void removeCompareInputChangeListener(ICompareInputChangeListener listener) {
if (fListener != null) {
fListener.remove(listener);
if (fListener.isEmpty())
fListener= null;
}
}
/**
* Sends out notification that a change has occured on the <code>ICompareInput</code>.
*/
protected void fireChange() {
if (fListener != null) {
Object[] listeners= fListener.getListeners();
for (int i= 0; i < listeners.length; i++)
((ICompareInputChangeListener) listeners[i]).compareInputChanged(this);
}
}
//---- getters & setters
/**
* Returns <code>true</code> if this node shouldn't automatically be expanded in
* a </code>DiffTreeViewer</code>.
*
* @return <code>true</code> if node shouldn't automatically be expanded
*/
public boolean dontExpand() {
return fDontExpand;
}
/**
* Controls whether this node is not automatically expanded when displayed in
* a </code>DiffTreeViewer</code>.
*
* @param dontExpand if <code>true</code> this node is not automatically expanded in </code>DiffTreeViewer</code>
*/
public void setDontExpand(boolean dontExpand) {
fDontExpand= dontExpand;
}
/**
* Returns the first not-<code>null</code> input of this node.
* Method checks the three inputs in the order: ancestor, right, left.
*
* @return the first not-<code>null</code> input of this node
*/
public ITypedElement getId() {
if (fAncestor != null)
return fAncestor;
if (fRight != null)
return fRight;
return fLeft;
}
/**
* Returns the (non-<code>null</code>) name of the left or right side if they are identical.
* Otherwise both names are concatenated (separated with a slash ('/')).
* <p>
* Subclasses may re-implement to provide a different name for this node.
*/
/* (non Javadoc)
* see ITypedElement.getName
*/
public String getName() {
String right= null;
if (fRight != null)
right= fRight.getName();
String left= null;
if (fLeft != null)
left= fLeft.getName();
if (right == null && left == null) {
if (fAncestor != null)
return fAncestor.getName();
return Utilities.getString("DiffNode.noName"); //$NON-NLS-1$
}
if (right == null)
return left;
if (left == null)
return right;
if (right.equals(left))
return right;
String s1;
String s2;
if (fSwapSides) {
s1= left;
s2= right;
} else {
s1= right;
s2= left;
}
String fmt= Utilities.getString("DiffNode.nameFormat"); //$NON-NLS-1$
return MessageFormat.format(fmt, new String[] { s1, s2 });
}
void swapSides(boolean swap) {
fSwapSides= swap;
}
/* (non Javadoc)
* see ITypedElement.getImage
*/
public Image getImage() {
ITypedElement id= getId();
if (id != null)
return id.getImage();
return null;
}
/* (non Javadoc)
* see ITypedElement.getType
*/
public String getType() {
ITypedElement id= getId();
if (id != null)
return id.getType();
return ITypedElement.UNKNOWN_TYPE;
}
/* (non Javadoc)
* see ICompareInput.getAncestor
*/
public ITypedElement getAncestor() {
return fAncestor;
}
/**
* Sets the left input to the given value.
*
* @param left the new value for the left input
*/
public void setLeft(ITypedElement left) {
fLeft= left;
}
/* (non Javadoc)
* see ICompareInput.getLeft
*/
public ITypedElement getLeft() {
return fLeft;
}
/**
* Sets the right input to the given value.
*
* @param right the new value for the right input
*/
public void setRight(ITypedElement right) {
fRight= right;
}
/* (non Javadoc)
* see ICompareInput.getRight
*/
public ITypedElement getRight() {
return fRight;
}
/* (non Javadoc)
* see ICompareInput.copy
*/
public void copy(boolean leftToRight) {
//System.out.println("DiffNode.copy: " + leftToRight);
IDiffContainer pa= getParent();
if (pa instanceof ICompareInput) {
ICompareInput parent= (ICompareInput) pa;
Object dstParent= leftToRight ? parent.getRight() : parent.getLeft();
if (dstParent instanceof IEditableContent) {
ITypedElement dst= leftToRight ? getRight() : getLeft();
ITypedElement src= leftToRight ? getLeft() : getRight();
dst= ((IEditableContent)dstParent).replace(dst, src);
if (leftToRight)
setRight(dst);
else
setLeft(dst);
//setKind(Differencer.NO_CHANGE);
fireChange();
}
}
}
/* (non Javadoc)
* see Object.hashCode
*/
public int hashCode() {
String[] path= getPath(this, 0);
int hashCode= 1;
for (int i= 0; i < path.length; i++) {
String s= path[i];
hashCode= (31*hashCode) + (s != null ? s.hashCode() : 0);
}
return hashCode;
}
/* (non Javadoc)
* see Object.equals
*/
public boolean equals(Object other) {
if (other != null && getClass() == other.getClass()) {
String[] path1= getPath(this, 0);
String[] path2= getPath((DiffNode) other, 0);
if (path1.length != path2.length)
return false;
for (int i= 0; i < path1.length; i++)
if (! path1[i].equals(path2[i]))
return false;
return true;
}
return super.equals(other);
}
private static String[] getPath(ITypedElement el, int level) {
String[] path= null;
if (el instanceof IDiffContainer) {
IDiffContainer parent= ((IDiffContainer)el).getParent();
if (parent instanceof ITypedElement)
path= getPath((ITypedElement)parent, level+1);
}
if (path == null)
path= new String[level+1];
path[(path.length-1)-level]= el.getName();
return path;
}
}