Update of /cvsroot/jcommander/plugins/org.jcommander.eclipsepatch.compare/compare/org/eclipse/compare/structuremergeviewer In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5127/compare/org/eclipse/compare/structuremergeviewer Added Files: DiffTreeViewer.java ICompareInputChangeListener.java Differencer.java DiffTreeViewerResources.properties ICompareInput.java package.html IDiffElement.java IStructureComparator.java IStructureCreator.java DiffElement.java DiffNode.java DocumentRangeNode.java StructureDiffViewer.java DiffContainer.java IDiffContainer.java Log Message: org.eclipse.compare, extracted from the Eclipse CVS. Now independent of org.eclipse.ui.ide etc. --- NEW FILE: ICompareInput.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import org.eclipse.compare.ITypedElement; import org.eclipse.swt.graphics.Image; /** * Interface for objects used as input to a two-way or three-way compare viewer. * It defines API for accessing the three sides for the compare, * and a name and image which is used when displaying the three way input * in the UI, for example, in a title bar. * <p> * Note: at most two sides of an <code>ICompareInput</code> can be <code>null</code>, * (as it is normal for additions or deletions) but not all three. * <p> * <code>ICompareInput</code> provides methods for registering * <code>ICompareInputChangeListener</code>s * that get informed if one (or more) * of the three sides of an <code>ICompareInput</code> object changes its value. * <p> * For example when accepting an incoming addition * the (non-<code>null</code>) left side of an <code>ICompareInput</code> * is copied to the right side by means of method <code>copy</code>. * This should trigger a call to <code>compareInputChanged</code> of registered * <code>ICompareInputChangeListener</code>s. * <p> * Clients can implement this interface, or use the convenience implementation * <code>DiffNode</code>. * </p> * * @see StructureDiffViewer * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer * @see DiffNode */ public interface ICompareInput { /** * Returns name of input. * This name is displayed when this input is shown in a viewer. * In many cases this name is the name of one of the non-<code>null</code> sides or a combination * thereof. * * @return name of input */ String getName(); /** * Returns an image representing this input. * This image is typically displayed when this input is shown in a viewer. * In many cases this image is the image of one of the non-<code>null</code> sides. * * @return image representing this input, or <code>null</code> if no icon should be shown */ Image getImage(); /** * Returns the kind of difference between the * three sides ancestor, left and right. * This field is only meaningful if the <code>ICompareInput</code> * is the result of another compare. In this case it is used * together with <code>getImage</code> to compose a icon * which reflects the kind of difference between the two or three elements. * * @return kind of difference (see <code>Differencer</code>) */ int getKind(); /** * Returns the ancestor side of this input. * Returns <code>null</code> if this input has no ancestor * or in the two-way compare case. * * @return the ancestor of this input, or <code>null</code> */ ITypedElement getAncestor(); /** * Returns the left side of this input. * Returns <code>null</code> if there is no left side (deletion or addition). * * @return the left side of this input, or <code>null</code> */ ITypedElement getLeft(); /** * Returns the right side of this input. * Returns <code>null</code> if there is no right side (deletion or addition). * * @return the right side of this input, or <code>null</code> */ ITypedElement getRight(); /** * Registers the given listener for notification. * If the identical listener is already registered the method has no effect. * * @param listener the listener to register for changes of this input */ void addCompareInputChangeListener(ICompareInputChangeListener listener); /** * Unregisters the given listener. * If the identical listener is not registered the method has no effect. * * @param listener the listener to unregister */ void removeCompareInputChangeListener(ICompareInputChangeListener listener); /** * Copy one side (source) to the other side (destination) depending on the * value of <code>leftToRight</code>. This method is called from * a merge viewer if a corresponding action ("take left" or "take right") * has been pressed. * <p> * The implementation should handle the following cases: * <UL> * <LI> * if the source side is <code>null</code> the destination must be deleted, * <LI> * if the destination is <code>null</code> the destination must be created * and filled with the contents from the source, * <LI> * if both sides are non-<code>null</code> the contents of source must be copied to destination. * </UL> * In addition the implementation should send out notification to the registered * <code>ICompareInputChangeListener</code>. * * @param leftToRight if <code>true</code> the left side is copied to the right side. * If <code>false</code> the right side is copied to the left side */ void copy(boolean leftToRight); } --- NEW FILE: DiffContainer.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import java.util.ArrayList; /** * The standard implementation of a diff container element. * <p> * This class may be instantiated, or further subclassed. * </p> */ public abstract class DiffContainer extends DiffElement implements IDiffContainer { private static IDiffElement[] fgEmptyArray= new IDiffElement[0]; private ArrayList fChildren; /** * Creates a new container with the specified kind under the given parent. * * @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 DiffContainer(IDiffContainer parent, int kind) { super(parent, kind); } /** * Tries to find the child with the given name. * Returns <code>null</code> if no such child exists. * * @param name of the child to find * @return the first element with a matching name */ public IDiffElement findChild(String name) { Object[] children= getChildren(); for (int i= 0; i < children.length; i++) { IDiffElement child= (IDiffElement) children[i]; if (name.equals(child.getName())) return child; } return null; } /* (non Javadoc) * see IDiffContainer.add */ public void add(IDiffElement diff) { if (fChildren == null) fChildren= new ArrayList(); fChildren.add(diff); diff.setParent(this); } /* * Removes the given child from this container. * If the container becomes empty it is removed from its container. */ public void removeToRoot(IDiffElement child) { if (fChildren != null) { fChildren.remove(child); child.setParent(null); if (fChildren.size() == 0) { IDiffContainer p= getParent(); if (p != null) p.removeToRoot(this); } } } /** * Removes the given child (non-recursively) from this container. * * @param child to remove */ public void remove(IDiffElement child) { if (fChildren != null) { fChildren.remove(child); child.setParent(null); } } /* (non Javadoc) * see IDiffContainer.hasChildren */ public boolean hasChildren() { return fChildren != null && fChildren.size() > 0; } /* (non Javadoc) * see IDiffContainer.getChildren */ public IDiffElement[] getChildren() { if (fChildren != null) return (IDiffElement[]) fChildren.toArray(fgEmptyArray); return fgEmptyArray; } } --- NEW FILE: StructureDiffViewer.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.widgets.*; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.compare.*; import org.eclipse.compare.internal.*; /** * A diff tree viewer that can be configured with a <code>IStructureCreator</code> * to retrieve a hierarchical structure from the input object (an <code>ICompareInput</code>) * and perform a two-way or three-way compare on it. * <p> * This class may be instantiated; it is not intended to be subclassed outside * this package. * </p> * * @see IStructureCreator * @see ICompareInput */ public class StructureDiffViewer extends DiffTreeViewer { private Differencer fDifferencer; private boolean fThreeWay= false; private ITypedElement fAncestorInput; private ITypedElement fLeftInput; private ITypedElement fRightInput; private IStructureComparator fAncestorStructure; private IStructureComparator fLeftStructure; private IStructureComparator fRightStructure; private IStructureCreator fStructureCreator; private IDiffContainer fRoot; private IContentChangeListener fContentChangedListener; private CompareViewerSwitchingPane fParent; /** * Creates a new viewer for the given SWT tree control with the specified configuration. * * @param tree the tree control * @param configuration the configuration for this viewer */ public StructureDiffViewer(Tree tree, CompareConfiguration configuration) { super(tree, configuration); Composite c= tree.getParent(); if (c instanceof CompareViewerSwitchingPane) fParent= (CompareViewerSwitchingPane) c; initialize(); } /** * Creates a new viewer under the given SWT parent with the specified configuration. * * @param parent the SWT control under which to create the viewer * @param configuration the configuration for this viewer */ public StructureDiffViewer(Composite parent, CompareConfiguration configuration) { super(parent, configuration); if (parent instanceof CompareViewerSwitchingPane) fParent= (CompareViewerSwitchingPane) parent; initialize(); } private void initialize() { setAutoExpandLevel(3); fContentChangedListener= new IContentChangeListener() { public void contentChanged(IContentChangeNotifier changed) { StructureDiffViewer.this.contentChanged(changed); } }; new ICompareInputChangeListener() { public void compareInputChanged(ICompareInput input) { StructureDiffViewer.this.compareInputChanged(input); } }; } /** * Configures the <code>StructureDiffViewer</code> with a structure creator. * The structure creator is used to create a hierarchical structure * for each side of the viewer's input element of type <code>ICompareInput</code>. * * @param structureCreator the new structure creator */ public void setStructureCreator(IStructureCreator structureCreator) { if (fStructureCreator != structureCreator) { fStructureCreator= structureCreator; Control tree= getControl(); if (tree != null && !tree.isDisposed()) tree.setData(CompareUI.COMPARE_VIEWER_TITLE, getTitle()); } } /** * Returns the structure creator or <code>null</code> if no * structure creator has been set with <code>setStructureCreator</code>. * * @return the structure creator or <code>null</code> */ public IStructureCreator getStructureCreator() { return fStructureCreator; } /** * Reimplemented to get the descriptive title for this viewer from the <code>IStructureCreator</code>. * @return the viewer's name */ public String getTitle() { if (fStructureCreator != null) return fStructureCreator.getName(); return super.getTitle(); } /** * Overridden because the input of this viewer is not identical to the root of the tree. * The tree's root is a IDiffContainer that was returned from the method <code>diff</code>. * * @return the root of the diff tree produced by method <code>diff</code> */ protected Object getRoot() { return fRoot; } /* * (non-Javadoc) Method declared on StructuredViewer. * Overridden to create the comparable structures from the input object * and to feed them through the differencing engine. Note: for this viewer * the value from <code>getInput</code> is not identical to <code>getRoot</code>. */ protected void inputChanged(Object input, Object oldInput) { if (input instanceof ICompareInput) { compareInputChanged((ICompareInput) input); if (input != oldInput) initialSelection(); } } protected void initialSelection() { expandToLevel(2); } /* (non Javadoc) * Overridden to unregister all listeners. */ protected void handleDispose(DisposeEvent event) { compareInputChanged(null); fContentChangedListener= null; super.handleDispose(event); } /** * Recreates the comparable structures for the input sides. * @param input this viewer's new input */ protected void compareInputChanged(ICompareInput input) { ITypedElement t= null; boolean changed= false; if (input != null) t= input.getAncestor(); fThreeWay= (t != null); if (t != fAncestorInput) { if (fAncestorInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fAncestorInput).removeContentChangeListener(fContentChangedListener); fAncestorInput= t; if (fAncestorInput != null) { fAncestorStructure= fStructureCreator.getStructure(fAncestorInput); changed= true; } else fAncestorStructure= null; if (fAncestorInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fAncestorInput).addContentChangeListener(fContentChangedListener); } if (input != null) t= input.getLeft(); if (t != fLeftInput) { if (fLeftInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fLeftInput).removeContentChangeListener(fContentChangedListener); fLeftInput= t; if (fLeftInput != null) { fLeftStructure= fStructureCreator.getStructure(fLeftInput); changed= true; } else fLeftStructure= null; if (fLeftInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fLeftInput).addContentChangeListener(fContentChangedListener); } if (input != null) t= input.getRight(); if (t != fRightInput) { if (fRightInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fRightInput).removeContentChangeListener(fContentChangedListener); fRightInput= t; if (fRightInput != null) { fRightStructure= fStructureCreator.getStructure(fRightInput); changed= true; } else fRightStructure= null; if (fRightInput instanceof IContentChangeNotifier) ((IContentChangeNotifier)fRightInput).addContentChangeListener(fContentChangedListener); } if (changed) diff(); } /** * Calls <code>diff</code> whenever the byte contents changes. * @param changed the object that sent out the notification */ protected void contentChanged(IContentChangeNotifier changed) { if (fStructureCreator == null) return; if (changed != null) { if (changed == fAncestorInput) { fAncestorStructure= fStructureCreator.getStructure(fAncestorInput); } else if (changed == fLeftInput) { fLeftStructure= fStructureCreator.getStructure(fLeftInput); } else if (changed == fRightInput) { fRightStructure= fStructureCreator.getStructure(fRightInput); } else return; } else { fAncestorStructure= fStructureCreator.getStructure(fAncestorInput); fLeftStructure= fStructureCreator.getStructure(fLeftInput); fRightStructure= fStructureCreator.getStructure(fRightInput); } diff(); } /** * This method is called from within <code>diff()</code> before the difference * tree is being built. * Clients may override this method to perform their own pre-processing. * This default implementation does nothing. * @param ancestor the ancestor input to the differencing operation * @param left the left input to the differencing operation * @param right the right input to the differencing operation * @since 2.0 */ protected void preDiffHook(IStructureComparator ancestor, IStructureComparator left, IStructureComparator right) { // we do nothing here } /** * Runs the difference engine and refreshes the tree. */ protected void diff() { preDiffHook(fAncestorStructure, fLeftStructure, fRightStructure); String message= null; if ((fThreeWay && fAncestorStructure == null) || fLeftStructure == null || fRightStructure == null) { // could not get structure of one (or more) of the legs fRoot= null; message= CompareMessages.StructureDiffViewer_StructureError; } else { // calculate difference of the two (or three) structures if (fDifferencer == null) fDifferencer= new Differencer() { protected boolean contentsEqual(Object o1, Object o2) { return StructureDiffViewer.this.contentsEqual(o1, o2); } protected Object visit(Object data, int result, Object ancestor, Object left, Object right) { Object o= super.visit(data, result, ancestor, left, right); if (fLeftIsLocal && o instanceof DiffNode) ((DiffNode)o).swapSides(fLeftIsLocal); return o; } }; fRoot= (IDiffContainer) fDifferencer.findDifferences(fThreeWay, null, null, fAncestorStructure, fLeftStructure, fRightStructure); if (fRoot == null || fRoot.getChildren().length == 0) { message= CompareMessages.StructureDiffViewer_NoStructuralDifferences; } else { postDiffHook(fDifferencer, fRoot); } } if (fParent != null) fParent.setTitleArgument(message); refresh(getRoot()); } /** * This method is called from within <code>diff()</code> after the difference * tree has been built. * Clients may override this method to perform their own post-processing. * This default implementation does nothing. * @param differencer the differencer used to perform the differencing * @param root the non-<code>null</code> root node of the difference tree * @since 2.0 */ protected void postDiffHook(Differencer differencer, IDiffContainer root) { // we do nothing here } /* * Performs a byte compare on the given objects. * Called from the difference engine. * Returns <code>null</code> if no structure creator has been set. */ private boolean contentsEqual(Object o1, Object o2) { if (fStructureCreator != null) { boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); String s1= fStructureCreator.getContents(o1, ignoreWhiteSpace); String s2= fStructureCreator.getContents(o2, ignoreWhiteSpace); if (s1 == null || s2 == null) return false; return s1.equals(s2); } return false; } /** * Tracks property changes of the configuration object. * Clients may override to track their own property changes. * In this case they must call the inherited method. * @param event the property changed event that triggered the call to this method */ protected void propertyChange(PropertyChangeEvent event) { String key= event.getProperty(); if (key.equals(CompareConfiguration.IGNORE_WHITESPACE)) diff(); else super.propertyChange(event); } /** * Overridden to call the <code>save</code> method on the structure creator after * nodes have been copied from one side to the other side of an input object. * * @param leftToRight if <code>true</code> the left side is copied to the right side. * If <code>false</code> the right side is copied to the left side */ protected void copySelected(boolean leftToRight) { super.copySelected(leftToRight); if (fStructureCreator != null) fStructureCreator.save( leftToRight ? fRightStructure : fLeftStructure, leftToRight ? fRightInput : fLeftInput); } } --- NEW FILE: DiffElement.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import org.eclipse.swt.graphics.Image; import org.eclipse.compare.ITypedElement; /** * An abstract base implementation of the <code>IDiffElement</code> interface. * <p> * Subclasses may add behavior and state, and may override <code>getImage</code> * and <code>getType</code> to suit. * </p> */ public abstract class DiffElement implements IDiffElement { private int fKind; private IDiffContainer fParent; /** * Creates a new <code>DiffElement</code> as a child of the given parent. * If parent is not <code>null</code> the new element is added to the parent. * * @param parent the parent of this child; if not <code>null</code> this element is automatically added as a child * @param kind the kind of change */ public DiffElement(IDiffContainer parent, int kind) { fParent= parent; fKind= kind; if (parent != null) parent.add(this); } /** * The <code>DiffElement</code> implementation of this <code>ITypedInput</code> * method returns <code>null</code>. Subclasses may re-implement to provide * an image for this element. * @return <code>null</code>. */ public Image getImage() { return null; } /** * The <code>DiffElement</code> implementation of this <code>ITypedElement</code> * method returns <code>ITypedElement.UNKNOWN_TYPE</code>. Subclasses may * re-implement to provide a type for this element. * @return <code>ITypedElement.UNKNOWN_TYPE</code>. */ public String getType() { return ITypedElement.UNKNOWN_TYPE; } /** * Sets the kind of difference for this element. * * @param kind set the kind of difference this element represents * @see Differencer */ public void setKind(int kind) { fKind= kind; } /* (non Javadoc) * see IDiffElement.getKind */ public int getKind() { return fKind; } /* (non Javadoc) * see IDiffElement.getParent */ public IDiffContainer getParent() { return fParent; } /* (non Javadoc) * see IDiffElement.setParent */ public void setParent(IDiffContainer parent) { fParent= parent; } } --- NEW FILE: IStructureComparator.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; /** * Interface used to compare hierarchical structures. * It is used by the differencing engine. * <p> * Clients typically implement this interface in an adaptor class which * wrappers the objects to be compared. * * @see org.eclipse.compare.ResourceNode * @see Differencer */ public interface IStructureComparator { /** * Returns an iterator for all children of this object or <code>null</code> * if there are no children. * * @return an array with all children of this object, or an empty array if there are no children */ Object[] getChildren(); /** * Returns whether some other object is "equal to" this one * with respect to a structural comparison. For example, when comparing * Java class methods, <code>equals</code> would return <code>true</code> * if two methods have the same signature (the argument names and the * method body might differ). * * @param other the reference object with which to compare * @return <code>true</code> if this object is the same as the other argument; <code>false</code> otherwise * @see java.lang.Object#equals */ boolean equals(Object other); } --- NEW FILE: DocumentRangeNode.java --- /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; import org.eclipse.jface.text.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.compare.*; import org.eclipse.compare.internal.Utilities; import org.eclipse.compare.contentmergeviewer.IDocumentRange; /** * A document range node represents a structural element * when performing a structure compare of documents. * <code>DocumentRangeNodes</code> are created while parsing the document and represent * a semantic entity (e.g. a Java class or method). * As a consequence of the parsing a <code>DocumentRangeNode</code> maps to a range * of characters in the document. * <p> * Since a <code>DocumentRangeNode</code> implements the <code>IStructureComparator</code> * and <code>IStreamContentAccessor</code> interfaces it can be used as input to the * differencing engine. This makes it possible to perform * a structural diff on a document and have the nodes and leaves of the compare easily map * to character ranges within the document. * <p> * Subclasses may add additional state collected while parsing the document. * </p> * @see Differencer */ public class DocumentRangeNode implements IDocumentRange, IStructureComparator, IEditableContent, IEncodedStreamContentAccessor { private static final boolean POS_UPDATE= true; private static final String UTF_16= "UTF-16"; //$NON-NLS-1$ private IDocument fBaseDocument; private Position fRange; // the range in the base document private int fTypeCode; private String fID; private Position fAppendPosition; // a position where to insert a child textually private ArrayList fChildren; /** * Creates a new <code>DocumentRangeNode</code> for the given range within the specified * document. The <code>typeCode</code> is uninterpreted client data. The ID is used when comparing * two nodes with each other: i.e. the differencing engine performs a content compare * on two nodes if their IDs are equal. * * @param typeCode a type code for this node * @param id an identifier for this node * @param document document on which this node is based on * @param start start position of range within document * @param length length of range */ public DocumentRangeNode(int typeCode, String id, IDocument document, int start, int length) { fTypeCode= typeCode; fID= id; fBaseDocument= document; fBaseDocument.addPositionCategory(RANGE_CATEGORY); fRange= new Position(start, length); if (POS_UPDATE) { try { document.addPosition(RANGE_CATEGORY, fRange); } catch (BadPositionCategoryException ex) { // silently ignored } catch (BadLocationException ex) { // silently ignored } } } /* (non Javadoc) * see IDocumentRange.getDocument */ public IDocument getDocument() { return fBaseDocument; } /* (non Javadoc) * see IDocumentRange.getRange */ public Position getRange() { return fRange; } /** * Returns the type code of this node. * The type code is uninterpreted client data which can be set in the constructor. * * @return the type code of this node */ public int getTypeCode() { return fTypeCode; } /** * Returns this node's id. * It is used in <code>equals</code> and <code>hashcode</code>. * * @return the node's id */ public String getId() { return fID; } /** * Sets this node's id. * It is used in <code>equals</code> and <code>hashcode</code>. * * @param id the new id for this node */ public void setId(String id) { fID= id; } /** * Adds the given node as a child. * * @param node the node to add as a child */ public void addChild(DocumentRangeNode node) { if (fChildren == null) fChildren= new ArrayList(); fChildren.add(node); } /* (non Javadoc) * see IStructureComparator.getChildren */ public Object[] getChildren() { if (fChildren != null) return fChildren.toArray(); return new Object[0]; } /** * Sets the length of the range of this node. * * @param length the length of the range */ public void setLength(int length) { getRange().setLength(length); } /** * Sets a position within the document range that can be used to (legally) insert * text without breaking the syntax of the document. * <p> * E.g. when parsing a Java document the "append position" of a <code>DocumentRangeNode</code> * representing a Java class could be the character position just before the closing bracket. * Inserting the text of a new method there would not disturb the syntax of the class. * * @param pos the character position within the underlying document where text can be legally inserted */ public void setAppendPosition(int pos) { if (POS_UPDATE) { fBaseDocument.removePosition(fAppendPosition); try { Position p= new Position(pos); fBaseDocument.addPosition(RANGE_CATEGORY, p); fAppendPosition= p; } catch (BadPositionCategoryException ex) { // silently ignored } catch (BadLocationException ex) { // silently ignored } } else { fAppendPosition= new Position(pos); } } /** * Returns the position that has been set with <code>setAppendPosition</code>. * If <code>setAppendPosition</code> hasn't been called, the position after the last character * of this range is returned. * * @return a position where text can be legally inserted */ public Position getAppendPosition() { if (fAppendPosition == null) { if (POS_UPDATE) { try { Position p= new Position(fBaseDocument.getLength()); fBaseDocument.addPosition(RANGE_CATEGORY, p); fAppendPosition= p; } catch (BadPositionCategoryException ex) { // silently ignored } catch (BadLocationException ex) { // silently ignored } } else { fAppendPosition= new Position(fBaseDocument.getLength()); } } return fAppendPosition; } /** * Implementation based on <code>getID</code>. * @param other the object to compare this <code>DocumentRangeNode</code> against. * @return <code>true</code> if the <code>DocumentRangeNodes</code>are equal; <code>false</code> otherwise. */ public boolean equals(Object other) { if (other != null && other.getClass() == getClass()) { DocumentRangeNode tn= (DocumentRangeNode) other; return fTypeCode == tn.fTypeCode && fID.equals(tn.fID); } return super.equals(other); } /** * Implementation based on <code>getID</code>. * @return a hash code for this object. */ public int hashCode() { return fID.hashCode(); } /* * Find corresponding position */ private Position findCorrespondingPosition(DocumentRangeNode otherParent, DocumentRangeNode child) { // we try to find a predecessor of left Node which exists on the right side if (child != null && fChildren != null) { int ix= otherParent.fChildren.indexOf(child); if (ix >= 0) { for (int i= ix - 1; i >= 0; i--) { DocumentRangeNode c1= (DocumentRangeNode) otherParent.fChildren.get(i); int i2= fChildren.indexOf(c1); if (i2 >= 0) { DocumentRangeNode c= (DocumentRangeNode) fChildren.get(i2); //System.out.println(" found corresponding: " + i2 + " " + c); Position p= c.fRange; //try { Position po= new Position(p.getOffset() + p.getLength() + 1, 0); //c.fBaseDocument.addPosition(RANGE_CATEGORY, po); return po; //} catch (BadLocationException ex) { //} //break; } } for (int i= ix; i < otherParent.fChildren.size(); i++) { DocumentRangeNode c1= (DocumentRangeNode) otherParent.fChildren.get(i); int i2= fChildren.indexOf(c1); if (i2 >= 0) { DocumentRangeNode c= (DocumentRangeNode) fChildren.get(i2); //System.out.println(" found corresponding: " + i2 + " " + c); Position p= c.fRange; //try { Position po= new Position(p.getOffset(), 0); //c.fBaseDocument.addPosition(RANGE_CATEGORY, po); return po; //} catch (BadLocationException ex) { //} //break; } } } } return getAppendPosition(); } private void add(String s, DocumentRangeNode parent, DocumentRangeNode child) { Position p= findCorrespondingPosition(parent, child); if (p != null) { try { fBaseDocument.replace(p.getOffset(), p.getLength(), s); } catch (BadLocationException ex) { // silently ignored } } } /* (non Javadoc) * see IStreamContentAccessor.getContents */ public InputStream getContents() { String s; try { s= fBaseDocument.get(fRange.getOffset(), fRange.getLength()); } catch (BadLocationException ex) { s= ""; //$NON-NLS-1$ } return new ByteArrayInputStream(Utilities.getBytes(s, UTF_16)); } /* (non Javadoc) * see IEditableContent.isEditable */ public boolean isEditable() { return true; } /* (non Javadoc) * see IEditableContent.replace */ public ITypedElement replace(ITypedElement child, ITypedElement other) { DocumentRangeNode src= null; String srcContents= ""; //$NON-NLS-1$ if (other != null) { src= (DocumentRangeNode) child; if (other instanceof IStreamContentAccessor) { try { srcContents= Utilities.readString((IStreamContentAccessor)other); } catch(CoreException ex) { // NeedWork } } } if (child == null) // no destination: we have to add the contents into the parent add(srcContents, null, src); return child; } /* (non Javadoc) * see IEditableContent.setContent */ public void setContent(byte[] content) { // empty default implementation } /* (non-Javadoc) * @see org.eclipse.compare.IStreamContentAccessor#getEncoding() */ public String getCharset() { return UTF_16; } } --- NEW FILE: package.html --- <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta name="Author" content="IBM"> <meta name="GENERATOR" content="Mozilla/4.75 [en] (WinNT; U) [Netscape]"> <title>Package-level Javadoc</title> </head> <body> Provides support for finding and displaying the differences between hierarchically structured data. <h2> Package Specification</h2> The class <b>Differencer</b> is a differencing engine for hierarchically structured data. It takes two or three inputs and performs a two-way or three-way compare on them. <p> If the input elements to the differencing engine implement the <b>IStructureComparator</b> interface the engine recursively applies itself to the children of the input element. Leaf elements must implement the <b>org.eclipse.compare.IStreamContentAccessor</b> interface so that the differencer can perform a bytewise comparison on their contents. <p> One good example for this is <b>org.eclipse.compare.ResourceNode</b> which implements both interfaces (and more) for Eclipse workspace resources (org.eclipse.core.resources.IResource). <p> Another example is the <b>DocumentRangeNode</b> which can be used to compare hierarchical structures that are superimposed on a document, that is where nodes and leafs correspond to ranges in a document (<b>org.eclipse.compare.contentmergeviewer.IDocumentRange</b>). <br> Typically <b>DocumentRangeNode</b>s are created while parsing a document and they represent the semantic entities of the document (e.g. a Java class, method or field). The two subclasses <b>JavaNode</b> (in org.eclipse.jdt.internal.ui.compare) and <b>PropertyNode</b> (in org.eclipse.jdt.internal.ui.compare) are good examples for this. <p> By default the differencing engine returns the result of the compare operation as a tree of <b>DiffNode</b> objects. However, this can be changed by overriding a single method of the engine. <p> Every <b>DiffNode</b> describes the changes among the two or three inputs. <p> A tree of <b>DiffNodes</b> can be displayed in a <b>DiffTreeViewer</b>. The <b>DiffTreeViewer</b> requires that inner nodes of the tree implement the <b>IDiffContainer</b> interface and leafs the <b>IDiffElement</b> interface. <p> The typical steps to compare hierarchically structured data and to display the differences would be to: <ul> <li> map the input data into a tree of <b>IStructureComparator</b> and <b>IStreamContentAccessor</b>s,</li> <li> perform the compare operation by means of the <b>Differencer</b>, and</li> <li> feed the differencing result into the <b>DiffTreeViewer</b>.</li> </ul> The <b>StructureDiffViewer</b> is a specialized <b>DiffTreeViewer</b> that automates the three steps from above. It takes a single input object of type <b>ICompareInput</b> from which it retrieves the two or three input elements to compare. Then it uses a <b>IStructureCreator</b> to extract a tree of <b>IStructureComparator</b> and <b>IStreamContentAccessor</b> from them. These trees are then compared with the differencing engine and the result is displayed in the tree viewer. <p> </body> </html> --- NEW FILE: DiffTreeViewer.java --- /******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.compare.structuremergeviewer; import java.util.Iterator; import java.util.ResourceBundle; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.*; import org.eclipse.jface.util.*; import org.eclipse.jface.action.*; import org.eclipse.jface.viewers.*; import org.eclipse.compare.internal.*; import org.eclipse.compare.*; /** * A tree viewer that works on objects implementing * the <code>IDiffContainer</code> and <code>IDiffElement</code> interfaces. * <p> * This class may be instantiated; it is not intended to be subclassed outside * this package. * </p> * * @see IDiffContainer * @see IDiffElement */ public class DiffTreeViewer extends TreeViewer { static class DiffViewerSorter extends ViewerSorter { public boolean isSorterProperty(Object element, Object property) { return false; } public int category(Object node) { if (node instanceof DiffNode) { Object o= ((DiffNode) node).getId(); if (o instanceof DocumentRangeNode) return ((DocumentRangeNode) o).getTypeCode(); } return 0; } } class DiffViewerContentProvider implements ITreeContentProvider { public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // empty implementation } public boolean isDeleted(Object element) { return false; } public void dispose() { inputChanged(DiffTreeViewer.this, getInput(), null); } public Object getParent(Object element) { if (element instanceof IDiffElement) return ((IDiffElement)element).getParent(); return null; } public final boolean hasChildren(Object element) { if (element instanceof IDiffContainer) return ((IDiffContainer)element).hasChildren(); return false; } public final Object[] getChildren(Object element) { if (element instanceof IDiffContainer) return ((IDiffContainer)element).getChildren(); return new Object[0]; } public Object[] getElements(Object element) { return getChildren(element); } } /* * Takes care of swapping left and right if fLeftIsLocal * is true. */ class DiffViewerLabelProvider extends LabelProvider { public String getText(Object element) { if (element instanceof IDiffElement) return ((IDiffElement)element).getName(); return Utilities.getString(fBundle, "defaultLabel"); //$NON-NLS-1$ } public Image getImage(Object element) { if (element instanceof IDiffElement) { IDiffElement input= (IDiffElement) element; int kind= input.getKind(); if (fLeftIsLocal) { switch (kind & Differencer.DIRECTION_MASK) { case Differencer.LEFT: kind= (kind &~ Differencer.LEFT) | Differencer.RIGHT; break; case Differencer.RIGHT: kind= (kind &~ Differencer.RIGHT) | Differencer.LEFT; break; } } return fCompareConfiguration.getImage(input.getImage(), kind); } return null; } } static class FilterSame extends ViewerFilter { public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof IDiffElement) return (((IDiffElement)element).getKind() & Differencer.PSEUDO_CONFLICT) == 0; return true; } public boolean isFilterProperty(Object element, Object property) { return false; } } private ResourceBundle fBundle; private CompareConfiguration fCompareConfiguration; /* package */ boolean fLeftIsLocal; private IPropertyChangeListener fPropertyChangeListener; private Action fCopyLeftToRightAction; private Action fCopyRightToLeftAction; private Action fEmptyMenuAction; private Action fExpandAllAction; /** * Creates a new viewer for the given SWT tree control with the specified configuration. * * @param tree the tree control * @param configuration the configuration for this viewer */ public DiffTreeViewer(Tree tree, CompareConfiguration configuration) { super(tree); initialize(configuration); } /** * Creates a new viewer under the given SWT parent and with the specified configuration. * * @param parent the SWT control under which to create the viewer * @param configuration the configuration for this viewer */ public DiffTreeViewer(Composite parent, CompareConfiguration configuration) { super(new Tree(parent, SWT.MULTI)); initialize(configuration); } private void initialize(CompareConfiguration configuration) { Control tree= getControl(); INavigatable nav= new INavigatable() { public boolean gotoDifference(boolean next) { // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 return internalNavigate(next, true); } }; tree.setData(INavigatable.NAVIGATOR_PROPERTY, nav); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 IOpenable openable= new IOpenable() { public void openSelected() { internalOpen(); } }; tree.setData(IOpenable.OPENABLE_PROPERTY, openable); fLeftIsLocal= Utilities.getBoolean(configuration, "LEFT_IS_LOCAL", false); //$NON-NLS-1$ tree.setData(CompareUI.COMPARE_VIEWER_TITLE, getTitle()); Composite parent= tree.getParent(); fBundle= ResourceBundle.getBundle("org.eclipse.compare.structuremergeviewer.DiffTreeViewerResources"); //$NON-NLS-1$ // register for notification with the CompareConfiguration fCompareConfiguration= configuration; if (fCompareConfiguration != null) { fPropertyChangeListener= new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { DiffTreeViewer.this.propertyChange(event); } }; fCompareConfiguration.addPropertyChangeListener(fPropertyChangeListener); } setContentProvider(new DiffViewerContentProvider()); setLabelProvider(new DiffViewerLabelProvider()); addSelectionChangedListener( new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent se) { updateActions(); } } ); setSorter(new DiffViewerSorter()); ToolBarManager tbm= CompareViewerPane.getToolBarManager(parent); if (tbm != null) { tbm.removeAll(); tbm.add(new Separator("merge")); //$NON-NLS-1$ tbm.add(new Separator("modes")); //$NON-NLS-1$ tbm.add(new Separator("navigation")); //$NON-NLS-1$ createToolItems(tbm); updateActions(); tbm.update(true); } MenuManager mm= new MenuManager(); mm.setRemoveAllWhenShown(true); mm.addMenuListener( new IMenuListener() { public void menuAboutToShow(IMenuManager mm2) { fillContextMenu(mm2); if (mm2.isEmpty()) { if (fEmptyMenuAction == null) { fEmptyMenuAction= new Action(Utilities.getString(fBundle, "emptyMenuItem")) { //$NON-NLS-1$ // left empty }; fEmptyMenuAction.setEnabled(false); } mm2.add(fEmptyMenuAction); } } } ); tree.setMenu(mm.createContextMenu(tree)); } /** * Returns the viewer's name. * * @return the viewer's name */ public String getTitle() { String title= Utilities.getString(fBundle, "title", null); //$NON-NLS-1$ if (title == null) title= Utilities.getString("DiffTreeViewer.title"); //$NON-NLS-1$ return title; } /** * Returns the resource bundle. * * @return the viewer's resource bundle */ protected ResourceBundle getBundle() { return fBundle; } /** * Returns the compare configuration of this viewer. * * @return the compare configuration of this viewer */ public CompareConfiguration getCompareConfiguration() { return fCompareConfiguration; } /** * Called on the viewer disposal. * Unregisters from the compare configuration. * Clients may extend if they have to do additional cleanup. * @param event dispose event that triggered call to this method */ protected void handleDispose(DisposeEvent event) { if (fCompareConfiguration != null) { if (fPropertyChangeListener != null) fCompareConfiguration.removePropertyChangeListener(fPropertyChangeListener); fCompareConfiguration= null; } fPropertyChangeListener= null; super.handleDispose(event); } /** * Tracks property changes of the configuration object. * Clients may extend to track their own property changes. * @param event property change event that triggered call to this method */ protected void propertyChange(PropertyChangeEvent event) { // empty default implementation } protected void inputChanged(Object in, Object oldInput) { super.inputChanged(in, oldInput); if (in != oldInput) { initialSelection(); updateActions(); } } /** * This hook method is called from within <code>inputChanged</code> * after a new input has been set but before any controls are updated. * This default implementation calls <code>navigate(true)</code> * to select and expand the first leaf node. * Clients can override this method and are free to decide whether * they want to call the inherited method. * * @since 2.0 */ protected void initialSelection() { navigate(true); } /** * Overridden to avoid expanding <code>DiffNode</code>s that shouldn't expand. * @param node the node to expand * @param level non-negative level, or <code>ALL_LEVELS</code> to collapse all levels of the tree */ protected void internalExpandToLevel(Widget node, int level) { Object data= node.getData(); if (dontExpand(data)) return; super.internalExpandToLevel(node, level); } /** * This hook method is called from within <code>internalExpandToLevel</code> * to control whether a given model node should be expanded or not. * This default implementation checks whether the object is a <code>DiffNode</code> and * calls <code>dontExpand()</code> on it. * Clients can override this method and are free to decide whether * they want to call the inherited method. * * @param o the model object to be expanded * @return <code>false</code> if a node should be expanded, <code>true</code> to prevent expanding * @since 2.0 */ protected boolean dontExpand(Object o) { return o instanceof DiffNode && ((DiffNode)o).dontExpand(); } //---- merge action support /** * This factory method is called after the viewer's controls have been created. * It installs four actions in the given <code>ToolBarManager</code>. Two actions * allow for copying one side of a <code>DiffNode</code> to the other side. * Two other actions are for navigating from one node to the next (previous). * <p> * Clients can override this method and are free to decide whether they want to call * the inherited method. * * @param toolbarManager the toolbar manager for which to add the actions */ protected void createToolItems(ToolBarManager toolbarManager) { // fCopyLeftToRightAction= new Action() { // public void run() { // copySelected(true); // } // }; // Utilities.initAction(fCopyLeftToRightAction, fBundle, "action.TakeLeft."); // toolbarManager.appendToGroup("merge", fCopyLeftToRightAction); // fCopyRightToLeftAction= new Action() { // public void run() { // copySelected(false); // } // }; // Utilities.initAction(fCopyRightToLeftAction, fBundle, "action.TakeRight."); // toolbarManager.appendToGroup("merge", fCopyRightToLeftAction); // fNextAction= new Action() { // public void run() { // navigate(true); // } // }; // Utilities.initAction(fNextAction, fBundle, "action.NextDiff."); //$NON-NLS-1$ // toolbarManager.appendToGroup("navigation", fNextAction); //$NON-NLS-1$ // fPreviousAction= new Action() { // public void run() { // navigate(false); // } // }; // Utilities.initAction(fPreviousAction, fBundle, "action.PrevDiff."); //$NON-NLS-1$ // toolbarManager.appendToGroup("navigation", fPreviousAction); //$NON-NLS-1$ } /** * This method is called to add actions to the viewer's context menu. * It installs actions for expanding tree nodes, copying one side of a <code>DiffNode</code> to the other side. * Clients can override this method and are free to decide whether they want to call * the inherited method. * * @param manager the menu manager for which to add the actions */ protected void fillContextMenu(IMenuManager manager) { if (fExpandAllAction == null) { fExpandAllAction= new Action() { public void run() { expandSelection(); } }; Utilities.initAction(fExpandAllAction, fBundle, "action.ExpandAll."); //$NON-NLS-1$ } boolean enable= false; ISelection selection= getSelection(); if (selection instanceof IStructuredSelection) { Iterator elements= ((IStructuredSelection)selection).iterator(); while (elements.hasNext()) { Object element= elements.next(); if (element instanceof IDiffContainer) { if (((IDiffContainer)element).hasChildren()) { enable= true; break; } } } } fExpandAllAction.setEnabled(enable); manager.add(fExpandAllAction); if (fCopyLeftToRightAction != null) manager.add(fCopyLeftToRightAction); if (fCopyRightToLeftAction != null) manager.add(fCopyRightToLeftAction); } /** * Expands to infinity all items in the selection. * * @since 2.0 */ protected void expandSelection() { ISelection selection= getSelection(); if (selection instanceof IStructuredSelection) { Iterator elements= ((IStructuredSelection)selection).iterator(); while (elements.hasNext()) { Object next= elements.next(); expandToLevel(next, ALL_LEVELS); } } } /** * Copies one side of all <code>DiffNode</code>s in the current selection to the other side. * Called from the (internal) actions for copying the sides of a <code>DiffNode</code>. * Clients may override. * * @param leftToRight if <code>true</code> the left side is copied to the right side. * If <code>false</code> the right side is copied to the left side */ protected void copySelected(boolean leftToRight) { ISelection selection= getSelection(); if (selection instanceof IStructuredSelection) { Iterator e= ((IStructuredSelection) selection).iterator(); while (e.hasNext()) { Object element= e.next(); if (element instanceof ICompareInput) copyOne((ICompareInput) element, leftToRight); } } } /** * Called to copy one side of the given node to the other. * This default implementation delegates the call to <code>ICompareInput.copy(...)</code>. * Clients may override. * @param node the node to copy * @param leftToRight if <code>true</code> the left side is copied to the right side. * If <code>false</code> the right side is copied to the left side */ protected void copyOne(ICompareInput node, boolean leftToRight) { node.copy(leftToRight); // update node's image update(new Object[] { node }, null); } /** * Selects the next (or previous) node of the current selection. * If there is no current selection the first (last) node in the tree is selected. * Wraps around at end or beginning. * Clients may override. * * @param next if <code>true</code> the next node is selected, otherwise the previous node */ protected void navigate(boolean next) { // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 internalNavigate(next, false); } //---- private /** * Selects the next (or previous) node of the current selection. * If there is no current selection the first (last) node in the tree is selected. * Wraps around at end or beginning. * Clients may override. * * @param next if <code>true</code> the next node is selected, otherwise the previous node * @param fireOpen if <code>true</code> an open event is fired. * @return <code>true</code> if at end (or beginning) */ private boolean internalNavigate(boolean next, boolean fireOpen) { Control c= getControl(); if (!(c instanceof Tree)) return false; Tree tree= (Tree) c; TreeItem item= null; TreeItem children[]= tree.getSelection(); if (children != null && children.length > 0) item= children[0]; if (item == null) { children= tree.getItems(); if (children != null && children.length > 0) { item= children[0]; if (item != null && item.getItemCount() <= 0) { internalSetSelection(item, fireOpen); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 return false; } } } while (true) { item= findNextPrev(item, next); if (item == null) break; if (item.getItemCount() <= 0) break; } if (item != null) { internalSetSelection(item, fireOpen); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 return false; } return true; } private TreeItem findNextPrev(TreeItem item, boolean next) { if (item == null) return null; TreeItem children[]= null; if (!next) { TreeItem parent= item.getParentItem(); if (parent != null) children= parent.getItems(); else children= item.getParent().getItems(); if (children != null && children.length > 0) { // goto previous child int index= 0; for (; index < children.length; index++) if (children[index] == item) break; if (index > 0) { item= children[index-1]; while (true) { createChildren(item); int n= item.getItemCount(); if (n <= 0) break; item.setExpanded(true); item= item.getItems()[n-1]; } // previous return item; } } // go up item= parent; } else { item.setExpanded(true); createChildren(item); if (item.getItemCount() > 0) { // has children: go down children= item.getItems(); return children[0]; } while (item != null) { children= null; TreeItem parent= item.getParentItem(); if (parent != null) children= parent.getItems(); else children= item.getParent().getItems(); if (children != null && children.length > 0) { // goto next child int index= 0; for (; index < children.length; index++) if (children[index] == item) break; if (index < children.length-1) { // next return children[index+1]; } } // go up item= parent; } } return item; } private void internalSetSelection(TreeItem ti, boolean fireOpen) { if (ti != null) { Object data= ti.getData(); if (data != null) { // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 ISelection selection= new StructuredSelection(data); setSelection(selection, true); ISelection currentSelection= getSelection(); if (fireOpen && currentSelection != null && selection.equals(currentSelection)) { fireOpen(new OpenEvent(this, selection)); } } } } private final boolean isEditable(Object element, boolean left) { if (element instanceof ICompareInput) { ICompareInput diff= (ICompareInput) element; Object side= left ? diff.getLeft() : diff.getRight(); if (side == null && diff instanceof IDiffElement) { IDiffContainer container= ((IDiffElement)diff).getParent(); if (container instanceof ICompareInput) { ICompareInput parent= (ICompareInput) container; side= left ? parent.getLeft() : parent.getRight(); } } if (side instanceof IEditableContent) return ((IEditableContent) side).isEditable(); } return false; } private void updateActions() { int leftToRight= 0; int rightToLeft= 0; ISelection selection= getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection ss= (IStructuredSelection) selection; Iterator e= ss.iterator(); while (e.hasNext()) { Object element= e.next(); if (element instanceof ICompareInput) { if (isEditable(element, false)) leftToRight++; if (isEditable(element, true)) rightToLeft++; if (leftToRight > 0 && rightToLeft > 0) break; } } if (fExpandAllAction != null) fExpandAllAction.setEnabled(selection.isEmpty()); } if (fCopyLeftToRightAction != null) fCopyLeftToRightAction.setEnabled(leftToRight > 0); if (fCopyRightToLeftAction != null) fCopyRightToLeftAction.setEnabled(rightToLeft > 0); } /* * Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106 */ private void internalOpen() { ISelection selection= getSelection(); if (selection != null && !selection.isEmpty()) { fireOpen(new OpenEvent(this, selection)); } } } --- NEW FILE: DiffTreeViewerResources.properties --- ############################################################################### # Copyright (c) 2000, 2004 IBM Corporation and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://... [truncated message content] |