diff options
author | Michael Valenta | 2007-09-14 15:17:55 +0000 |
---|---|---|
committer | Michael Valenta | 2007-09-14 15:17:55 +0000 |
commit | 32ea1739b098b6fa956bf65a903cf24030bfd6bf (patch) | |
tree | c0e021314c3eaf39a873bd6225dad99093dd6ea0 | |
parent | 0a0d6b97aebeb53b69784ccd5a593cf7a0c2fcd7 (diff) | |
download | eclipse.platform.team-branch_20070914_ExtractDocumentDiff.tar.gz eclipse.platform.team-branch_20070914_ExtractDocumentDiff.tar.xz eclipse.platform.team-branch_20070914_ExtractDocumentDiff.zip |
Compare Exploratory Workbranch_20070914_ExtractDocumentDiff
4 files changed, 3296 insertions, 2600 deletions
diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java index 9cb18d1f9..659dee757 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java @@ -19,12 +19,14 @@ package org.eclipse.compare.contentmergeviewer; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.util.*; -import java.util.List; import org.eclipse.compare.*; import org.eclipse.compare.internal.*; +import org.eclipse.compare.internal.merge.DocumentMerger; +import org.eclipse.compare.internal.merge.DocumentMerger.Diff; +import org.eclipse.compare.internal.merge.DocumentMerger.IDocumentMergerInput; import org.eclipse.compare.patch.IHunk; -import org.eclipse.compare.rangedifferencer.*; +import org.eclipse.compare.rangedifferencer.RangeDifference; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.*; @@ -32,7 +34,6 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.*; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.JFaceResources; @@ -54,7 +55,6 @@ import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; import org.eclipse.ui.*; import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.texteditor.*; import com.ibm.icu.text.MessageFormat; @@ -161,13 +161,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private static final int BIRDS_EYE_VIEW_INSET= 2; /** */ private static final int RESOLVE_SIZE= 5; - /** if true copying conflicts from one side to other concatenates both sides */ - private static final boolean APPEND_CONFLICT= true; /** line width of change borders */ private static final int LW= 1; - /** Selects between smartTokenDiff and mergingTokenDiff */ - private static final boolean USE_MERGING_TOKEN_DIFF= false; // determines whether a change between left and right is considered incoming or outgoing private boolean fLeftIsLocal; @@ -202,13 +198,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private IPreferenceStore fPreferenceStore; private IPropertyChangeListener fPreferenceChangeListener; - /** All diffs for calculating scrolling position (includes line ranges without changes) */ - private ArrayList fAllDiffs; - /** Subset of above: just real differences. */ - private ArrayList fChangeDiffs; - /** The current diff */ - private Diff fCurrentDiff; - private HashMap fNewAncestorRanges= new HashMap(); private HashMap fNewLeftRanges= new HashMap(); private HashMap fNewRightRanges= new HashMap(); @@ -291,6 +280,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private TextEditorPropertyAction toggleLineNumbersAction; private IFindReplaceTarget fFindReplaceTarget; private ChangePropertyAction fIgnoreWhitespace; + private DocumentMerger fMerger; + /** The current diff */ + private Diff fCurrentDiff; private final class InternalOutlineViewerCreator extends OutlineViewerCreator implements ISelectionChangedListener { public Viewer findStructureViewer(Viewer oldViewer, @@ -340,16 +332,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff findDiff(Position p, boolean left) { - for (Iterator iterator = fAllDiffs.iterator(); iterator.hasNext();) { + for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) { Diff diff = (Diff) iterator.next(); Position diffPos; if (left) { - diffPos = diff.fLeftPos; + diffPos = diff.getPosition(LEFT_CONTRIBUTOR); } else { - diffPos = diff.fRightPos; + diffPos = diff.getPosition(RIGHT_CONTRIBUTOR); } // If the element falls within a diff, highlight that diff - if (diffPos.offset + diffPos.length >= p.offset && diff.fDirection != RangeDifference.NOCHANGE) + if (diffPos.offset + diffPos.length >= p.offset && diff.getKind() != RangeDifference.NOCHANGE) return diff; // Otherwise, highlight the first diff after the elements position if (diffPos.offset >= p.offset) @@ -1028,276 +1020,36 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } } - /* - * A Diff represents synchronized character ranges in two or three Documents. - * The MergeTextViewer uses Diffs to find differences in line and token ranges. - */ - /* package */ class Diff { - /** character range in ancestor document */ - Position fAncestorPos; - /** character range in left document */ - Position fLeftPos; - /** character range in right document */ - Position fRightPos; - /** if this is a TokenDiff fParent points to the enclosing LineDiff */ - Diff fParent; - /** if Diff has been resolved */ - boolean fResolved; - int fDirection; - boolean fIsToken= false; - /** child token diffs */ - ArrayList fDiffs; - boolean fIsWhitespace= false; + private class ChangeHighlighter implements ITextPresentationListener { - /* - * Create Diff from two ranges and an optional parent diff. - */ - Diff(Diff parent, int dir, IDocument ancestorDoc, Position aRange, int ancestorStart, int ancestorEnd, - IDocument leftDoc, Position lRange, int leftStart, int leftEnd, - IDocument rightDoc, Position rRange, int rightStart, int rightEnd) { - fParent= parent != null ? parent : this; - fDirection= dir; - - fLeftPos= createPosition(leftDoc, lRange, leftStart, leftEnd); - fRightPos= createPosition(rightDoc, rRange, rightStart, rightEnd); - if (ancestorDoc != null) - fAncestorPos= createPosition(ancestorDoc, aRange, ancestorStart, ancestorEnd); - } - - Position getPosition(char type) { - switch (type) { - case ANCESTOR_CONTRIBUTOR: - return fAncestorPos; - case LEFT_CONTRIBUTOR: - return fLeftPos; - case RIGHT_CONTRIBUTOR: - return fRightPos; - } - return null; - } - - boolean isInRange(char type, int pos) { - Position p= getPosition(type); - return (pos >= p.offset) && (pos < (p.offset+p.length)); - } - - String changeType() { - boolean leftEmpty= fLeftPos.length == 0; - boolean rightEmpty= fRightPos.length == 0; - - if (fDirection == RangeDifference.LEFT) { - if (!leftEmpty && rightEmpty) - return CompareMessages.TextMergeViewer_changeType_addition; - if (leftEmpty && !rightEmpty) - return CompareMessages.TextMergeViewer_changeType_deletion; - } else { - if (leftEmpty && !rightEmpty) - return CompareMessages.TextMergeViewer_changeType_addition; - if (!leftEmpty && rightEmpty) - return CompareMessages.TextMergeViewer_changeType_deletion; - } - return CompareMessages.TextMergeViewer_changeType_change; - } - - Image getImage() { - int code= Differencer.CHANGE; - switch (fDirection) { - case RangeDifference.RIGHT: - code+= Differencer.LEFT; - break; - case RangeDifference.LEFT: - code+= Differencer.RIGHT; - break; - case RangeDifference.ANCESTOR: - case RangeDifference.CONFLICT: - code+= Differencer.CONFLICTING; - break; - } - if (code != 0) - return getCompareConfiguration().getImage(code); - return null; - } - - Position createPosition(IDocument doc, Position range, int start, int end) { - try { - int l= end-start; - if (range != null) { - int dl= range.length; - if (l > dl) - l= dl; - } else { - int dl= doc.getLength(); - if (start+l > dl) - l= dl-start; - } - - Position p= null; - try { - p= new Position(start, l); - } catch (RuntimeException ex) { - p= new Position(0, 0); - } - - try { - doc.addPosition(DIFF_RANGE_CATEGORY, p); - } catch (BadPositionCategoryException ex) { - // silently ignored - } - return p; - } catch (BadLocationException ee) { - // silently ignored - } - return null; - } + private final MergeSourceViewer viewer; - void add(Diff d) { - if (fDiffs == null) - fDiffs= new ArrayList(); - fDiffs.add(d); - } - - boolean isDeleted() { - if (fAncestorPos != null && fAncestorPos.isDeleted()) - return true; - return fLeftPos.isDeleted() || fRightPos.isDeleted(); - } - - void setResolved(boolean r) { - fResolved= r; - if (r) - fDiffs= null; + public ChangeHighlighter(MergeSourceViewer viewer) { + this.viewer = viewer; } - boolean isResolved() { - if (!fResolved && fDiffs != null) { - Iterator e= fDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); - if (!d.isResolved()) - return false; - } - return true; - } - return fResolved; - } - -// private boolean isIncoming() { -// switch (fDirection) { -// case RangeDifference.RIGHT: -// if (fLeftIsLocal) -// return true; -// break; -// case RangeDifference.LEFT: -// if (!fLeftIsLocal) -// return true; -// break; -// } -// return false; -// } - - private boolean isIncomingOrConflicting() { - switch (fDirection) { - case RangeDifference.RIGHT: - if (fLeftIsLocal) - return true; - break; - case RangeDifference.LEFT: - if (!fLeftIsLocal) - return true; - break; - case RangeDifference.CONFLICT: - return true; - } - return false; - } - -// private boolean isUnresolvedIncoming() { -// if (fResolved) -// return false; -// return isIncoming(); -// } - - private boolean isUnresolvedIncomingOrConflicting() { - if (fResolved) - return false; - return isIncomingOrConflicting(); - } - - Position getPosition(MergeSourceViewer w) { - if (w == fLeft) - return fLeftPos; - if (w == fRight) - return fRightPos; - if (w == fAncestor) - return fAncestorPos; - return null; - } - - /* - * Returns true if given character range overlaps with this Diff. + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) */ - boolean overlaps(MergeSourceViewer w, int start, int end) { - Position h= getPosition(w); - if (h != null) { - int ds= h.getOffset(); - int de= ds + h.getLength(); - if ((start < de) && (end >= ds)) - return true; - } - return false; - } - - int getMaxDiffHeight() { - Point region= new Point(0, 0); - int h= fLeft.getLineRange(fLeftPos, region).y; - if (isThreeWay()) - h= Math.max(h, fAncestor.getLineRange(fAncestorPos, region).y); - return Math.max(h, fRight.getLineRange(fRightPos, region).y); - } - - int getAncestorHeight() { - Point region= new Point(0, 0); - return fAncestor.getLineRange(fAncestorPos, region).y; - } - - int getLeftHeight() { - Point region= new Point(0, 0); - return fLeft.getLineRange(fLeftPos, region).y; - } - - int getRightHeight() { - Point region= new Point(0, 0); - return fRight.getLineRange(fRightPos, region).y; - } - - public Diff[] getChangeDiffs(MergeSourceViewer viewer, IRegion region) { - if (fDiffs != null && intersectsRegion(viewer, region)) { - List result = new ArrayList(); - for (Iterator iterator = fDiffs.iterator(); iterator.hasNext();) { - Diff diff = (Diff) iterator.next(); - if (diff.intersectsRegion(viewer, region)) { - result.add(diff); - } - } - return (Diff[]) result.toArray(new Diff[result.size()]); + public void applyTextPresentation(TextPresentation textPresentation) { + if (!fHighlightTokenChanges) + return; + IRegion region= textPresentation.getExtent(); + Diff[] changeDiffs = fMerger.getChangeDiffs(getLeg(viewer), region); + for (int i = 0; i < changeDiffs.length; i++) { + Diff diff = changeDiffs[i]; + StyleRange range = getStyleRange(diff, region); + if (range != null) + textPresentation.mergeStyleRange(range); } - return new Diff[0]; - } - - private boolean intersectsRegion(MergeSourceViewer viewer, - IRegion region) { - Position p = getPosition(viewer); - if (p != null) - return p.overlapsWith(region.getOffset(), region.getLength()); - return false; } - public StyleRange getStyleRange(MergeSourceViewer viewer, IRegion region) { + private StyleRange getStyleRange(Diff diff, IRegion region) { //Color cText = getColor(null, getTextColor()); - Color cTextFill = getColor(null, getTextFillColor()); + Color cTextFill = getColor(null, getTextFillColor(diff)); if (cTextFill == null) return null; - Position p = getPosition(viewer); + Position p = diff.getPosition(getLeg(viewer)); int start = p.getOffset(); int length = p.getLength(); // Don't start before the region @@ -1316,9 +1068,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return new StyleRange(start, length, null, cTextFill); } - private RGB getTextFillColor() { + private RGB getTextFillColor(Diff diff) { if (isThreeWay() && !isIgnoreAncestor()) { - switch (fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return INCOMING_TEXT_FILL; @@ -1336,54 +1088,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } return OUTGOING_TEXT_FILL; } - - public boolean hasChildren() { - return fDiffs != null && !fDiffs.isEmpty(); - } - } - - private class ChangeHighlighter implements ITextPresentationListener { - - private final MergeSourceViewer viewer; - - public ChangeHighlighter(MergeSourceViewer viewer) { - this.viewer = viewer; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) - */ - public void applyTextPresentation(TextPresentation textPresentation) { - if (!fHighlightTokenChanges) - return; - IRegion region= textPresentation.getExtent(); - Diff[] changeDiffs = getChangeDiffs(region); - for (int i = 0; i < changeDiffs.length; i++) { - Diff diff = changeDiffs[i]; - StyleRange range = getStyleRange(diff, region); - if (range != null) - textPresentation.mergeStyleRange(range); - } - } - - private StyleRange getStyleRange(Diff diff, IRegion region) { - return diff.getStyleRange(viewer, region); - } - - private Diff[] getChangeDiffs(IRegion region) { - if (fChangeDiffs == null) - return new Diff[0]; - List intersectingDiffs = new ArrayList(); - for (Iterator iterator = fChangeDiffs.iterator(); iterator.hasNext();) { - Diff diff = (Diff) iterator.next(); - Diff[] changeDiffs = diff.getChangeDiffs(viewer, region); - for (int i = 0; i < changeDiffs.length; i++) { - Diff changeDiff = changeDiffs[i]; - intersectingDiffs.add(changeDiff); - } - } - return (Diff[]) intersectingDiffs.toArray(new Diff[intersectingDiffs.size()]); - } } @@ -1438,6 +1142,58 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { public TextMergeViewer(Composite parent, int style, CompareConfiguration configuration) { super(style, ResourceBundle.getBundle(BUNDLE_NAME), configuration); + fMerger = new DocumentMerger(new IDocumentMergerInput() { + public ITokenComparator createTokenComparator(String line) { + return TextMergeViewer.this.createTokenComparator(line); + } + public CompareConfiguration getCompareConfiguration() { + return TextMergeViewer.this.getCompareConfiguration(); + } + public IDocument getDocument(char contributor) { + switch (contributor) { + case LEFT_CONTRIBUTOR: + return fLeft.getDocument(); + case RIGHT_CONTRIBUTOR: + return fRight.getDocument(); + case ANCESTOR_CONTRIBUTOR: + return fAncestor.getDocument(); + } + return null; + } + public int getHunkStart() { + return TextMergeViewer.this.getHunkStart(); + } + public Position getRegion(char contributor) { + switch (contributor) { + case LEFT_CONTRIBUTOR: + return fLeft.getRegion(); + case RIGHT_CONTRIBUTOR: + return fRight.getRegion(); + case ANCESTOR_CONTRIBUTOR: + return fAncestor.getRegion(); + } + return null; + } + public boolean isHunkOnLeft() { + ITypedElement left = ((ICompareInput)getInput()).getRight(); + return left != null && Utilities.getAdapter(left, IHunk.class) != null; + } + public boolean isIgnoreAncestor() { + return TextMergeViewer.this.isIgnoreAncestor(); + } + public boolean isPatchHunk() { + return TextMergeViewer.this.isPatchHunk(); + } + + public boolean isShowPseudoConflicts() { + return fShowPseudoConflicts; + } + public boolean isThreeWay() { + return TextMergeViewer.this.isThreeWay(); + } + + }); + int inheritedStyle= parent.getStyle(); if ((inheritedStyle & SWT.LEFT_TO_RIGHT) != 0) fInheritedDirection= SWT.LEFT_TO_RIGHT; @@ -1952,7 +1708,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { public void mouseMove(MouseEvent e) { Cursor cursor= null; Diff diff= handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y); - if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) + if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) cursor= fBirdsEyeCursor; if (fLastCursor != cursor) { fBirdsEyeCanvas.setCursor(cursor); @@ -1993,7 +1749,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private void setCurrentDiff2(Diff diff, boolean reveal) { - if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) { + if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) { //fCurrentDiff= null; setCurrentDiff(diff, reveal); } @@ -2007,20 +1763,20 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return null; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int shift= tp.getVerticalScrollOffset() + (2-LW); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), region); + tp.getLineRange(diff.getPosition(leg), region); int y= (region.x * lineHeight) + shift; int h= region.y * lineHeight; @@ -2050,26 +1806,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return null; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int lshift= fLeft.getVerticalScrollOffset(); int rshift= fRight.getVerticalScrollOffset(); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - fLeft.getLineRange(diff.fLeftPos, region); + fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region); int ly= (region.x * lineHeight) + lshift; int lh= region.y * lineHeight; - fRight.getLineRange(diff.fRightPos, region); + fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region); int ry= (region.x * lineHeight) + rshift; int rh= region.y * lineHeight; @@ -2096,35 +1851,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff handlemouseInBirdsEyeView(Canvas canvas, int my) { - int yy, hh; - - Point size= canvas.getSize(); - - int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); - if (virtualHeight < getViewportHeight()) - return null; - - int y= 0; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() - : diff.getRightHeight(); - if (useChange(diff.fDirection) && !diff.fIsWhitespace) { - - yy= (y*size.y)/virtualHeight; - hh= (h*size.y)/virtualHeight; - if (hh < 3) - hh= 3; - - if (my >= yy && my < yy+hh) - return diff; - } - y+= h; - } - } - return null; + return fMerger.findDiff(getViewportHeight(), fSynchronizedScrolling, canvas.getSize(), my); } private void paintBirdsEyeView(Canvas canvas, GC gc) { @@ -2135,54 +1862,50 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Point size= canvas.getSize(); - int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); + int virtualHeight= fSynchronizedScrolling ? fMerger.getVirtualHeight() : fMerger.getRightHeight(); if (virtualHeight < getViewportHeight()) return; Display display= canvas.getDisplay(); int y= 0; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() - : diff.getRightHeight(); - - if (useChange(diff.fDirection) && !diff.fIsWhitespace) { - - yy= (y*size.y)/virtualHeight; - hh= (h*size.y)/virtualHeight; - if (hh < 3) - hh= 3; - - c= getColor(display, getFillColor(diff)); - if (c != null) { - gc.setBackground(c); - gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh); - } - c= getColor(display, getStrokeColor(diff)); - if (c != null) { - gc.setForeground(c); - r.x= BIRDS_EYE_VIEW_INSET; - r.y= yy; - r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1; - r.height= hh; - if (diff == fCurrentDiff || - (fCurrentDiff != null && diff == fCurrentDiff.fParent)) { - gc.setLineWidth(2); - r.x++; - r.y++; - r.width--; - r.height--; - } else { - gc.setLineWidth(0 /* 1 */); - } - gc.drawRectangle(r); + for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() + : diff.getRightHeight(); + + if (fMerger.useChange(diff)) { + + yy= (y*size.y)/virtualHeight; + hh= (h*size.y)/virtualHeight; + if (hh < 3) + hh= 3; + + c= getColor(display, getFillColor(diff)); + if (c != null) { + gc.setBackground(c); + gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh); + } + c= getColor(display, getStrokeColor(diff)); + if (c != null) { + gc.setForeground(c); + r.x= BIRDS_EYE_VIEW_INSET; + r.y= yy; + r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1; + r.height= hh; + if (isCurrentDiff(diff)) { + gc.setLineWidth(2); + r.x++; + r.y++; + r.width--; + r.height--; + } else { + gc.setLineWidth(0 /* 1 */); } + gc.drawRectangle(r); } - - y+= h; } + + y+= h; } } @@ -2257,7 +1980,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { setCurrentDiff(fButtonDiff, false); copy(fCurrentDiff, fCenterButton.getText().equals(COPY_LEFT_TO_RIGHT_INDICATOR), - fCurrentDiff.fDirection != RangeDifference.CONFLICT); + fCurrentDiff.getKind() != RangeDifference.CONFLICT); } } } @@ -2651,9 +2374,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Diff selectDiff= null; if (FIX_47640) { if (leftRange != null) - selectDiff= findDiff(LEFT_CONTRIBUTOR, leftRange); + selectDiff= fMerger.findDiff(LEFT_CONTRIBUTOR, leftRange); else if (rightRange != null) - selectDiff= findDiff(RIGHT_CONTRIBUTOR, rightRange); + selectDiff= fMerger.findDiff(RIGHT_CONTRIBUTOR, rightRange); } if (selectDiff != null) setCurrentDiff(selectDiff, true); @@ -2673,37 +2396,12 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return new ContributorInfo(this, element, leg); } - private Diff findDiff(char c, Position range) { - - MergeSourceViewer v; - int start= range.getOffset(); - int end= start + range.getLength(); - if (c == LEFT_CONTRIBUTOR) - v= fLeft; - else if (c == RIGHT_CONTRIBUTOR) - v= fRight; - else - return null; - - if (fChangeDiffs != null) { - Iterator iter= fChangeDiffs.iterator(); - while (iter.hasNext()) { - Diff diff= (Diff) iter.next(); - if (diff.isDeleted() || diff.fDirection == RangeDifference.NOCHANGE) - continue; - if (diff.overlaps(v, start, end)) - return diff; - } - } - return null; - } - private void updateDiffBackground(Diff diff) { if (! fHighlightRanges) return; - if (diff == null || diff.fIsToken) + if (diff == null || diff.isToken()) return; if (fShowCurrentOnly && !isCurrentDiff(diff)) @@ -2714,36 +2412,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return; if (isThreeWay()) - fAncestor.setLineBackground(diff.fAncestorPos, c); - fLeft.setLineBackground(diff.fLeftPos, c); - fRight.setLineBackground(diff.fRightPos, c); + fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c); + fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c); + fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c); } private void updateAllDiffBackgrounds(Display display) { - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { boolean threeWay= isThreeWay(); - Iterator iter= fChangeDiffs.iterator(); - while (iter.hasNext()) { - Diff diff= (Diff) iter.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); Color c= getColor(display, getFillColor(diff)); if (threeWay) - fAncestor.setLineBackground(diff.fAncestorPos, c); - fLeft.setLineBackground(diff.fLeftPos, c); - fRight.setLineBackground(diff.fRightPos, c); + fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c); + fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c); + fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c); } } } - boolean isCurrentDiff(Diff diff) { - if (diff == null) - return false; - if (diff == fCurrentDiff) - return true; - if (fCurrentDiff != null && fCurrentDiff.fParent == diff) - return true; - return false; - } - /* * Called whenever one of the documents changes. * Sets the dirty state of this viewer and updates the lines. @@ -2810,22 +2497,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { IDocumentRange dr= (IDocumentRange) other; Position p= dr.getRange(); Diff diff= findDiff(otherType, p.offset); - if (diff != null) { - switch (type) { - case ANCESTOR_CONTRIBUTOR: - if (diff.fAncestorPos != null) - return diff.fAncestorPos.offset; - break; - case LEFT_CONTRIBUTOR: - if (diff.fLeftPos != null) - return diff.fLeftPos.offset; - break; - case RIGHT_CONTRIBUTOR: - if (diff.fRightPos != null) - return diff.fRightPos.offset; - break; - } - } + return fMerger.findInsertionPoint(diff, type); } return 0; } @@ -3059,224 +2731,53 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } //---- the differencing - - private static int maxWork(IRangeComparator a, IRangeComparator l, IRangeComparator r) { - int ln= l.getRangeCount(); - int rn= r.getRangeCount(); - if (a != null) { - int an= a.getRangeCount(); - return (2 * Math.max(an, ln)) + (2 * Math.max(an, rn)); - } - return 2 * Math.max(ln, rn); - } /** * Perform a two level 2- or 3-way diff. * The first level is based on line comparison, the second level on token comparison. */ private void doDiff() { - - ArrayList newAllDiffs = new ArrayList(); - fChangeDiffs= new ArrayList(); - fCurrentDiff= null; - - IDocument aDoc= null; IDocument lDoc= fLeft.getDocument(); IDocument rDoc= fRight.getDocument(); if (lDoc == null || rDoc == null) return; - - Position aRegion= null; - Position lRegion= fLeft.getRegion(); - Position rRegion= fRight.getRegion(); - - boolean threeWay= isThreeWay(); - - if (threeWay && !isIgnoreAncestor()) { - aDoc= fAncestor.getDocument(); - aRegion= fAncestor.getRegion(); - } - - resetPositions(lDoc); - resetPositions(rDoc); - resetPositions(aDoc); - fAncestor.resetLineBackground(); fLeft.resetLineBackground(); fRight.resetLineBackground(); - boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); - - DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); - DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); - DocLineComparator sancestor= null; - boolean isRight = true; - if (aDoc != null) { - sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - if (isPatchHunk()) { - ITypedElement right = ((ICompareInput)getInput()).getRight(); - isRight = right != null && Utilities.getAdapter(right, IHunk.class) != null; - if (isRight) { - sleft= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - } else { - sright= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - } - } - } - - if (!fSubDoc && rRegion != null && lRegion != null) { - // we have to add a diff for the ignored lines - - int astart= 0; - int as= 0; - if (aRegion != null) { - astart= aRegion.getOffset(); - as= Math.max(0, astart-1); - } - int ys= Math.max(0, lRegion.getOffset()-1); - int ms= Math.max(0, rRegion.getOffset()-1); - - if (as > 0 || ys > 0 || ms > 0) { - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, 0, astart, - lDoc, lRegion, 0, lRegion.getOffset(), - rDoc, rRegion, 0, rRegion.getOffset()); - newAllDiffs.add(diff); - } - } - - final ResourceBundle bundle= getResourceBundle(); - - final Object[] result= new Object[1]; - final DocLineComparator sa= sancestor, sl= sleft, sr= sright; - IRunnableWithProgress runnable= new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { - String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); //$NON-NLS-1$ - monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); - try { - result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); - } catch (OutOfMemoryError ex) { - System.gc(); - throw new InvocationTargetException(ex); - } - if (monitor.isCanceled()) { // canceled - throw new InterruptedException(); - } - monitor.done(); - } - }; - - RangeDifference[] e= null; + fCurrentDiff= null; try { - getCompareConfiguration().getContainer().run(true, true, runnable); - e= (RangeDifference[]) result[0]; - } catch (InvocationTargetException ex) { - String title= Utilities.getString(bundle, "tooComplexError.title"); //$NON-NLS-1$ - String format= Utilities.getString(bundle, "tooComplexError.format"); //$NON-NLS-1$ + fMerger.doDiff(); + } catch (CoreException e) { + CompareUIPlugin.log(e.getStatus()); + String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$ + String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$ String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } ); MessageDialog.openError(fComposite.getShell(), title, msg); - e= null; - } catch (InterruptedException ex) { - // } - - if (e == null) { - // we create a NOCHANGE range for the whole document - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, 0, aDoc != null ? aDoc.getLength() : 0, - lDoc, lRegion, 0, lDoc.getLength(), - rDoc, rRegion, 0, rDoc.getLength()); - - newAllDiffs.add(diff); - } else { - for (int i= 0; i < e.length; i++) { - String a= null, s= null, d= null; - RangeDifference es= e[i]; - - int kind= es.kind(); - - int ancestorStart= 0; - int ancestorEnd= 0; - if (sancestor != null) { - ancestorStart= sancestor.getTokenStart(es.ancestorStart()); - ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart= sleft.getTokenStart(es.leftStart()); - int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); - - int rightStart= sright.getTokenStart(es.rightStart()); - int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); - - if (isPatchHunk()) { - if (isRight) - leftStart = leftEnd = getHunkStart(); - else - rightStart = rightEnd = getHunkStart(); - } - - Diff diff= new Diff(null, kind, - aDoc, aRegion, ancestorStart, ancestorEnd, - lDoc, lRegion, leftStart, leftEnd, - rDoc, rRegion, rightStart, rightEnd); - - newAllDiffs.add(diff); // remember all range diffs for scrolling - - if (ignoreWhiteSpace && !isPatchHunk()) { - if (sancestor != null) - a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); - s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); - d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); - - if ((a == null || a.trim().length() == 0) && s.trim().length() == 0 && d.trim().length() == 0) { - diff.fIsWhitespace= true; - continue; - } - } - if (useChange(kind)) { - fChangeDiffs.add(diff); // here we remember only the real diffs - updateDiffBackground(diff); - - // Only do the token diff for non-hunks - if (!isPatchHunk()) { - if (s == null) - s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); - if (d == null) - d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); - - if (s.length() > 0 && d.length() > 0) { - if (a == null && sancestor != null) - a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); - if (USE_MERGING_TOKEN_DIFF) - mergingTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); - else - simpleTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); - } - } - } + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + updateDiffBackground(diff); } } - - if (!fSubDoc && rRegion != null && lRegion != null) { - // we have to add a diff for the ignored lines - - int aEnd= 0; - int aLen= 0; - if (aRegion != null && aDoc != null) { - aEnd= aRegion.getOffset()+aRegion.getLength(); - aLen= aDoc.getLength(); - } - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, aEnd, aLen, - lDoc, lRegion, lRegion.getOffset()+lRegion.getLength(), lDoc.getLength(), - rDoc, rRegion, rRegion.getOffset()+rRegion.getLength(), rDoc.getLength()); - newAllDiffs.add(diff); - } - fAllDiffs = newAllDiffs; invalidateTextPresentation(); } + private Diff findDiff(char type, int pos) { + try { + return fMerger.findDiff(type, pos); + } catch (CoreException e) { + CompareUIPlugin.log(e.getStatus()); + String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$ + String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$ + String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } ); + MessageDialog.openError(fComposite.getShell(), title, msg); + return null; + } + } + private void resetPositions(IDocument doc) { if (doc == null) return; @@ -3287,314 +2788,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } doc.addPositionCategory(DIFF_RANGE_CATEGORY); } - - private Diff findDiff(char type, int pos) { - - IDocument aDoc= null; - IDocument lDoc= fLeft.getDocument(); - IDocument rDoc= fRight.getDocument(); - if (lDoc == null || rDoc == null) - return null; - - Position aRegion= null; - Position lRegion= null; - Position rRegion= null; - - boolean threeWay= isThreeWay(); - - if (threeWay && !isIgnoreAncestor()) - aDoc= fAncestor.getDocument(); - - boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); - - DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); - DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); - DocLineComparator sancestor= null; - if (aDoc != null) - sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - - final ResourceBundle bundle= getResourceBundle(); - - final Object[] result= new Object[1]; - final DocLineComparator sa= sancestor, sl= sleft, sr= sright; - IRunnableWithProgress runnable= new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { - String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); //$NON-NLS-1$ - monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); - try { - result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); - } catch (OutOfMemoryError ex) { - System.gc(); - throw new InvocationTargetException(ex); - } - if (monitor.isCanceled()) { // canceled - throw new InterruptedException(); - } - monitor.done(); - } - }; - IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); - - RangeDifference[] e= null; - try { - progressService.run(true, true, runnable); - e= (RangeDifference[]) result[0]; - } catch (InvocationTargetException ex) { - String title= Utilities.getString(bundle, "tooComplexError.title"); //$NON-NLS-1$ - String format= Utilities.getString(bundle, "tooComplexError.format"); //$NON-NLS-1$ - String msg= MessageFormat.format(format, new Object[] { Integer.toString(progressService.getLongOperationTime()/1000) } ); - MessageDialog.openError(fComposite.getShell(), title, msg); - e= null; - } catch (InterruptedException ex) { - // - } - - if (e != null) { - for (int i= 0; i < e.length; i++) { - RangeDifference es= e[i]; - - int kind= es.kind(); - - int ancestorStart= 0; - int ancestorEnd= 0; - if (sancestor != null) { - ancestorStart= sancestor.getTokenStart(es.ancestorStart()); - ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart= sleft.getTokenStart(es.leftStart()); - int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); - - int rightStart= sright.getTokenStart(es.rightStart()); - int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); - - Diff diff= new Diff(null, kind, - aDoc, aRegion, ancestorStart, ancestorEnd, - lDoc, lRegion, leftStart, leftEnd, - rDoc, rRegion, rightStart, rightEnd); - - if (diff.isInRange(type, pos)) - return diff; - } - } - - return null; - } - - /* - * Returns true if kind of change should be shown. - */ - private boolean useChange(int kind) { - if (kind == RangeDifference.NOCHANGE) - return false; - if (kind == RangeDifference.ANCESTOR) - return fShowPseudoConflicts; - return true; - } - - private int getTokenEnd(ITokenComparator tc, int start, int count) { - if (count <= 0) - return tc.getTokenStart(start); - int index= start + count - 1; - return tc.getTokenStart(index) + tc.getTokenLength(index); - } - - private static int getTokenEnd2(ITokenComparator tc, int start, int length) { - return tc.getTokenStart(start + length); - } - - /* - * Returns the content of lines in the specified range as a String. - * This includes the line separators. - * - * @param doc the document from which to extract the characters - * @param start index of first line - * @param length number of lines - * @return the contents of the specified line range as a String - */ - private String extract2(IDocument doc, ITokenComparator tc, int start, int length) { - int count= tc.getRangeCount(); - if (length > 0 && count > 0) { - -// -// int startPos= tc.getTokenStart(start); -// int endPos= startPos; -// -// if (length > 1) -// endPos= tc.getTokenStart(start + (length-1)); -// endPos+= tc.getTokenLength(start + (length-1)); -// - - int startPos= tc.getTokenStart(start); - int endPos; - - if (length == 1) { - endPos= startPos + tc.getTokenLength(start); - } else { - endPos= tc.getTokenStart(start + length); - } - - try { - return doc.get(startPos, endPos - startPos); - } catch (BadLocationException e) { - // silently ignored - } - - } - return ""; //$NON-NLS-1$ - } - - /* - * Performs a token based 3-way diff on the character range specified by the given baseDiff. - */ - private void simpleTokenDiff(final Diff baseDiff, - IDocument ancestorDoc, String a, - IDocument rightDoc, String d, - IDocument leftDoc, String s) { - - int ancestorStart= 0; - ITokenComparator sa= null; - if (ancestorDoc != null) { - ancestorStart= baseDiff.fAncestorPos.getOffset(); - sa= createTokenComparator(a); - } - - int rightStart= baseDiff.fRightPos.getOffset(); - ITokenComparator sm= createTokenComparator(d); - - int leftStart= baseDiff.fLeftPos.getOffset(); - ITokenComparator sy= createTokenComparator(s); - - RangeDifference[] e= RangeDifferencer.findRanges(sa, sy, sm); - for (int i= 0; i < e.length; i++) { - RangeDifference es= e[i]; - int kind= es.kind(); - if (kind != RangeDifference.NOCHANGE) { - - int ancestorStart2= ancestorStart; - int ancestorEnd2= ancestorStart; - if (ancestorDoc != null) { - ancestorStart2 += sa.getTokenStart(es.ancestorStart()); - ancestorEnd2 += getTokenEnd(sa, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart2= leftStart + sy.getTokenStart(es.leftStart()); - int leftEnd2= leftStart + getTokenEnd(sy, es.leftStart(), es.leftLength()); - - int rightStart2= rightStart + sm.getTokenStart(es.rightStart()); - int rightEnd2= rightStart + getTokenEnd(sm, es.rightStart(), es.rightLength()); - - Diff diff= new Diff(baseDiff, kind, - ancestorDoc, null, ancestorStart2, ancestorEnd2, - leftDoc, null, leftStart2, leftEnd2, - rightDoc, null, rightStart2, rightEnd2); - - // ensure that token diff is smaller than basediff - int leftS= baseDiff.fLeftPos.offset; - int leftE= baseDiff.fLeftPos.offset+baseDiff.fLeftPos.length; - int rightS= baseDiff.fRightPos.offset; - int rightE= baseDiff.fRightPos.offset+baseDiff.fRightPos.length; - if (leftS != leftStart2 || leftE != leftEnd2 || - rightS != rightStart2 || rightE != rightEnd2) { - diff.fIsToken= true; - // add to base Diff - baseDiff.add(diff); - } - } - } - } - - /* - * Performs a "smart" token based 3-way diff on the character range specified by the given baseDiff. - * It is "smart" because it tries to minimize the number of token diffs by merging them. - */ - private void mergingTokenDiff(Diff baseDiff, - IDocument ancestorDoc, String a, - IDocument rightDoc, String d, - IDocument leftDoc, String s) { - ITokenComparator sa= null; - int ancestorStart= 0; - if (ancestorDoc != null) { - sa= createTokenComparator(a); - ancestorStart= baseDiff.fAncestorPos.getOffset(); - } - - int rightStart= baseDiff.fRightPos.getOffset(); - ITokenComparator sm= createTokenComparator(d); - - int leftStart= baseDiff.fLeftPos.getOffset(); - ITokenComparator sy= createTokenComparator(s); - - RangeDifference[] r= RangeDifferencer.findRanges(sa, sy, sm); - for (int i= 0; i < r.length; i++) { - RangeDifference es= r[i]; - // determine range of diffs in one line - int start= i; - int leftLine= -1; - int rightLine= -1; - try { - leftLine= leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart())); - rightLine= rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart())); - } catch (BadLocationException e) { - // silently ignored - } - i++; - for (; i < r.length; i++) { - es= r[i]; - try { - if (leftLine != leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart()))) - break; - if (rightLine != rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart()))) - break; - } catch (BadLocationException e) { - // silently ignored - } - } - int end= i; - - // find first diff from left - RangeDifference first= null; - for (int ii= start; ii < end; ii++) { - es= r[ii]; - if (useChange(es.kind())) { - first= es; - break; - } - } - - // find first diff from mine - RangeDifference last= null; - for (int ii= end-1; ii >= start; ii--) { - es= r[ii]; - if (useChange(es.kind())) { - last= es; - break; - } - } - - if (first != null && last != null) { - - int ancestorStart2= 0; - int ancestorEnd2= 0; - if (ancestorDoc != null) { - ancestorStart2= ancestorStart+sa.getTokenStart(first.ancestorStart()); - ancestorEnd2= ancestorStart+getTokenEnd(sa, last.ancestorStart(), last.ancestorLength()); - } - - int leftStart2= leftStart+sy.getTokenStart(first.leftStart()); - int leftEnd2= leftStart+getTokenEnd(sy, last.leftStart(), last.leftLength()); - - int rightStart2= rightStart+sm.getTokenStart(first.rightStart()); - int rightEnd2= rightStart+getTokenEnd(sm, last.rightStart(), last.rightLength()); - Diff diff= new Diff(baseDiff, first.kind(), - ancestorDoc, null, ancestorStart2, ancestorEnd2, - leftDoc, null, leftStart2, leftEnd2, - rightDoc, null, rightStart2, rightEnd2); - diff.fIsToken= true; - baseDiff.add(diff); - } - } - } //---- update UI stuff @@ -3629,16 +2822,8 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (fCopyDiffRightToLeftItem != null) ((Action)fCopyDiffRightToLeftItem.getAction()).setEnabled(rightToLeft); - boolean enableNavigation= false; - if (fCurrentDiff == null && fChangeDiffs != null && fChangeDiffs.size() > 0) - enableNavigation= true; - else if (fChangeDiffs != null && fChangeDiffs.size() > 1) - enableNavigation= true; - else if (fCurrentDiff != null && fCurrentDiff.fDiffs != null) - enableNavigation= true; - else if (fCurrentDiff != null && fCurrentDiff.fIsToken) - enableNavigation= true; - + boolean enableNavigation= isNavigationPossible(); + if (fNextDiff != null) { IAction a= fNextDiff.getAction(); a.setEnabled(enableNavigation || hasNextElement(true)); @@ -3667,14 +2852,14 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int unresolvedIncoming= 0; int unresolvedConflicting= 0; - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator + .hasNext();) { + Diff d = (Diff) iterator.next(); if (d.isIncomingOrConflicting() /* && useChange(d.fDirection) && !d.fIsWhitespace */) { incomingOrConflicting++; - if (!d.fResolved) { - if (d.fDirection == RangeDifference.CONFLICT) { + if (!d.isResolved()) { + if (d.getKind() == RangeDifference.CONFLICT) { unresolvedConflicting++; break; // we can stop here because a conflict has the maximum priority } @@ -3709,16 +2894,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { diffDescription= CompareMessages.TextMergeViewer_diffDescription_noDiff_format; } else { - if (diff.fIsToken) // we don't show special info for token diffs - diff= diff.fParent; + if (diff.isToken()) // we don't show special info for token diffs + diff= diff.getParent(); String format= CompareMessages.TextMergeViewer_diffDescription_diff_format; diffDescription= MessageFormat.format(format, new String[] { getDiffType(diff), // 0: diff type getDiffNumber(diff), // 1: diff number - getDiffRange(fLeft, diff.fLeftPos), // 2: left start line - getDiffRange(fRight, diff.fRightPos) // 3: left end line + getDiffRange(fLeft, diff.getPosition(LEFT_CONTRIBUTOR)), // 2: left start line + getDiffRange(fRight, diff.getPosition(RIGHT_CONTRIBUTOR)) // 3: left end line } ); } @@ -3741,7 +2926,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private String getDiffType(Diff diff) { String s= ""; //$NON-NLS-1$ - switch(diff.fDirection) { + switch(diff.getKind()) { case RangeDifference.LEFT: s= CompareMessages.TextMergeViewer_direction_outgoing; break; @@ -3759,10 +2944,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private String getDiffNumber(Diff diff) { // find the diff's number int diffNumber= 0; - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff d = (Diff) iterator.next(); diffNumber++; if (d == diff) break; @@ -4036,9 +3220,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Diff firstDiff= null; if (first) - firstDiff= findNext(fRight, fChangeDiffs, -1, -1, false); + firstDiff= findNext(fRight, -1, -1, false); else - firstDiff= findPrev(fRight, fChangeDiffs, 9999999, 9999999, false); + firstDiff= findPrev(fRight, 9999999, 9999999, false); setCurrentDiff(firstDiff, true); } @@ -4189,26 +3373,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { boolean showResolveUI= showResolveUI(); - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int lshift= fLeft.getVerticalScrollOffset(); int rshift= fRight.getVerticalScrollOffset(); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - fLeft.getLineRange(diff.fLeftPos, region); + fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region); int ly= (region.x * lineHeightLeft) + lshift; int lh= region.y * lineHeightLeft; - fRight.getLineRange(diff.fRightPos, region); + fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region); int ry= (region.x * lineHeightRight) + rshift; int rh= region.y * lineHeightRight; @@ -4336,20 +3519,20 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int shift= tp.getVerticalScrollOffset() + (2-LW); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), region); + tp.getLineRange(diff.getPosition(leg), region); int y= (region.x * lineHeight) + shift; int h= region.y * lineHeight; @@ -4378,7 +3561,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return; - if (fChangeDiffs == null) + if (!fMerger.hasChanges()) return; Control canvas= (Control) event.widget; @@ -4395,17 +3578,17 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { shift+= fTopInset; Point range= new Point(0, 0); - - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), range); + tp.getLineRange(diff.getPosition(leg), range); int y= (range.x * lineHeight) + shift; int h= range.y * lineHeight; @@ -4421,10 +3604,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private RGB getFillColor(Diff diff) { - boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; + boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff; RGB selected_fill= getBackground(null); if (isThreeWay() && !isIgnoreAncestor()) { - switch (diff.fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return selected ? selected_fill : INCOMING_FILL; @@ -4444,10 +3627,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private RGB getStrokeColor(Diff diff) { - boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; + boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff; if (isThreeWay() && !isIgnoreAncestor()) { - switch (diff.fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return selected ? SELECTED_INCOMING : INCOMING; @@ -4501,12 +3684,13 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (part == null) return null; Point s = part.getSelectedRange(); + char leg = getLeg(part); for (;;) { diff = null; diff = internalGetNextDiff(down, deep, part, s); - if (diff != null && diff.fDirection == RangeDifference.ANCESTOR + if (diff != null && diff.getKind() == RangeDifference.ANCESTOR && !isAncestorVisible()) { - Position position = diff.getPosition(part); + Position position = diff.getPosition(leg); s = new Point(position.getOffset(), position.getLength()); diff= null; continue; @@ -4517,10 +3701,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff internalGetNextDiff(boolean down, boolean deep, MergeSourceViewer part, Point s) { - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { if (down) - return findNext(part, fChangeDiffs, s.x, s.x+s.y, deep); - return findPrev(part, fChangeDiffs, s.x, s.x+s.y, deep); + return findNext(part, s.x, s.x+s.y, deep); + return findPrev(part, s.x, s.x+s.y, deep); } return null; } @@ -4533,12 +3717,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff getWrappedDiff(Diff diff, boolean down) { - if (fChangeDiffs != null && fChangeDiffs.size() > 0) { - if (down) - return (Diff) fChangeDiffs.get(0); - return (Diff) fChangeDiffs.get(fChangeDiffs.size()-1); - } - return null; + return fMerger.getWrappedDiff(diff, down); } /* @@ -4558,7 +3737,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } if (diff != null) setCurrentDiff(diff, true, deep); - if (diff != null && diff.fDirection == RangeDifference.ANCESTOR + if (diff != null && diff.getKind() == RangeDifference.ANCESTOR && !isAncestorVisible()) continue; break; @@ -4662,83 +3841,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { * is returned. */ private Diff findDiff(MergeSourceViewer tp, int rangeStart, int rangeEnd) { - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - if (diff.overlaps(tp, rangeStart, rangeEnd)) - return diff; - } - } - return null; + char contributor = getLeg(tp); + return fMerger.findDiff(contributor, rangeStart, rangeEnd); } - private static Diff findNext(MergeSourceViewer tp, List v, int start, int end, boolean deep) { - for (int i= 0; i < v.size(); i++) { - Diff diff= (Diff) v.get(i); - Position p= diff.getPosition(tp); - if (p != null) { - int startOffset= p.getOffset(); - if (end < startOffset) // <= - return diff; - if (deep && diff.fDiffs != null) { - Diff d= null; - int endOffset= startOffset + p.getLength(); - if (start == startOffset && (end == endOffset || end == endOffset-1)) { - d= findNext(tp, diff.fDiffs, start-1, start-1, deep); - } else if (end < endOffset) { - d= findNext(tp, diff.fDiffs, start, end, deep); - } - if (d != null) - return d; - } - } - } - return null; + private Diff findNext(MergeSourceViewer tp, int start, int end, boolean deep) { + return fMerger.findNext(getLeg(tp), start, end, deep); } - private static Diff findPrev(MergeSourceViewer tp, List v, int start, int end, boolean deep) { - for (int i= v.size()-1; i >= 0; i--) { - Diff diff= (Diff) v.get(i); - Position p= diff.getPosition(tp); - if (p != null) { - int startOffset= p.getOffset(); - int endOffset= startOffset + p.getLength(); - if (start > endOffset) { - if (deep && diff.fDiffs != null) { - // If we are going deep, find the last change in the diff - return findPrev(tp, diff.fDiffs, end, end, deep); - } - return diff; - } - if (deep && diff.fDiffs != null) { - Diff d= null; - if (start == startOffset && end == endOffset) { - // A whole diff is selected so we'll fall through - // and go the the last change in the previous diff - } else if (start >= startOffset) { - // If we are at or before the first diff, select the - // entire diff so next and previous are symmetrical - if (isFirstDiff(tp, startOffset, diff.fDiffs)) { - return diff; - } - d= findPrev(tp, diff.fDiffs, start, end, deep); - } - if (d != null) - return d; - } - } - } - return null; - } - - private static boolean isFirstDiff(MergeSourceViewer tp, int startOffset, - ArrayList diffs) { - if (diffs.isEmpty()) - return false; - Diff diff = (Diff)diffs.get(0); - Position p= diff.getPosition(tp); - return (p.getOffset() >= startOffset); + private Diff findPrev(MergeSourceViewer tp, int start, int end, boolean deep) { + return fMerger.findPrev(getLeg(tp), start, end, deep); } /* @@ -4770,27 +3882,27 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { // before we set fCurrentDiff we change the selection // so that the paint code uses the old background colors // otherwise selection isn't drawn correctly - if (d.fIsToken || !fHighlightTokenChanges || deep || !d.hasChildren()) { + if (d.isToken() || !fHighlightTokenChanges || deep || !d.hasChildren()) { if (isThreeWay() && !isIgnoreAncestor()) - fAncestor.setSelection(d.fAncestorPos); - fLeft.setSelection(d.fLeftPos); - fRight.setSelection(d.fRightPos); + fAncestor.setSelection(d.getPosition(ANCESTOR_CONTRIBUTOR)); + fLeft.setSelection(d.getPosition(LEFT_CONTRIBUTOR)); + fRight.setSelection(d.getPosition(RIGHT_CONTRIBUTOR)); } else { if (isThreeWay() && !isIgnoreAncestor()) - fAncestor.setSelection(new Position(d.fAncestorPos.offset, 0)); - fLeft.setSelection(new Position(d.fLeftPos.offset, 0)); - fRight.setSelection(new Position(d.fRightPos.offset, 0)); + fAncestor.setSelection(new Position(d.getPosition(ANCESTOR_CONTRIBUTOR).offset, 0)); + fLeft.setSelection(new Position(d.getPosition(LEFT_CONTRIBUTOR).offset, 0)); + fRight.setSelection(new Position(d.getPosition(RIGHT_CONTRIBUTOR).offset, 0)); } // now switch diffs fCurrentDiff= d; - revealDiff(d, d.fIsToken); + revealDiff(d, d.isToken()); } else { fCurrentDiff= d; } - Diff d1= oldDiff != null ? oldDiff.fParent : null; - Diff d2= fCurrentDiff != null ? fCurrentDiff.fParent : null; + Diff d1= oldDiff != null ? oldDiff.getParent() : null; + Diff d2= fCurrentDiff != null ? fCurrentDiff.getParent() : null; if (d1 != d2) { updateDiffBackground(d1); updateDiffBackground(d2); @@ -4813,11 +3925,11 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (smart) { Point region= new Point(0, 0); // find the starting line of the diff in all text widgets - int ls= fLeft.getLineRange(d.fLeftPos, region).x; - int rs= fRight.getLineRange(d.fRightPos, region).x; + int ls= fLeft.getLineRange(d.getPosition(LEFT_CONTRIBUTOR), region).x; + int rs= fRight.getLineRange(d.getPosition(RIGHT_CONTRIBUTOR), region).x; if (isThreeWay() && !isIgnoreAncestor()) { - int as= fAncestor.getLineRange(d.fAncestorPos, region).x; + int as= fAncestor.getLineRange(d.getPosition(ANCESTOR_CONTRIBUTOR), region).x; if (as >= fAncestor.getTopIndex() && as <= fAncestor.getBottomIndex()) ancestorIsVisible= true; } @@ -4835,33 +3947,31 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { MergeSourceViewer allButThis= null; if (leftIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fLeft, fLeft.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(LEFT_CONTRIBUTOR, fLeft.getTopIndex()); allButThis= fLeft; } else if (rightIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fRight, fRight.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(RIGHT_CONTRIBUTOR, fRight.getTopIndex()); allButThis= fRight; } else if (ancestorIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fAncestor, fAncestor.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(ANCESTOR_CONTRIBUTOR, fAncestor.getTopIndex()); allButThis= fAncestor; } else { - if (fAllDiffs != null) { - int vpos= 0; - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - if (diff == d) - break; - if (fSynchronizedScrolling) { - vpos+= diff.getMaxDiffHeight(); - } else { - avpos+= diff.getAncestorHeight(); - lvpos+= diff.getLeftHeight(); - rvpos+= diff.getRightHeight(); - } + int vpos= 0; + for (Iterator iterator = fMerger.rangesIterator(); iterator + .hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff == d) + break; + if (fSynchronizedScrolling) { + vpos+= diff.getMaxDiffHeight(); + } else { + avpos+= diff.getAncestorHeight(); + lvpos+= diff.getLeftHeight(); + rvpos+= diff.getRightHeight(); } - if (fSynchronizedScrolling) - avpos= lvpos= rvpos= vpos; } + if (fSynchronizedScrolling) + avpos= lvpos= rvpos= vpos; int delta= fRight.getViewportLines()/4; avpos-= delta; if (avpos < 0) @@ -4881,11 +3991,11 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } // horizontal scrolling - if (d.fIsToken) { + if (d.isToken()) { // we only scroll horizontally for token diffs - reveal(fAncestor, d.fAncestorPos); - reveal(fLeft, d.fLeftPos); - reveal(fRight, d.fRightPos); + reveal(fAncestor, d.getPosition(ANCESTOR_CONTRIBUTOR)); + reveal(fLeft, d.getPosition(LEFT_CONTRIBUTOR)); + reveal(fRight, d.getPosition(RIGHT_CONTRIBUTOR)); } else { // in all other cases we reset the horizontal offset hscroll(fAncestor); @@ -4916,14 +4026,13 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { //-------------------------------------------------------------------------------- void copyAllUnresolved(boolean leftToRight) { - if (fChangeDiffs != null && isThreeWay() && !isIgnoreAncestor()) { + if (fMerger.hasChanges() && isThreeWay() && !isIgnoreAncestor()) { IRewriteTarget target= leftToRight ? fRight.getRewriteTarget() : fLeft.getRewriteTarget(); boolean compoundChangeStarted= false; - Iterator e= fChangeDiffs.iterator(); try { - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - switch (diff.fDirection) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + switch (diff.getKind()) { case RangeDifference.LEFT: if (leftToRight) { if (!compoundChangeStarted) { @@ -5029,66 +4138,15 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (diff != null && !diff.isResolved()) { if (!validateChange(!leftToRight)) return false; - Position fromPos= null; - Position toPos= null; - IDocument fromDoc= null; - IDocument toDoc= null; - if (leftToRight) { fRight.setEnabled(true); - fromPos= diff.fLeftPos; - toPos= diff.fRightPos; - fromDoc= fLeft.getDocument(); - toDoc= fRight.getDocument(); } else { fLeft.setEnabled(true); - fromPos= diff.fRightPos; - toPos= diff.fLeftPos; - fromDoc= fRight.getDocument(); - toDoc= fLeft.getDocument(); - } - - if (fromDoc != null) { - - int fromStart= fromPos.getOffset(); - int fromLen= fromPos.getLength(); - - int toStart= toPos.getOffset(); - int toLen= toPos.getLength(); - - try { - String s= null; - - switch (diff.fDirection) { - case RangeDifference.RIGHT: - case RangeDifference.LEFT: - s= fromDoc.get(fromStart, fromLen); - break; - case RangeDifference.ANCESTOR: - break; - case RangeDifference.CONFLICT: - if (APPEND_CONFLICT) { - s= toDoc.get(toStart, toLen); - s+= fromDoc.get(fromStart, fromLen); - } else - s= fromDoc.get(fromStart, fromLen); - break; - } - if (s != null) { - toDoc.replace(toStart, toLen, s); - toPos.setOffset(toStart); - toPos.setLength(s.length()); - } - - } catch (BadLocationException e) { - // silently ignored - } } - - diff.setResolved(true); - updateResolveStatus(); - - return true; + boolean result = fMerger.copy(diff, leftToRight); + if (result) + updateResolveStatus(); + return result; } return false; } @@ -5104,36 +4162,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } //---- scrolling - - /* - * Calculates virtual height (in lines) of views by adding the maximum of corresponding diffs. - */ - private int getVirtualHeight() { - int h= 1; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - h+= diff.getMaxDiffHeight(); - } - } - return h; - } - - /* - * Calculates height (in lines) of right view by adding the height of the right diffs. - */ - private int getRightHeight() { - int h= 1; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - h+= diff.getRightHeight(); - } - } - return h; - } /* * The height of the TextEditors in lines. @@ -5160,35 +4188,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { /* * Returns the virtual position for the given view position. */ - private int realToVirtualPosition(MergeSourceViewer w, int vpos) { - - if (! fSynchronizedScrolling || fAllDiffs == null) + private int realToVirtualPosition(char contributor, int vpos) { + if (! fSynchronizedScrolling) return vpos; - - int viewPos= 0; // real view position - int virtualPos= 0; // virtual position - Point region= new Point(0, 0); - - Iterator e= fAllDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - Position pos= diff.getPosition(w); - w.getLineRange(pos, region); - int realHeight= region.y; - int virtualHeight= diff.getMaxDiffHeight(); - if (vpos <= viewPos + realHeight) { // OK, found! - vpos-= viewPos; // make relative to this slot - // now scale position within this slot to virtual slot - if (realHeight <= 0) - vpos= 0; - else - vpos= (vpos*virtualHeight)/realHeight; - return virtualPos+vpos; - } - viewPos+= realHeight; - virtualPos+= virtualHeight; - } - return virtualPos; + return fMerger.realToVirtualPosition(contributor, vpos); } private void scrollVertical(int avpos, int lvpos, int rvpos, MergeSourceViewer allBut) { @@ -5196,7 +4199,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int s= 0; if (fSynchronizedScrolling) { - s= getVirtualHeight() - rvpos; + s= fMerger.getVirtualHeight() - rvpos; int height= fRight.getViewportLines()/4; if (s < 0) s= 0; @@ -5208,21 +4211,21 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (isThreeWay() && allBut != fAncestor) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fAncestor, avpos+s)-s; + int y= virtualToRealPosition(ANCESTOR_CONTRIBUTOR, avpos+s)-s; fAncestor.vscroll(y); } } if (allBut != fLeft) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fLeft, lvpos+s)-s; + int y= virtualToRealPosition(LEFT_CONTRIBUTOR, lvpos+s)-s; fLeft.vscroll(y); } } if (allBut != fRight) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fRight, rvpos+s)-s; + int y= virtualToRealPosition(RIGHT_CONTRIBUTOR, rvpos+s)-s; fRight.vscroll(y); } } @@ -5254,12 +4257,12 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int ix= w.getTopIndex(); int ix2= w.getDocumentRegionOffset(); - int viewPosition= realToVirtualPosition(w, ix-ix2); + int viewPosition= realToVirtualPosition(getLeg(w), ix-ix2); scrollVertical(viewPosition, viewPosition, viewPosition, w); // scroll all but the given views if (fVScrollBar != null) { - int value= Math.max(0, Math.min(viewPosition, getVirtualHeight() - getViewportHeight())); + int value= Math.max(0, Math.min(viewPosition, fMerger.getVirtualHeight() - getViewportHeight())); fVScrollBar.setSelection(value); //refreshBirdEyeView(); } @@ -5270,7 +4273,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private void updateVScrollBar() { if (Utilities.okToUse(fVScrollBar) && fSynchronizedScrolling) { - int virtualHeight= getVirtualHeight(); + int virtualHeight= fMerger.getVirtualHeight(); int viewPortHeight= getViewportHeight(); int pageIncrement= viewPortHeight-1; int thumb= (viewPortHeight > virtualHeight) ? virtualHeight : viewPortHeight; @@ -5284,34 +4287,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { /* * maps given virtual position into a real view position of this view. */ - private int virtualToRealPosition(MergeSourceViewer part, int v) { - - if (! fSynchronizedScrolling || fAllDiffs == null) + private int virtualToRealPosition(char contributor, int v) { + if (! fSynchronizedScrolling) return v; - - int virtualPos= 0; - int viewPos= 0; - Point region= new Point(0, 0); - - Iterator e= fAllDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - Position pos= diff.getPosition(part); - int viewHeight= part.getLineRange(pos, region).y; - int virtualHeight= diff.getMaxDiffHeight(); - if (v < (virtualPos + virtualHeight)) { - v-= virtualPos; // make relative to this slot - if (viewHeight <= 0) { - v= 0; - } else { - v= (int) (v * ((double)viewHeight/virtualHeight)); - } - return viewPos+v; - } - virtualPos+= virtualHeight; - viewPos+= viewHeight; - } - return viewPos; + return fMerger.virtualToRealPosition(contributor, v); } /* (non-Javadoc) @@ -5453,8 +4432,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private void resetDiffs() { // clear stuff fCurrentDiff= null; - fChangeDiffs= null; - fAllDiffs= null; + fMerger.reset(); resetPositions(fLeft.getDocument()); resetPositions(fRight.getDocument()); resetPositions(fAncestor.getDocument()); @@ -5492,4 +4470,36 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { fFindReplaceTarget= new FindReplaceTarget(); return fFindReplaceTarget; } + + /* package */ char getLeg(MergeSourceViewer w) { + if (w == fLeft) + return LEFT_CONTRIBUTOR; + if (w == fRight) + return RIGHT_CONTRIBUTOR; + if (w == fAncestor) + return ANCESTOR_CONTRIBUTOR; + return ANCESTOR_CONTRIBUTOR; + } + + public boolean isCurrentDiff(Diff diff) { + if (diff == null) + return false; + if (diff == fCurrentDiff) + return true; + if (fCurrentDiff != null && fCurrentDiff.getParent() == diff) + return true; + return false; + } + + public boolean isNavigationPossible() { + if (fCurrentDiff == null && fMerger.hasChanges()) + return true; + else if (fMerger.changesCount() > 1) + return true; + else if (fCurrentDiff != null && fCurrentDiff.hasChildren()) + return true; + else if (fCurrentDiff != null && fCurrentDiff.isToken()) + return true; + return false; + } } diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java new file mode 100644 index 000000000..64290904a --- /dev/null +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java @@ -0,0 +1,1338 @@ +/******************************************************************************* + * Copyright (c) 2007 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.internal.merge; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.contentmergeviewer.ITokenComparator; +import org.eclipse.compare.internal.*; +import org.eclipse.compare.rangedifferencer.*; +import org.eclipse.compare.structuremergeviewer.Differencer; +import org.eclipse.core.runtime.*; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.IProgressService; + +/** + * A document merger manages the differences between two documents + * for either a 2-way or 3-way comparison. + * <p> + * This class should not have any UI dependencies. + */ +public class DocumentMerger { + + private static final String DIFF_RANGE_CATEGORY = CompareUIPlugin.PLUGIN_ID + ".DIFF_RANGE_CATEGORY"; //$NON-NLS-1$ + + /** Selects between smartTokenDiff and mergingTokenDiff */ + private static final boolean USE_MERGING_TOKEN_DIFF= false; + + /** if true copying conflicts from one side to other concatenates both sides */ + private static final boolean APPEND_CONFLICT= true; + + /** All diffs for calculating scrolling position (includes line ranges without changes) */ + private ArrayList fAllDiffs; + /** Subset of above: just real differences. */ + private ArrayList fChangeDiffs; + + private final boolean fLeftIsLocal; + + private IDocumentMergerInput fInput; + + public interface IDocumentMergerInput { + + IDocument getDocument(char contributor); + + Position getRegion(char contributor); + + boolean isIgnoreAncestor(); + + boolean isThreeWay(); + + CompareConfiguration getCompareConfiguration(); + + ITokenComparator createTokenComparator(String s); + + boolean isHunkOnLeft(); + + int getHunkStart(); + + boolean isPatchHunk(); + + boolean isShowPseudoConflicts(); + + } + + public class Diff { + /** character range in ancestor document */ + Position fAncestorPos; + /** character range in left document */ + Position fLeftPos; + /** character range in right document */ + Position fRightPos; + /** if this is a TokenDiff fParent points to the enclosing LineDiff */ + Diff fParent; + /** if Diff has been resolved */ + boolean fResolved; + int fDirection; + boolean fIsToken= false; + /** child token diffs */ + ArrayList fDiffs; + boolean fIsWhitespace= false; + + /* + * Create Diff from two ranges and an optional parent diff. + */ + Diff(Diff parent, int dir, IDocument ancestorDoc, Position aRange, int ancestorStart, int ancestorEnd, + IDocument leftDoc, Position lRange, int leftStart, int leftEnd, + IDocument rightDoc, Position rRange, int rightStart, int rightEnd) { + fParent= parent != null ? parent : this; + fDirection= dir; + + fLeftPos= createPosition(leftDoc, lRange, leftStart, leftEnd); + fRightPos= createPosition(rightDoc, rRange, rightStart, rightEnd); + if (ancestorDoc != null) + fAncestorPos= createPosition(ancestorDoc, aRange, ancestorStart, ancestorEnd); + } + + public Position getPosition(char type) { + switch (type) { + case MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR: + return fAncestorPos; + case MergeViewerContentProvider.LEFT_CONTRIBUTOR: + return fLeftPos; + case MergeViewerContentProvider.RIGHT_CONTRIBUTOR: + return fRightPos; + } + return null; + } + + boolean isInRange(char type, int pos) { + Position p= getPosition(type); + return (pos >= p.offset) && (pos < (p.offset+p.length)); + } + + public String changeType() { + boolean leftEmpty= fLeftPos.length == 0; + boolean rightEmpty= fRightPos.length == 0; + + if (fDirection == RangeDifference.LEFT) { + if (!leftEmpty && rightEmpty) + return CompareMessages.TextMergeViewer_changeType_addition; + if (leftEmpty && !rightEmpty) + return CompareMessages.TextMergeViewer_changeType_deletion; + } else { + if (leftEmpty && !rightEmpty) + return CompareMessages.TextMergeViewer_changeType_addition; + if (!leftEmpty && rightEmpty) + return CompareMessages.TextMergeViewer_changeType_deletion; + } + return CompareMessages.TextMergeViewer_changeType_change; + } + + public Image getImage() { + int code= Differencer.CHANGE; + switch (fDirection) { + case RangeDifference.RIGHT: + code+= Differencer.LEFT; + break; + case RangeDifference.LEFT: + code+= Differencer.RIGHT; + break; + case RangeDifference.ANCESTOR: + case RangeDifference.CONFLICT: + code+= Differencer.CONFLICTING; + break; + } + if (code != 0) + return getCompareConfiguration().getImage(code); + return null; + } + + Position createPosition(IDocument doc, Position range, int start, int end) { + try { + int l= end-start; + if (range != null) { + int dl= range.length; + if (l > dl) + l= dl; + } else { + int dl= doc.getLength(); + if (start+l > dl) + l= dl-start; + } + + Position p= null; + try { + p= new Position(start, l); + } catch (RuntimeException ex) { + p= new Position(0, 0); + } + + try { + doc.addPosition(DIFF_RANGE_CATEGORY, p); + } catch (BadPositionCategoryException ex) { + // silently ignored + } + return p; + } catch (BadLocationException ee) { + // silently ignored + } + return null; + } + + void add(Diff d) { + if (fDiffs == null) + fDiffs= new ArrayList(); + fDiffs.add(d); + } + + public boolean isDeleted() { + if (fAncestorPos != null && fAncestorPos.isDeleted()) + return true; + return fLeftPos.isDeleted() || fRightPos.isDeleted(); + } + + void setResolved(boolean r) { + fResolved= r; + if (r) + fDiffs= null; + } + + public boolean isResolved() { + if (!fResolved && fDiffs != null) { + Iterator e= fDiffs.iterator(); + while (e.hasNext()) { + Diff d= (Diff) e.next(); + if (!d.isResolved()) + return false; + } + return true; + } + return fResolved; + } + +// private boolean isIncoming() { +// switch (fDirection) { +// case RangeDifference.RIGHT: +// if (fLeftIsLocal) +// return true; +// break; +// case RangeDifference.LEFT: +// if (!fLeftIsLocal) +// return true; +// break; +// } +// return false; +// } + + public boolean isIncomingOrConflicting() { + switch (fDirection) { + case RangeDifference.RIGHT: + if (fLeftIsLocal) + return true; + break; + case RangeDifference.LEFT: + if (!fLeftIsLocal) + return true; + break; + case RangeDifference.CONFLICT: + return true; + } + return false; + } + +// private boolean isUnresolvedIncoming() { +// if (fResolved) +// return false; +// return isIncoming(); +// } + + public boolean isUnresolvedIncomingOrConflicting() { + if (fResolved) + return false; + return isIncomingOrConflicting(); + } + + Position getPosition(int contributor) { + if (contributor == MergeViewerContentProvider.LEFT_CONTRIBUTOR) + return fLeftPos; + if (contributor == MergeViewerContentProvider.RIGHT_CONTRIBUTOR) + return fRightPos; + if (contributor == MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR) + return fAncestorPos; + return null; + } + + /* + * Returns true if given character range overlaps with this Diff. + */ + public boolean overlaps(int contributor, int start, int end) { + Position h= getPosition(contributor); + if (h != null) { + int ds= h.getOffset(); + int de= ds + h.getLength(); + if ((start < de) && (end >= ds)) + return true; + } + return false; + } + + public int getMaxDiffHeight() { + Point region= new Point(0, 0); + int h= getLineRange(getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR), fLeftPos, region).y; + if (isThreeWay()) + h= Math.max(h, getLineRange(getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR), fAncestorPos, region).y); + return Math.max(h, getLineRange(getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR), fRightPos, region).y); + } + + public int getAncestorHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR), fAncestorPos, region).y; + } + + public int getLeftHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR), fLeftPos, region).y; + } + + public int getRightHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR), fRightPos, region).y; + } + + public Diff[] getChangeDiffs(int contributor, IRegion region) { + if (fDiffs != null && intersectsRegion(contributor, region)) { + List result = new ArrayList(); + for (Iterator iterator = fDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff.intersectsRegion(contributor, region)) { + result.add(diff); + } + } + return (Diff[]) result.toArray(new Diff[result.size()]); + } + return new Diff[0]; + } + + private boolean intersectsRegion(int contributor, IRegion region) { + Position p = getPosition(contributor); + if (p != null) + return p.overlapsWith(region.getOffset(), region.getLength()); + return false; + } + + public boolean hasChildren() { + return fDiffs != null && !fDiffs.isEmpty(); + } + + public int getKind() { + return fDirection; + } + + public boolean isToken() { + return fIsToken; + } + + public Diff getParent() { + return fParent; + } + + public Iterator childIterator() { + if (fDiffs == null) + return new ArrayList().iterator(); + return fDiffs.iterator(); + } + } + + public DocumentMerger(IDocumentMergerInput input) { + this.fInput = input; + fLeftIsLocal= Utilities.getBoolean(getCompareConfiguration(), "LEFT_IS_LOCAL", false); //$NON-NLS-1$ + } + + /** + * Perform a two level 2- or 3-way diff. + * The first level is based on line comparison, the second level on token comparison. + * @throws CoreException + */ + public void doDiff() throws CoreException { + + fChangeDiffs= new ArrayList(); + IDocument lDoc = getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + IDocument rDoc = getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + + if (lDoc == null || rDoc == null) + return; + + Position lRegion= getRegion(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + Position rRegion= getRegion(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + + IDocument aDoc = null; + Position aRegion= null; + if (isThreeWay() && !isIgnoreAncestor()) { + aDoc= getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + aRegion= getRegion(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + } + + resetPositions(lDoc); + resetPositions(rDoc); + resetPositions(aDoc); + + boolean ignoreWhiteSpace= isIgnoreWhitespace(); + + DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); + DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); + DocLineComparator sancestor= null; + if (aDoc != null) { + sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + if (isPatchHunk()) { + if (isHunkOnLeft()) { + sright= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + } else { + sleft= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + } + } + } + + final Object[] result= new Object[1]; + final DocLineComparator sa= sancestor, sl= sleft, sr= sright; + IRunnableWithProgress runnable= new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { + monitor.beginTask("Computing Differences...", maxWork(sa, sl, sr)); + try { + result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); + } catch (OutOfMemoryError ex) { + System.gc(); + throw new InvocationTargetException(ex); + } + if (monitor.isCanceled()) { // canceled + throw new InterruptedException(); + } + monitor.done(); + } + }; + + RangeDifference[] e= null; + try { + getCompareConfiguration().getContainer().run(true, true, runnable); + e= (RangeDifference[]) result[0]; + } catch (InvocationTargetException ex) { + // we create a NOCHANGE range for the whole document + Diff diff= new Diff(null, RangeDifference.NOCHANGE, + aDoc, aRegion, 0, aDoc != null ? aDoc.getLength() : 0, + lDoc, lRegion, 0, lDoc.getLength(), + rDoc, rRegion, 0, rDoc.getLength()); + + fAllDiffs = new ArrayList(); + fAllDiffs.add(diff); + throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, "Too many differences found", ex.getTargetException())); + } catch (InterruptedException ex) { + // + } + + ArrayList newAllDiffs = new ArrayList(); + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + + int ancestorStart= 0; + int ancestorEnd= 0; + if (sancestor != null) { + ancestorStart= sancestor.getTokenStart(es.ancestorStart()); + ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart= sleft.getTokenStart(es.leftStart()); + int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); + + int rightStart= sright.getTokenStart(es.rightStart()); + int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); + + if (isPatchHunk()) { + if (isHunkOnLeft()) { + rightStart = rightEnd = getHunkStart(); + } else { + leftStart = leftEnd = getHunkStart(); + } + } + + Diff diff= new Diff(null, es.kind(), + aDoc, aRegion, ancestorStart, ancestorEnd, + lDoc, lRegion, leftStart, leftEnd, + rDoc, rRegion, rightStart, rightEnd); + + newAllDiffs.add(diff); // remember all range diffs for scrolling + + if (isPatchHunk()) { + if (useChange(diff)) { + recordChangeDiff(diff); + } + } else { + if (ignoreWhiteSpace || useChange(es.kind())) { + + // Extract the string for each contributor. + String a= null; + if (sancestor != null) + a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); + String s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); + String d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); + + // Indicate whether all contributors are whitespace + if (ignoreWhiteSpace + && (a == null || a.trim().length() == 0) + && s.trim().length() == 0 + && d.trim().length() == 0) { + diff.fIsWhitespace= true; + } + + // If the diff is of interest, record it and generate the token diffs + if (useChange(diff)) { + recordChangeDiff(diff); + if (s.length() > 0 && d.length() > 0) { + if (a == null && sancestor != null) + a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); + if (USE_MERGING_TOKEN_DIFF) + mergingTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); + else + simpleTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); + } + } + } + } + } + fAllDiffs = newAllDiffs; + } + + public Diff findDiff(char type, int pos) throws CoreException { + + IDocument aDoc= null; + IDocument lDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + IDocument rDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + if (lDoc == null || rDoc == null) + return null; + + Position aRegion= null; + Position lRegion= null; + Position rRegion= null; + + boolean threeWay= isThreeWay(); + + if (threeWay && !isIgnoreAncestor()) + aDoc= getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + + boolean ignoreWhiteSpace= isIgnoreWhitespace(); + + DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); + DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); + DocLineComparator sancestor= null; + if (aDoc != null) + sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + + final Object[] result= new Object[1]; + final DocLineComparator sa= sancestor, sl= sleft, sr= sright; + IRunnableWithProgress runnable= new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { + monitor.beginTask("Finding Differences...", maxWork(sa, sl, sr)); + try { + result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); + } catch (OutOfMemoryError ex) { + System.gc(); + throw new InvocationTargetException(ex); + } + if (monitor.isCanceled()) { // canceled + throw new InterruptedException(); + } + monitor.done(); + } + }; + IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); + + RangeDifference[] e= null; + try { + progressService.run(true, true, runnable); + e= (RangeDifference[]) result[0]; + } catch (InvocationTargetException ex) { + throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, "Too many differences found", ex.getTargetException())); + } catch (InterruptedException ex) { + // + } + + if (e != null) { + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + + int kind= es.kind(); + + int ancestorStart= 0; + int ancestorEnd= 0; + if (sancestor != null) { + ancestorStart= sancestor.getTokenStart(es.ancestorStart()); + ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart= sleft.getTokenStart(es.leftStart()); + int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); + + int rightStart= sright.getTokenStart(es.rightStart()); + int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); + + Diff diff= new Diff(null, kind, + aDoc, aRegion, ancestorStart, ancestorEnd, + lDoc, lRegion, leftStart, leftEnd, + rDoc, rRegion, rightStart, rightEnd); + + if (diff.isInRange(type, pos)) + return diff; + } + } + + return null; + } + + private void recordChangeDiff(Diff diff) { + fChangeDiffs.add(diff); // here we remember only the real diffs + } + + private boolean isHunkOnLeft() { + return fInput.isHunkOnLeft(); + } + + private int getHunkStart() { + return fInput.getHunkStart(); + } + + private boolean isPatchHunk() { + return fInput.isPatchHunk(); + } + + private boolean isIgnoreWhitespace() { + return Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); + } + + private IDocument getDocument(char contributor) { + return fInput.getDocument(contributor); + } + + private Position getRegion(char contributor) { + return fInput.getRegion(contributor); + } + + public boolean isIgnoreAncestor() { + return fInput.isIgnoreAncestor(); + } + + public boolean isThreeWay() { + return fInput.isThreeWay(); + } + + /** + * Return the compare configuration associated with this merger. + * @return the compare configuration associated with this merger + */ + public CompareConfiguration getCompareConfiguration() { + return fInput.getCompareConfiguration(); + } + + /* + * Returns true if kind of change should be shown. + */ + public boolean useChange(Diff diff) { + if (diff.fIsWhitespace) + return false; + int kind = diff.getKind(); + return useChange(kind); + } + + private boolean useChange(int kind) { + if (kind == RangeDifference.NOCHANGE) + return false; + if (kind == RangeDifference.ANCESTOR) + return fInput.isShowPseudoConflicts(); + return true; + } + + private int getTokenEnd(ITokenComparator tc, int start, int count) { + if (count <= 0) + return tc.getTokenStart(start); + int index= start + count - 1; + return tc.getTokenStart(index) + tc.getTokenLength(index); + } + + private static int getTokenEnd2(ITokenComparator tc, int start, int length) { + return tc.getTokenStart(start + length); + } + + /** + * Returns the content of lines in the specified range as a String. + * This includes the line separators. + * + * @param doc the document from which to extract the characters + * @param start index of first line + * @param length number of lines + * @return the contents of the specified line range as a String + */ + private String extract2(IDocument doc, ITokenComparator tc, int start, int length) { + int count= tc.getRangeCount(); + if (length > 0 && count > 0) { + +// +// int startPos= tc.getTokenStart(start); +// int endPos= startPos; +// +// if (length > 1) +// endPos= tc.getTokenStart(start + (length-1)); +// endPos+= tc.getTokenLength(start + (length-1)); +// + + int startPos= tc.getTokenStart(start); + int endPos; + + if (length == 1) { + endPos= startPos + tc.getTokenLength(start); + } else { + endPos= tc.getTokenStart(start + length); + } + + try { + return doc.get(startPos, endPos - startPos); + } catch (BadLocationException e) { + // silently ignored + } + + } + return ""; //$NON-NLS-1$ + } + + private static IRegion toRegion(Position position) { + if (position != null) + return new Region(position.getOffset(), position.getLength()); + return null; + } + + /* + * Performs a "smart" token based 3-way diff on the character range specified by the given baseDiff. + * It is "smart" because it tries to minimize the number of token diffs by merging them. + */ + private void mergingTokenDiff(Diff baseDiff, + IDocument ancestorDoc, String a, + IDocument rightDoc, String d, + IDocument leftDoc, String s) { + ITokenComparator sa= null; + int ancestorStart= 0; + if (ancestorDoc != null) { + sa= createTokenComparator(a); + ancestorStart= baseDiff.fAncestorPos.getOffset(); + } + + int rightStart= baseDiff.fRightPos.getOffset(); + ITokenComparator sm= createTokenComparator(d); + + int leftStart= baseDiff.fLeftPos.getOffset(); + ITokenComparator sy= createTokenComparator(s); + + RangeDifference[] r= RangeDifferencer.findRanges(sa, sy, sm); + for (int i= 0; i < r.length; i++) { + RangeDifference es= r[i]; + // determine range of diffs in one line + int start= i; + int leftLine= -1; + int rightLine= -1; + try { + leftLine= leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart())); + rightLine= rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart())); + } catch (BadLocationException e) { + // silently ignored + } + i++; + for (; i < r.length; i++) { + es= r[i]; + try { + if (leftLine != leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart()))) + break; + if (rightLine != rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart()))) + break; + } catch (BadLocationException e) { + // silently ignored + } + } + int end= i; + + // find first diff from left + RangeDifference first= null; + for (int ii= start; ii < end; ii++) { + es= r[ii]; + if (useChange(es.kind())) { + first= es; + break; + } + } + + // find first diff from mine + RangeDifference last= null; + for (int ii= end-1; ii >= start; ii--) { + es= r[ii]; + if (useChange(es.kind())) { + last= es; + break; + } + } + + if (first != null && last != null) { + + int ancestorStart2= 0; + int ancestorEnd2= 0; + if (ancestorDoc != null) { + ancestorStart2= ancestorStart+sa.getTokenStart(first.ancestorStart()); + ancestorEnd2= ancestorStart+getTokenEnd(sa, last.ancestorStart(), last.ancestorLength()); + } + + int leftStart2= leftStart+sy.getTokenStart(first.leftStart()); + int leftEnd2= leftStart+getTokenEnd(sy, last.leftStart(), last.leftLength()); + + int rightStart2= rightStart+sm.getTokenStart(first.rightStart()); + int rightEnd2= rightStart+getTokenEnd(sm, last.rightStart(), last.rightLength()); + Diff diff= new Diff(baseDiff, first.kind(), + ancestorDoc, null, ancestorStart2, ancestorEnd2, + leftDoc, null, leftStart2, leftEnd2, + rightDoc, null, rightStart2, rightEnd2); + diff.fIsToken= true; + baseDiff.add(diff); + } + } + } + + /* + * Performs a token based 3-way diff on the character range specified by the given baseDiff. + */ + private void simpleTokenDiff(final Diff baseDiff, + IDocument ancestorDoc, String a, + IDocument rightDoc, String d, + IDocument leftDoc, String s) { + + int ancestorStart= 0; + ITokenComparator sa= null; + if (ancestorDoc != null) { + ancestorStart= baseDiff.fAncestorPos.getOffset(); + sa= createTokenComparator(a); + } + + int rightStart= baseDiff.fRightPos.getOffset(); + ITokenComparator sm= createTokenComparator(d); + + int leftStart= baseDiff.fLeftPos.getOffset(); + ITokenComparator sy= createTokenComparator(s); + + RangeDifference[] e= RangeDifferencer.findRanges(sa, sy, sm); + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + int kind= es.kind(); + if (kind != RangeDifference.NOCHANGE) { + + int ancestorStart2= ancestorStart; + int ancestorEnd2= ancestorStart; + if (ancestorDoc != null) { + ancestorStart2 += sa.getTokenStart(es.ancestorStart()); + ancestorEnd2 += getTokenEnd(sa, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart2= leftStart + sy.getTokenStart(es.leftStart()); + int leftEnd2= leftStart + getTokenEnd(sy, es.leftStart(), es.leftLength()); + + int rightStart2= rightStart + sm.getTokenStart(es.rightStart()); + int rightEnd2= rightStart + getTokenEnd(sm, es.rightStart(), es.rightLength()); + + Diff diff= new Diff(baseDiff, kind, + ancestorDoc, null, ancestorStart2, ancestorEnd2, + leftDoc, null, leftStart2, leftEnd2, + rightDoc, null, rightStart2, rightEnd2); + + // ensure that token diff is smaller than basediff + int leftS= baseDiff.fLeftPos.offset; + int leftE= baseDiff.fLeftPos.offset+baseDiff.fLeftPos.length; + int rightS= baseDiff.fRightPos.offset; + int rightE= baseDiff.fRightPos.offset+baseDiff.fRightPos.length; + if (leftS != leftStart2 || leftE != leftEnd2 || + rightS != rightStart2 || rightE != rightEnd2) { + diff.fIsToken= true; + // add to base Diff + baseDiff.add(diff); + } + } + } + } + + private ITokenComparator createTokenComparator(String s) { + return fInput.createTokenComparator(s); + } + + private static int maxWork(IRangeComparator a, IRangeComparator l, IRangeComparator r) { + int ln= l.getRangeCount(); + int rn= r.getRangeCount(); + if (a != null) { + int an= a.getRangeCount(); + return (2 * Math.max(an, ln)) + (2 * Math.max(an, rn)); + } + return 2 * Math.max(ln, rn); + } + + private void resetPositions(IDocument doc) { + if (doc == null) + return; + try { + doc.removePositionCategory(DIFF_RANGE_CATEGORY); + } catch (BadPositionCategoryException e) { + // Ignore + } + doc.addPositionCategory(DIFF_RANGE_CATEGORY); + } + + /* + * Returns the start line and the number of lines which correspond to the given position. + * Starting line number is 0 based. + */ + protected Point getLineRange(IDocument doc, Position p, Point region) { + + if (p == null || doc == null) { + region.x= 0; + region.y= 0; + return region; + } + + int start= p.getOffset(); + int length= p.getLength(); + + int startLine= 0; + try { + startLine= doc.getLineOfOffset(start); + } catch (BadLocationException e) { + // silently ignored + } + + int lineCount= 0; + + if (length == 0) { +// // if range length is 0 and if range starts a new line +// try { +// if (start == doc.getLineStartOffset(startLine)) { +// lines--; +// } +// } catch (BadLocationException e) { +// lines--; +// } + + } else { + int endLine= 0; + try { + endLine= doc.getLineOfOffset(start + length - 1); // why -1? + } catch (BadLocationException e) { + // silently ignored + } + lineCount= endLine-startLine+1; + } + + region.x= startLine; + region.y= lineCount; + return region; + } + + public Diff findDiff(Position p, boolean left) { + for (Iterator iterator = fAllDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + Position diffPos; + if (left) { + diffPos = diff.fLeftPos; + } else { + diffPos = diff.fRightPos; + } + // If the element falls within a diff, highlight that diff + if (diffPos.offset + diffPos.length >= p.offset && diff.fDirection != RangeDifference.NOCHANGE) + return diff; + // Otherwise, highlight the first diff after the elements position + if (diffPos.offset >= p.offset) + return diff; + } + return null; + } + + public void reset() { + fChangeDiffs= null; + fAllDiffs= null; + } + + /** + * Returns the virtual position for the given view position. + * @param contributor + * @param vpos + * @return the virtual position for the given view position + */ + public int realToVirtualPosition(char contributor, int vpos) { + + if (fAllDiffs == null) + return vpos; + + int viewPos= 0; // real view position + int virtualPos= 0; // virtual position + Point region= new Point(0, 0); + + Iterator e= fAllDiffs.iterator(); + while (e.hasNext()) { + Diff diff= (Diff) e.next(); + Position pos= diff.getPosition(contributor); + getLineRange(getDocument(contributor),pos, region); + int realHeight= region.y; + int virtualHeight= diff.getMaxDiffHeight(); + if (vpos <= viewPos + realHeight) { // OK, found! + vpos-= viewPos; // make relative to this slot + // now scale position within this slot to virtual slot + if (realHeight <= 0) + vpos= 0; + else + vpos= (vpos*virtualHeight)/realHeight; + return virtualPos+vpos; + } + viewPos+= realHeight; + virtualPos+= virtualHeight; + } + return virtualPos; + } + + /** + * maps given virtual position into a real view position of this view. + * @param contributor + * @param v + * @return the real view position + */ + public int virtualToRealPosition(char contributor, int v) { + + if (fAllDiffs == null) + return v; + + int virtualPos= 0; + int viewPos= 0; + Point region= new Point(0, 0); + + Iterator e= fAllDiffs.iterator(); + while (e.hasNext()) { + Diff diff= (Diff) e.next(); + Position pos= diff.getPosition(contributor); + int viewHeight= getLineRange(getDocument(contributor), pos, region).y; + int virtualHeight= diff.getMaxDiffHeight(); + if (v < (virtualPos + virtualHeight)) { + v-= virtualPos; // make relative to this slot + if (viewHeight <= 0) { + v= 0; + } else { + v= (int) (v * ((double)viewHeight/virtualHeight)); + } + return viewPos+v; + } + virtualPos+= virtualHeight; + viewPos+= viewHeight; + } + return viewPos; + } + + /* + * Calculates virtual height (in lines) of views by adding the maximum of corresponding diffs. + */ + public int getVirtualHeight() { + int h= 1; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + h+= diff.getMaxDiffHeight(); + } + } + return h; + } + + /* + * Calculates height (in lines) of right view by adding the height of the right diffs. + */ + public int getRightHeight() { + int h= 1; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + h+= diff.getRightHeight(); + } + } + return h; + } + + public int findInsertionPoint(Diff diff, char type) { + if (diff != null) { + switch (type) { + case MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR: + if (diff.fAncestorPos != null) + return diff.fAncestorPos.offset; + break; + case MergeViewerContentProvider.LEFT_CONTRIBUTOR: + if (diff.fLeftPos != null) + return diff.fLeftPos.offset; + break; + case MergeViewerContentProvider.RIGHT_CONTRIBUTOR: + if (diff.fRightPos != null) + return diff.fRightPos.offset; + break; + } + } + return 0; + } + + public Diff[] getChangeDiffs(char contributor, IRegion region) { + if (fChangeDiffs == null) + return new Diff[0]; + List intersectingDiffs = new ArrayList(); + for (Iterator iterator = fChangeDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + Diff[] changeDiffs = diff.getChangeDiffs(contributor, region); + for (int i = 0; i < changeDiffs.length; i++) { + Diff changeDiff = changeDiffs[i]; + intersectingDiffs.add(changeDiff); + } + } + return (Diff[]) intersectingDiffs.toArray(new Diff[intersectingDiffs.size()]); + } + + public Diff findDiff(int viewportHeight, boolean synchronizedScrolling, Point size, int my) { + int virtualHeight= synchronizedScrolling ? getVirtualHeight() : getRightHeight(); + if (virtualHeight < viewportHeight) + return null; + + int yy, hh; + int y= 0; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + int h= synchronizedScrolling ? diff.getMaxDiffHeight() + : diff.getRightHeight(); + if (useChange(diff.getKind()) && !diff.fIsWhitespace) { + + yy= (y*size.y)/virtualHeight; + hh= (h*size.y)/virtualHeight; + if (hh < 3) + hh= 3; + + if (my >= yy && my < yy+hh) + return diff; + } + y+= h; + } + } + return null; + } + + public boolean hasChanges() { + return fChangeDiffs != null && !fChangeDiffs.isEmpty(); + } + + public Iterator changesIterator() { + if (fChangeDiffs == null) + return new ArrayList().iterator(); + return fChangeDiffs.iterator(); + } + + public Iterator rangesIterator() { + if (fAllDiffs == null) + return new ArrayList().iterator(); + return fAllDiffs.iterator(); + } + + public boolean isFirstChildDiff(char contributor, int startOffset, + Diff diff) { + if (!diff.hasChildren()) + return false; + Diff d = (Diff)diff.fDiffs.get(0); + Position p= d.getPosition(contributor); + return (p.getOffset() >= startOffset); + } + + public Diff getWrappedDiff(Diff diff, boolean down) { + if (fChangeDiffs != null && fChangeDiffs.size() > 0) { + if (down) + return (Diff) fChangeDiffs.get(0); + return (Diff) fChangeDiffs.get(fChangeDiffs.size()-1); + } + return null; + } + + /* + * Copy the contents of the given diff from one side to the other but + * doesn't reveal anything. + * Returns true if copy was successful. + */ + public boolean copy(Diff diff, boolean leftToRight) { + + if (diff != null && !diff.isResolved()) { + Position fromPos= null; + Position toPos= null; + IDocument fromDoc= null; + IDocument toDoc= null; + + if (leftToRight) { + fromPos= diff.getPosition(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + toPos= diff.getPosition(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + fromDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + toDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + } else { + fromPos= diff.getPosition(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + toPos= diff.getPosition(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + fromDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + toDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + } + + if (fromDoc != null) { + + int fromStart= fromPos.getOffset(); + int fromLen= fromPos.getLength(); + + int toStart= toPos.getOffset(); + int toLen= toPos.getLength(); + + try { + String s= null; + + switch (diff.getKind()) { + case RangeDifference.RIGHT: + case RangeDifference.LEFT: + s= fromDoc.get(fromStart, fromLen); + break; + case RangeDifference.ANCESTOR: + break; + case RangeDifference.CONFLICT: + if (APPEND_CONFLICT) { + s= toDoc.get(toStart, toLen); + s+= fromDoc.get(fromStart, fromLen); + } else + s= fromDoc.get(fromStart, fromLen); + break; + } + if (s != null) { + toDoc.replace(toStart, toLen, s); + toPos.setOffset(toStart); + toPos.setLength(s.length()); + } + + } catch (BadLocationException e) { + // silently ignored + } + } + + diff.setResolved(true); + return true; + } + return false; + } + + public int changesCount() { + if (fChangeDiffs == null) + return 0; + return fChangeDiffs.size(); + } + + public Diff findDiff(char contributor, int rangeStart, int rangeEnd) { + if (hasChanges()) { + for (Iterator iterator = changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff.isDeleted() || diff.getKind() == RangeDifference.NOCHANGE) + continue; + if (diff.overlaps(contributor, rangeStart, rangeEnd)) + return diff; + } + } + return null; + } + + public Diff findDiff(char contributor, Position range) { + int start= range.getOffset(); + int end= start + range.getLength(); + return findDiff(contributor, start, end); + } + + public Diff findNext(char contributor, int start, int end, boolean deep) { + return findNext(contributor, fChangeDiffs, start, end, deep); + } + + private Diff findNext(char contributor, List v, int start, int end, boolean deep) { + if (v == null) + return null; + for (int i= 0; i < v.size(); i++) { + Diff diff= (Diff) v.get(i); + Position p= diff.getPosition(contributor); + if (p != null) { + int startOffset= p.getOffset(); + if (end < startOffset) // <= + return diff; + if (deep && diff.hasChildren()) { + Diff d= null; + int endOffset= startOffset + p.getLength(); + if (start == startOffset && (end == endOffset || end == endOffset-1)) { + d= findNext(contributor, diff.fDiffs, start-1, start-1, deep); + } else if (end < endOffset) { + d= findNext(contributor, diff.fDiffs, start, end, deep); + } + if (d != null) + return d; + } + } + } + return null; + } + + public Diff findPrev(char contributor, int start, int end, boolean deep) { + return findPrev(contributor, fChangeDiffs, start, end, deep); + } + + private Diff findPrev(char contributor, List v, int start, int end, boolean deep) { + if (v == null) + return null; + for (int i= v.size()-1; i >= 0; i--) { + Diff diff= (Diff) v.get(i); + Position p= diff.getPosition(contributor); + if (p != null) { + int startOffset= p.getOffset(); + int endOffset= startOffset + p.getLength(); + if (start > endOffset) { + if (deep && diff.hasChildren()) { + // If we are going deep, find the last change in the diff + return findPrev(contributor, diff.fDiffs, end, end, deep); + } + return diff; + } + if (deep && diff.hasChildren()) { + Diff d= null; + if (start == startOffset && end == endOffset) { + // A whole diff is selected so we'll fall through + // and go the the last change in the previous diff + } else if (start >= startOffset) { + // If we are at or before the first diff, select the + // entire diff so next and previous are symmetrical + if (isFirstChildDiff(contributor, startOffset, diff)) { + return diff; + } + d= findPrev(contributor, diff.fDiffs, start, end, deep); + } + if (d != null) + return d; + } + } + } + return null; + } + +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java index 9cb18d1f9..659dee757 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java @@ -19,12 +19,14 @@ package org.eclipse.compare.contentmergeviewer; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.util.*; -import java.util.List; import org.eclipse.compare.*; import org.eclipse.compare.internal.*; +import org.eclipse.compare.internal.merge.DocumentMerger; +import org.eclipse.compare.internal.merge.DocumentMerger.Diff; +import org.eclipse.compare.internal.merge.DocumentMerger.IDocumentMergerInput; import org.eclipse.compare.patch.IHunk; -import org.eclipse.compare.rangedifferencer.*; +import org.eclipse.compare.rangedifferencer.RangeDifference; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.*; @@ -32,7 +34,6 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.*; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.JFaceResources; @@ -54,7 +55,6 @@ import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; import org.eclipse.ui.*; import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.texteditor.*; import com.ibm.icu.text.MessageFormat; @@ -161,13 +161,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private static final int BIRDS_EYE_VIEW_INSET= 2; /** */ private static final int RESOLVE_SIZE= 5; - /** if true copying conflicts from one side to other concatenates both sides */ - private static final boolean APPEND_CONFLICT= true; /** line width of change borders */ private static final int LW= 1; - /** Selects between smartTokenDiff and mergingTokenDiff */ - private static final boolean USE_MERGING_TOKEN_DIFF= false; // determines whether a change between left and right is considered incoming or outgoing private boolean fLeftIsLocal; @@ -202,13 +198,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private IPreferenceStore fPreferenceStore; private IPropertyChangeListener fPreferenceChangeListener; - /** All diffs for calculating scrolling position (includes line ranges without changes) */ - private ArrayList fAllDiffs; - /** Subset of above: just real differences. */ - private ArrayList fChangeDiffs; - /** The current diff */ - private Diff fCurrentDiff; - private HashMap fNewAncestorRanges= new HashMap(); private HashMap fNewLeftRanges= new HashMap(); private HashMap fNewRightRanges= new HashMap(); @@ -291,6 +280,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private TextEditorPropertyAction toggleLineNumbersAction; private IFindReplaceTarget fFindReplaceTarget; private ChangePropertyAction fIgnoreWhitespace; + private DocumentMerger fMerger; + /** The current diff */ + private Diff fCurrentDiff; private final class InternalOutlineViewerCreator extends OutlineViewerCreator implements ISelectionChangedListener { public Viewer findStructureViewer(Viewer oldViewer, @@ -340,16 +332,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff findDiff(Position p, boolean left) { - for (Iterator iterator = fAllDiffs.iterator(); iterator.hasNext();) { + for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) { Diff diff = (Diff) iterator.next(); Position diffPos; if (left) { - diffPos = diff.fLeftPos; + diffPos = diff.getPosition(LEFT_CONTRIBUTOR); } else { - diffPos = diff.fRightPos; + diffPos = diff.getPosition(RIGHT_CONTRIBUTOR); } // If the element falls within a diff, highlight that diff - if (diffPos.offset + diffPos.length >= p.offset && diff.fDirection != RangeDifference.NOCHANGE) + if (diffPos.offset + diffPos.length >= p.offset && diff.getKind() != RangeDifference.NOCHANGE) return diff; // Otherwise, highlight the first diff after the elements position if (diffPos.offset >= p.offset) @@ -1028,276 +1020,36 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } } - /* - * A Diff represents synchronized character ranges in two or three Documents. - * The MergeTextViewer uses Diffs to find differences in line and token ranges. - */ - /* package */ class Diff { - /** character range in ancestor document */ - Position fAncestorPos; - /** character range in left document */ - Position fLeftPos; - /** character range in right document */ - Position fRightPos; - /** if this is a TokenDiff fParent points to the enclosing LineDiff */ - Diff fParent; - /** if Diff has been resolved */ - boolean fResolved; - int fDirection; - boolean fIsToken= false; - /** child token diffs */ - ArrayList fDiffs; - boolean fIsWhitespace= false; + private class ChangeHighlighter implements ITextPresentationListener { - /* - * Create Diff from two ranges and an optional parent diff. - */ - Diff(Diff parent, int dir, IDocument ancestorDoc, Position aRange, int ancestorStart, int ancestorEnd, - IDocument leftDoc, Position lRange, int leftStart, int leftEnd, - IDocument rightDoc, Position rRange, int rightStart, int rightEnd) { - fParent= parent != null ? parent : this; - fDirection= dir; - - fLeftPos= createPosition(leftDoc, lRange, leftStart, leftEnd); - fRightPos= createPosition(rightDoc, rRange, rightStart, rightEnd); - if (ancestorDoc != null) - fAncestorPos= createPosition(ancestorDoc, aRange, ancestorStart, ancestorEnd); - } - - Position getPosition(char type) { - switch (type) { - case ANCESTOR_CONTRIBUTOR: - return fAncestorPos; - case LEFT_CONTRIBUTOR: - return fLeftPos; - case RIGHT_CONTRIBUTOR: - return fRightPos; - } - return null; - } - - boolean isInRange(char type, int pos) { - Position p= getPosition(type); - return (pos >= p.offset) && (pos < (p.offset+p.length)); - } - - String changeType() { - boolean leftEmpty= fLeftPos.length == 0; - boolean rightEmpty= fRightPos.length == 0; - - if (fDirection == RangeDifference.LEFT) { - if (!leftEmpty && rightEmpty) - return CompareMessages.TextMergeViewer_changeType_addition; - if (leftEmpty && !rightEmpty) - return CompareMessages.TextMergeViewer_changeType_deletion; - } else { - if (leftEmpty && !rightEmpty) - return CompareMessages.TextMergeViewer_changeType_addition; - if (!leftEmpty && rightEmpty) - return CompareMessages.TextMergeViewer_changeType_deletion; - } - return CompareMessages.TextMergeViewer_changeType_change; - } - - Image getImage() { - int code= Differencer.CHANGE; - switch (fDirection) { - case RangeDifference.RIGHT: - code+= Differencer.LEFT; - break; - case RangeDifference.LEFT: - code+= Differencer.RIGHT; - break; - case RangeDifference.ANCESTOR: - case RangeDifference.CONFLICT: - code+= Differencer.CONFLICTING; - break; - } - if (code != 0) - return getCompareConfiguration().getImage(code); - return null; - } - - Position createPosition(IDocument doc, Position range, int start, int end) { - try { - int l= end-start; - if (range != null) { - int dl= range.length; - if (l > dl) - l= dl; - } else { - int dl= doc.getLength(); - if (start+l > dl) - l= dl-start; - } - - Position p= null; - try { - p= new Position(start, l); - } catch (RuntimeException ex) { - p= new Position(0, 0); - } - - try { - doc.addPosition(DIFF_RANGE_CATEGORY, p); - } catch (BadPositionCategoryException ex) { - // silently ignored - } - return p; - } catch (BadLocationException ee) { - // silently ignored - } - return null; - } + private final MergeSourceViewer viewer; - void add(Diff d) { - if (fDiffs == null) - fDiffs= new ArrayList(); - fDiffs.add(d); - } - - boolean isDeleted() { - if (fAncestorPos != null && fAncestorPos.isDeleted()) - return true; - return fLeftPos.isDeleted() || fRightPos.isDeleted(); - } - - void setResolved(boolean r) { - fResolved= r; - if (r) - fDiffs= null; + public ChangeHighlighter(MergeSourceViewer viewer) { + this.viewer = viewer; } - boolean isResolved() { - if (!fResolved && fDiffs != null) { - Iterator e= fDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); - if (!d.isResolved()) - return false; - } - return true; - } - return fResolved; - } - -// private boolean isIncoming() { -// switch (fDirection) { -// case RangeDifference.RIGHT: -// if (fLeftIsLocal) -// return true; -// break; -// case RangeDifference.LEFT: -// if (!fLeftIsLocal) -// return true; -// break; -// } -// return false; -// } - - private boolean isIncomingOrConflicting() { - switch (fDirection) { - case RangeDifference.RIGHT: - if (fLeftIsLocal) - return true; - break; - case RangeDifference.LEFT: - if (!fLeftIsLocal) - return true; - break; - case RangeDifference.CONFLICT: - return true; - } - return false; - } - -// private boolean isUnresolvedIncoming() { -// if (fResolved) -// return false; -// return isIncoming(); -// } - - private boolean isUnresolvedIncomingOrConflicting() { - if (fResolved) - return false; - return isIncomingOrConflicting(); - } - - Position getPosition(MergeSourceViewer w) { - if (w == fLeft) - return fLeftPos; - if (w == fRight) - return fRightPos; - if (w == fAncestor) - return fAncestorPos; - return null; - } - - /* - * Returns true if given character range overlaps with this Diff. + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) */ - boolean overlaps(MergeSourceViewer w, int start, int end) { - Position h= getPosition(w); - if (h != null) { - int ds= h.getOffset(); - int de= ds + h.getLength(); - if ((start < de) && (end >= ds)) - return true; - } - return false; - } - - int getMaxDiffHeight() { - Point region= new Point(0, 0); - int h= fLeft.getLineRange(fLeftPos, region).y; - if (isThreeWay()) - h= Math.max(h, fAncestor.getLineRange(fAncestorPos, region).y); - return Math.max(h, fRight.getLineRange(fRightPos, region).y); - } - - int getAncestorHeight() { - Point region= new Point(0, 0); - return fAncestor.getLineRange(fAncestorPos, region).y; - } - - int getLeftHeight() { - Point region= new Point(0, 0); - return fLeft.getLineRange(fLeftPos, region).y; - } - - int getRightHeight() { - Point region= new Point(0, 0); - return fRight.getLineRange(fRightPos, region).y; - } - - public Diff[] getChangeDiffs(MergeSourceViewer viewer, IRegion region) { - if (fDiffs != null && intersectsRegion(viewer, region)) { - List result = new ArrayList(); - for (Iterator iterator = fDiffs.iterator(); iterator.hasNext();) { - Diff diff = (Diff) iterator.next(); - if (diff.intersectsRegion(viewer, region)) { - result.add(diff); - } - } - return (Diff[]) result.toArray(new Diff[result.size()]); + public void applyTextPresentation(TextPresentation textPresentation) { + if (!fHighlightTokenChanges) + return; + IRegion region= textPresentation.getExtent(); + Diff[] changeDiffs = fMerger.getChangeDiffs(getLeg(viewer), region); + for (int i = 0; i < changeDiffs.length; i++) { + Diff diff = changeDiffs[i]; + StyleRange range = getStyleRange(diff, region); + if (range != null) + textPresentation.mergeStyleRange(range); } - return new Diff[0]; - } - - private boolean intersectsRegion(MergeSourceViewer viewer, - IRegion region) { - Position p = getPosition(viewer); - if (p != null) - return p.overlapsWith(region.getOffset(), region.getLength()); - return false; } - public StyleRange getStyleRange(MergeSourceViewer viewer, IRegion region) { + private StyleRange getStyleRange(Diff diff, IRegion region) { //Color cText = getColor(null, getTextColor()); - Color cTextFill = getColor(null, getTextFillColor()); + Color cTextFill = getColor(null, getTextFillColor(diff)); if (cTextFill == null) return null; - Position p = getPosition(viewer); + Position p = diff.getPosition(getLeg(viewer)); int start = p.getOffset(); int length = p.getLength(); // Don't start before the region @@ -1316,9 +1068,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return new StyleRange(start, length, null, cTextFill); } - private RGB getTextFillColor() { + private RGB getTextFillColor(Diff diff) { if (isThreeWay() && !isIgnoreAncestor()) { - switch (fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return INCOMING_TEXT_FILL; @@ -1336,54 +1088,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } return OUTGOING_TEXT_FILL; } - - public boolean hasChildren() { - return fDiffs != null && !fDiffs.isEmpty(); - } - } - - private class ChangeHighlighter implements ITextPresentationListener { - - private final MergeSourceViewer viewer; - - public ChangeHighlighter(MergeSourceViewer viewer) { - this.viewer = viewer; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) - */ - public void applyTextPresentation(TextPresentation textPresentation) { - if (!fHighlightTokenChanges) - return; - IRegion region= textPresentation.getExtent(); - Diff[] changeDiffs = getChangeDiffs(region); - for (int i = 0; i < changeDiffs.length; i++) { - Diff diff = changeDiffs[i]; - StyleRange range = getStyleRange(diff, region); - if (range != null) - textPresentation.mergeStyleRange(range); - } - } - - private StyleRange getStyleRange(Diff diff, IRegion region) { - return diff.getStyleRange(viewer, region); - } - - private Diff[] getChangeDiffs(IRegion region) { - if (fChangeDiffs == null) - return new Diff[0]; - List intersectingDiffs = new ArrayList(); - for (Iterator iterator = fChangeDiffs.iterator(); iterator.hasNext();) { - Diff diff = (Diff) iterator.next(); - Diff[] changeDiffs = diff.getChangeDiffs(viewer, region); - for (int i = 0; i < changeDiffs.length; i++) { - Diff changeDiff = changeDiffs[i]; - intersectingDiffs.add(changeDiff); - } - } - return (Diff[]) intersectingDiffs.toArray(new Diff[intersectingDiffs.size()]); - } } @@ -1438,6 +1142,58 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { public TextMergeViewer(Composite parent, int style, CompareConfiguration configuration) { super(style, ResourceBundle.getBundle(BUNDLE_NAME), configuration); + fMerger = new DocumentMerger(new IDocumentMergerInput() { + public ITokenComparator createTokenComparator(String line) { + return TextMergeViewer.this.createTokenComparator(line); + } + public CompareConfiguration getCompareConfiguration() { + return TextMergeViewer.this.getCompareConfiguration(); + } + public IDocument getDocument(char contributor) { + switch (contributor) { + case LEFT_CONTRIBUTOR: + return fLeft.getDocument(); + case RIGHT_CONTRIBUTOR: + return fRight.getDocument(); + case ANCESTOR_CONTRIBUTOR: + return fAncestor.getDocument(); + } + return null; + } + public int getHunkStart() { + return TextMergeViewer.this.getHunkStart(); + } + public Position getRegion(char contributor) { + switch (contributor) { + case LEFT_CONTRIBUTOR: + return fLeft.getRegion(); + case RIGHT_CONTRIBUTOR: + return fRight.getRegion(); + case ANCESTOR_CONTRIBUTOR: + return fAncestor.getRegion(); + } + return null; + } + public boolean isHunkOnLeft() { + ITypedElement left = ((ICompareInput)getInput()).getRight(); + return left != null && Utilities.getAdapter(left, IHunk.class) != null; + } + public boolean isIgnoreAncestor() { + return TextMergeViewer.this.isIgnoreAncestor(); + } + public boolean isPatchHunk() { + return TextMergeViewer.this.isPatchHunk(); + } + + public boolean isShowPseudoConflicts() { + return fShowPseudoConflicts; + } + public boolean isThreeWay() { + return TextMergeViewer.this.isThreeWay(); + } + + }); + int inheritedStyle= parent.getStyle(); if ((inheritedStyle & SWT.LEFT_TO_RIGHT) != 0) fInheritedDirection= SWT.LEFT_TO_RIGHT; @@ -1952,7 +1708,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { public void mouseMove(MouseEvent e) { Cursor cursor= null; Diff diff= handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y); - if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) + if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) cursor= fBirdsEyeCursor; if (fLastCursor != cursor) { fBirdsEyeCanvas.setCursor(cursor); @@ -1993,7 +1749,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private void setCurrentDiff2(Diff diff, boolean reveal) { - if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) { + if (diff != null && diff.getKind() != RangeDifference.NOCHANGE) { //fCurrentDiff= null; setCurrentDiff(diff, reveal); } @@ -2007,20 +1763,20 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return null; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int shift= tp.getVerticalScrollOffset() + (2-LW); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), region); + tp.getLineRange(diff.getPosition(leg), region); int y= (region.x * lineHeight) + shift; int h= region.y * lineHeight; @@ -2050,26 +1806,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return null; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int lshift= fLeft.getVerticalScrollOffset(); int rshift= fRight.getVerticalScrollOffset(); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - fLeft.getLineRange(diff.fLeftPos, region); + fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region); int ly= (region.x * lineHeight) + lshift; int lh= region.y * lineHeight; - fRight.getLineRange(diff.fRightPos, region); + fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region); int ry= (region.x * lineHeight) + rshift; int rh= region.y * lineHeight; @@ -2096,35 +1851,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff handlemouseInBirdsEyeView(Canvas canvas, int my) { - int yy, hh; - - Point size= canvas.getSize(); - - int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); - if (virtualHeight < getViewportHeight()) - return null; - - int y= 0; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() - : diff.getRightHeight(); - if (useChange(diff.fDirection) && !diff.fIsWhitespace) { - - yy= (y*size.y)/virtualHeight; - hh= (h*size.y)/virtualHeight; - if (hh < 3) - hh= 3; - - if (my >= yy && my < yy+hh) - return diff; - } - y+= h; - } - } - return null; + return fMerger.findDiff(getViewportHeight(), fSynchronizedScrolling, canvas.getSize(), my); } private void paintBirdsEyeView(Canvas canvas, GC gc) { @@ -2135,54 +1862,50 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Point size= canvas.getSize(); - int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); + int virtualHeight= fSynchronizedScrolling ? fMerger.getVirtualHeight() : fMerger.getRightHeight(); if (virtualHeight < getViewportHeight()) return; Display display= canvas.getDisplay(); int y= 0; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() - : diff.getRightHeight(); - - if (useChange(diff.fDirection) && !diff.fIsWhitespace) { - - yy= (y*size.y)/virtualHeight; - hh= (h*size.y)/virtualHeight; - if (hh < 3) - hh= 3; - - c= getColor(display, getFillColor(diff)); - if (c != null) { - gc.setBackground(c); - gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh); - } - c= getColor(display, getStrokeColor(diff)); - if (c != null) { - gc.setForeground(c); - r.x= BIRDS_EYE_VIEW_INSET; - r.y= yy; - r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1; - r.height= hh; - if (diff == fCurrentDiff || - (fCurrentDiff != null && diff == fCurrentDiff.fParent)) { - gc.setLineWidth(2); - r.x++; - r.y++; - r.width--; - r.height--; - } else { - gc.setLineWidth(0 /* 1 */); - } - gc.drawRectangle(r); + for (Iterator iterator = fMerger.rangesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() + : diff.getRightHeight(); + + if (fMerger.useChange(diff)) { + + yy= (y*size.y)/virtualHeight; + hh= (h*size.y)/virtualHeight; + if (hh < 3) + hh= 3; + + c= getColor(display, getFillColor(diff)); + if (c != null) { + gc.setBackground(c); + gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh); + } + c= getColor(display, getStrokeColor(diff)); + if (c != null) { + gc.setForeground(c); + r.x= BIRDS_EYE_VIEW_INSET; + r.y= yy; + r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1; + r.height= hh; + if (isCurrentDiff(diff)) { + gc.setLineWidth(2); + r.x++; + r.y++; + r.width--; + r.height--; + } else { + gc.setLineWidth(0 /* 1 */); } + gc.drawRectangle(r); } - - y+= h; } + + y+= h; } } @@ -2257,7 +1980,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { setCurrentDiff(fButtonDiff, false); copy(fCurrentDiff, fCenterButton.getText().equals(COPY_LEFT_TO_RIGHT_INDICATOR), - fCurrentDiff.fDirection != RangeDifference.CONFLICT); + fCurrentDiff.getKind() != RangeDifference.CONFLICT); } } } @@ -2651,9 +2374,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Diff selectDiff= null; if (FIX_47640) { if (leftRange != null) - selectDiff= findDiff(LEFT_CONTRIBUTOR, leftRange); + selectDiff= fMerger.findDiff(LEFT_CONTRIBUTOR, leftRange); else if (rightRange != null) - selectDiff= findDiff(RIGHT_CONTRIBUTOR, rightRange); + selectDiff= fMerger.findDiff(RIGHT_CONTRIBUTOR, rightRange); } if (selectDiff != null) setCurrentDiff(selectDiff, true); @@ -2673,37 +2396,12 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return new ContributorInfo(this, element, leg); } - private Diff findDiff(char c, Position range) { - - MergeSourceViewer v; - int start= range.getOffset(); - int end= start + range.getLength(); - if (c == LEFT_CONTRIBUTOR) - v= fLeft; - else if (c == RIGHT_CONTRIBUTOR) - v= fRight; - else - return null; - - if (fChangeDiffs != null) { - Iterator iter= fChangeDiffs.iterator(); - while (iter.hasNext()) { - Diff diff= (Diff) iter.next(); - if (diff.isDeleted() || diff.fDirection == RangeDifference.NOCHANGE) - continue; - if (diff.overlaps(v, start, end)) - return diff; - } - } - return null; - } - private void updateDiffBackground(Diff diff) { if (! fHighlightRanges) return; - if (diff == null || diff.fIsToken) + if (diff == null || diff.isToken()) return; if (fShowCurrentOnly && !isCurrentDiff(diff)) @@ -2714,36 +2412,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { return; if (isThreeWay()) - fAncestor.setLineBackground(diff.fAncestorPos, c); - fLeft.setLineBackground(diff.fLeftPos, c); - fRight.setLineBackground(diff.fRightPos, c); + fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c); + fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c); + fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c); } private void updateAllDiffBackgrounds(Display display) { - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { boolean threeWay= isThreeWay(); - Iterator iter= fChangeDiffs.iterator(); - while (iter.hasNext()) { - Diff diff= (Diff) iter.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); Color c= getColor(display, getFillColor(diff)); if (threeWay) - fAncestor.setLineBackground(diff.fAncestorPos, c); - fLeft.setLineBackground(diff.fLeftPos, c); - fRight.setLineBackground(diff.fRightPos, c); + fAncestor.setLineBackground(diff.getPosition(ANCESTOR_CONTRIBUTOR), c); + fLeft.setLineBackground(diff.getPosition(LEFT_CONTRIBUTOR), c); + fRight.setLineBackground(diff.getPosition(RIGHT_CONTRIBUTOR), c); } } } - boolean isCurrentDiff(Diff diff) { - if (diff == null) - return false; - if (diff == fCurrentDiff) - return true; - if (fCurrentDiff != null && fCurrentDiff.fParent == diff) - return true; - return false; - } - /* * Called whenever one of the documents changes. * Sets the dirty state of this viewer and updates the lines. @@ -2810,22 +2497,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { IDocumentRange dr= (IDocumentRange) other; Position p= dr.getRange(); Diff diff= findDiff(otherType, p.offset); - if (diff != null) { - switch (type) { - case ANCESTOR_CONTRIBUTOR: - if (diff.fAncestorPos != null) - return diff.fAncestorPos.offset; - break; - case LEFT_CONTRIBUTOR: - if (diff.fLeftPos != null) - return diff.fLeftPos.offset; - break; - case RIGHT_CONTRIBUTOR: - if (diff.fRightPos != null) - return diff.fRightPos.offset; - break; - } - } + return fMerger.findInsertionPoint(diff, type); } return 0; } @@ -3059,224 +2731,53 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } //---- the differencing - - private static int maxWork(IRangeComparator a, IRangeComparator l, IRangeComparator r) { - int ln= l.getRangeCount(); - int rn= r.getRangeCount(); - if (a != null) { - int an= a.getRangeCount(); - return (2 * Math.max(an, ln)) + (2 * Math.max(an, rn)); - } - return 2 * Math.max(ln, rn); - } /** * Perform a two level 2- or 3-way diff. * The first level is based on line comparison, the second level on token comparison. */ private void doDiff() { - - ArrayList newAllDiffs = new ArrayList(); - fChangeDiffs= new ArrayList(); - fCurrentDiff= null; - - IDocument aDoc= null; IDocument lDoc= fLeft.getDocument(); IDocument rDoc= fRight.getDocument(); if (lDoc == null || rDoc == null) return; - - Position aRegion= null; - Position lRegion= fLeft.getRegion(); - Position rRegion= fRight.getRegion(); - - boolean threeWay= isThreeWay(); - - if (threeWay && !isIgnoreAncestor()) { - aDoc= fAncestor.getDocument(); - aRegion= fAncestor.getRegion(); - } - - resetPositions(lDoc); - resetPositions(rDoc); - resetPositions(aDoc); - fAncestor.resetLineBackground(); fLeft.resetLineBackground(); fRight.resetLineBackground(); - boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); - - DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); - DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); - DocLineComparator sancestor= null; - boolean isRight = true; - if (aDoc != null) { - sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - if (isPatchHunk()) { - ITypedElement right = ((ICompareInput)getInput()).getRight(); - isRight = right != null && Utilities.getAdapter(right, IHunk.class) != null; - if (isRight) { - sleft= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - } else { - sright= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - } - } - } - - if (!fSubDoc && rRegion != null && lRegion != null) { - // we have to add a diff for the ignored lines - - int astart= 0; - int as= 0; - if (aRegion != null) { - astart= aRegion.getOffset(); - as= Math.max(0, astart-1); - } - int ys= Math.max(0, lRegion.getOffset()-1); - int ms= Math.max(0, rRegion.getOffset()-1); - - if (as > 0 || ys > 0 || ms > 0) { - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, 0, astart, - lDoc, lRegion, 0, lRegion.getOffset(), - rDoc, rRegion, 0, rRegion.getOffset()); - newAllDiffs.add(diff); - } - } - - final ResourceBundle bundle= getResourceBundle(); - - final Object[] result= new Object[1]; - final DocLineComparator sa= sancestor, sl= sleft, sr= sright; - IRunnableWithProgress runnable= new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { - String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); //$NON-NLS-1$ - monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); - try { - result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); - } catch (OutOfMemoryError ex) { - System.gc(); - throw new InvocationTargetException(ex); - } - if (monitor.isCanceled()) { // canceled - throw new InterruptedException(); - } - monitor.done(); - } - }; - - RangeDifference[] e= null; + fCurrentDiff= null; try { - getCompareConfiguration().getContainer().run(true, true, runnable); - e= (RangeDifference[]) result[0]; - } catch (InvocationTargetException ex) { - String title= Utilities.getString(bundle, "tooComplexError.title"); //$NON-NLS-1$ - String format= Utilities.getString(bundle, "tooComplexError.format"); //$NON-NLS-1$ + fMerger.doDiff(); + } catch (CoreException e) { + CompareUIPlugin.log(e.getStatus()); + String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$ + String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$ String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } ); MessageDialog.openError(fComposite.getShell(), title, msg); - e= null; - } catch (InterruptedException ex) { - // } - - if (e == null) { - // we create a NOCHANGE range for the whole document - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, 0, aDoc != null ? aDoc.getLength() : 0, - lDoc, lRegion, 0, lDoc.getLength(), - rDoc, rRegion, 0, rDoc.getLength()); - - newAllDiffs.add(diff); - } else { - for (int i= 0; i < e.length; i++) { - String a= null, s= null, d= null; - RangeDifference es= e[i]; - - int kind= es.kind(); - - int ancestorStart= 0; - int ancestorEnd= 0; - if (sancestor != null) { - ancestorStart= sancestor.getTokenStart(es.ancestorStart()); - ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart= sleft.getTokenStart(es.leftStart()); - int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); - - int rightStart= sright.getTokenStart(es.rightStart()); - int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); - - if (isPatchHunk()) { - if (isRight) - leftStart = leftEnd = getHunkStart(); - else - rightStart = rightEnd = getHunkStart(); - } - - Diff diff= new Diff(null, kind, - aDoc, aRegion, ancestorStart, ancestorEnd, - lDoc, lRegion, leftStart, leftEnd, - rDoc, rRegion, rightStart, rightEnd); - - newAllDiffs.add(diff); // remember all range diffs for scrolling - - if (ignoreWhiteSpace && !isPatchHunk()) { - if (sancestor != null) - a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); - s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); - d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); - - if ((a == null || a.trim().length() == 0) && s.trim().length() == 0 && d.trim().length() == 0) { - diff.fIsWhitespace= true; - continue; - } - } - if (useChange(kind)) { - fChangeDiffs.add(diff); // here we remember only the real diffs - updateDiffBackground(diff); - - // Only do the token diff for non-hunks - if (!isPatchHunk()) { - if (s == null) - s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); - if (d == null) - d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); - - if (s.length() > 0 && d.length() > 0) { - if (a == null && sancestor != null) - a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); - if (USE_MERGING_TOKEN_DIFF) - mergingTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); - else - simpleTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); - } - } - } + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + updateDiffBackground(diff); } } - - if (!fSubDoc && rRegion != null && lRegion != null) { - // we have to add a diff for the ignored lines - - int aEnd= 0; - int aLen= 0; - if (aRegion != null && aDoc != null) { - aEnd= aRegion.getOffset()+aRegion.getLength(); - aLen= aDoc.getLength(); - } - Diff diff= new Diff(null, RangeDifference.NOCHANGE, - aDoc, aRegion, aEnd, aLen, - lDoc, lRegion, lRegion.getOffset()+lRegion.getLength(), lDoc.getLength(), - rDoc, rRegion, rRegion.getOffset()+rRegion.getLength(), rDoc.getLength()); - newAllDiffs.add(diff); - } - fAllDiffs = newAllDiffs; invalidateTextPresentation(); } + private Diff findDiff(char type, int pos) { + try { + return fMerger.findDiff(type, pos); + } catch (CoreException e) { + CompareUIPlugin.log(e.getStatus()); + String title= Utilities.getString(getResourceBundle(), "tooComplexError.title"); //$NON-NLS-1$ + String format= Utilities.getString(getResourceBundle(), "tooComplexError.format"); //$NON-NLS-1$ + String msg= MessageFormat.format(format, new Object[] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } ); + MessageDialog.openError(fComposite.getShell(), title, msg); + return null; + } + } + private void resetPositions(IDocument doc) { if (doc == null) return; @@ -3287,314 +2788,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } doc.addPositionCategory(DIFF_RANGE_CATEGORY); } - - private Diff findDiff(char type, int pos) { - - IDocument aDoc= null; - IDocument lDoc= fLeft.getDocument(); - IDocument rDoc= fRight.getDocument(); - if (lDoc == null || rDoc == null) - return null; - - Position aRegion= null; - Position lRegion= null; - Position rRegion= null; - - boolean threeWay= isThreeWay(); - - if (threeWay && !isIgnoreAncestor()) - aDoc= fAncestor.getDocument(); - - boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); - - DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); - DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); - DocLineComparator sancestor= null; - if (aDoc != null) - sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); - - final ResourceBundle bundle= getResourceBundle(); - - final Object[] result= new Object[1]; - final DocLineComparator sa= sancestor, sl= sleft, sr= sright; - IRunnableWithProgress runnable= new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { - String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); //$NON-NLS-1$ - monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); - try { - result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); - } catch (OutOfMemoryError ex) { - System.gc(); - throw new InvocationTargetException(ex); - } - if (monitor.isCanceled()) { // canceled - throw new InterruptedException(); - } - monitor.done(); - } - }; - IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); - - RangeDifference[] e= null; - try { - progressService.run(true, true, runnable); - e= (RangeDifference[]) result[0]; - } catch (InvocationTargetException ex) { - String title= Utilities.getString(bundle, "tooComplexError.title"); //$NON-NLS-1$ - String format= Utilities.getString(bundle, "tooComplexError.format"); //$NON-NLS-1$ - String msg= MessageFormat.format(format, new Object[] { Integer.toString(progressService.getLongOperationTime()/1000) } ); - MessageDialog.openError(fComposite.getShell(), title, msg); - e= null; - } catch (InterruptedException ex) { - // - } - - if (e != null) { - for (int i= 0; i < e.length; i++) { - RangeDifference es= e[i]; - - int kind= es.kind(); - - int ancestorStart= 0; - int ancestorEnd= 0; - if (sancestor != null) { - ancestorStart= sancestor.getTokenStart(es.ancestorStart()); - ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart= sleft.getTokenStart(es.leftStart()); - int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); - - int rightStart= sright.getTokenStart(es.rightStart()); - int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); - - Diff diff= new Diff(null, kind, - aDoc, aRegion, ancestorStart, ancestorEnd, - lDoc, lRegion, leftStart, leftEnd, - rDoc, rRegion, rightStart, rightEnd); - - if (diff.isInRange(type, pos)) - return diff; - } - } - - return null; - } - - /* - * Returns true if kind of change should be shown. - */ - private boolean useChange(int kind) { - if (kind == RangeDifference.NOCHANGE) - return false; - if (kind == RangeDifference.ANCESTOR) - return fShowPseudoConflicts; - return true; - } - - private int getTokenEnd(ITokenComparator tc, int start, int count) { - if (count <= 0) - return tc.getTokenStart(start); - int index= start + count - 1; - return tc.getTokenStart(index) + tc.getTokenLength(index); - } - - private static int getTokenEnd2(ITokenComparator tc, int start, int length) { - return tc.getTokenStart(start + length); - } - - /* - * Returns the content of lines in the specified range as a String. - * This includes the line separators. - * - * @param doc the document from which to extract the characters - * @param start index of first line - * @param length number of lines - * @return the contents of the specified line range as a String - */ - private String extract2(IDocument doc, ITokenComparator tc, int start, int length) { - int count= tc.getRangeCount(); - if (length > 0 && count > 0) { - -// -// int startPos= tc.getTokenStart(start); -// int endPos= startPos; -// -// if (length > 1) -// endPos= tc.getTokenStart(start + (length-1)); -// endPos+= tc.getTokenLength(start + (length-1)); -// - - int startPos= tc.getTokenStart(start); - int endPos; - - if (length == 1) { - endPos= startPos + tc.getTokenLength(start); - } else { - endPos= tc.getTokenStart(start + length); - } - - try { - return doc.get(startPos, endPos - startPos); - } catch (BadLocationException e) { - // silently ignored - } - - } - return ""; //$NON-NLS-1$ - } - - /* - * Performs a token based 3-way diff on the character range specified by the given baseDiff. - */ - private void simpleTokenDiff(final Diff baseDiff, - IDocument ancestorDoc, String a, - IDocument rightDoc, String d, - IDocument leftDoc, String s) { - - int ancestorStart= 0; - ITokenComparator sa= null; - if (ancestorDoc != null) { - ancestorStart= baseDiff.fAncestorPos.getOffset(); - sa= createTokenComparator(a); - } - - int rightStart= baseDiff.fRightPos.getOffset(); - ITokenComparator sm= createTokenComparator(d); - - int leftStart= baseDiff.fLeftPos.getOffset(); - ITokenComparator sy= createTokenComparator(s); - - RangeDifference[] e= RangeDifferencer.findRanges(sa, sy, sm); - for (int i= 0; i < e.length; i++) { - RangeDifference es= e[i]; - int kind= es.kind(); - if (kind != RangeDifference.NOCHANGE) { - - int ancestorStart2= ancestorStart; - int ancestorEnd2= ancestorStart; - if (ancestorDoc != null) { - ancestorStart2 += sa.getTokenStart(es.ancestorStart()); - ancestorEnd2 += getTokenEnd(sa, es.ancestorStart(), es.ancestorLength()); - } - - int leftStart2= leftStart + sy.getTokenStart(es.leftStart()); - int leftEnd2= leftStart + getTokenEnd(sy, es.leftStart(), es.leftLength()); - - int rightStart2= rightStart + sm.getTokenStart(es.rightStart()); - int rightEnd2= rightStart + getTokenEnd(sm, es.rightStart(), es.rightLength()); - - Diff diff= new Diff(baseDiff, kind, - ancestorDoc, null, ancestorStart2, ancestorEnd2, - leftDoc, null, leftStart2, leftEnd2, - rightDoc, null, rightStart2, rightEnd2); - - // ensure that token diff is smaller than basediff - int leftS= baseDiff.fLeftPos.offset; - int leftE= baseDiff.fLeftPos.offset+baseDiff.fLeftPos.length; - int rightS= baseDiff.fRightPos.offset; - int rightE= baseDiff.fRightPos.offset+baseDiff.fRightPos.length; - if (leftS != leftStart2 || leftE != leftEnd2 || - rightS != rightStart2 || rightE != rightEnd2) { - diff.fIsToken= true; - // add to base Diff - baseDiff.add(diff); - } - } - } - } - - /* - * Performs a "smart" token based 3-way diff on the character range specified by the given baseDiff. - * It is "smart" because it tries to minimize the number of token diffs by merging them. - */ - private void mergingTokenDiff(Diff baseDiff, - IDocument ancestorDoc, String a, - IDocument rightDoc, String d, - IDocument leftDoc, String s) { - ITokenComparator sa= null; - int ancestorStart= 0; - if (ancestorDoc != null) { - sa= createTokenComparator(a); - ancestorStart= baseDiff.fAncestorPos.getOffset(); - } - - int rightStart= baseDiff.fRightPos.getOffset(); - ITokenComparator sm= createTokenComparator(d); - - int leftStart= baseDiff.fLeftPos.getOffset(); - ITokenComparator sy= createTokenComparator(s); - - RangeDifference[] r= RangeDifferencer.findRanges(sa, sy, sm); - for (int i= 0; i < r.length; i++) { - RangeDifference es= r[i]; - // determine range of diffs in one line - int start= i; - int leftLine= -1; - int rightLine= -1; - try { - leftLine= leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart())); - rightLine= rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart())); - } catch (BadLocationException e) { - // silently ignored - } - i++; - for (; i < r.length; i++) { - es= r[i]; - try { - if (leftLine != leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart()))) - break; - if (rightLine != rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart()))) - break; - } catch (BadLocationException e) { - // silently ignored - } - } - int end= i; - - // find first diff from left - RangeDifference first= null; - for (int ii= start; ii < end; ii++) { - es= r[ii]; - if (useChange(es.kind())) { - first= es; - break; - } - } - - // find first diff from mine - RangeDifference last= null; - for (int ii= end-1; ii >= start; ii--) { - es= r[ii]; - if (useChange(es.kind())) { - last= es; - break; - } - } - - if (first != null && last != null) { - - int ancestorStart2= 0; - int ancestorEnd2= 0; - if (ancestorDoc != null) { - ancestorStart2= ancestorStart+sa.getTokenStart(first.ancestorStart()); - ancestorEnd2= ancestorStart+getTokenEnd(sa, last.ancestorStart(), last.ancestorLength()); - } - - int leftStart2= leftStart+sy.getTokenStart(first.leftStart()); - int leftEnd2= leftStart+getTokenEnd(sy, last.leftStart(), last.leftLength()); - - int rightStart2= rightStart+sm.getTokenStart(first.rightStart()); - int rightEnd2= rightStart+getTokenEnd(sm, last.rightStart(), last.rightLength()); - Diff diff= new Diff(baseDiff, first.kind(), - ancestorDoc, null, ancestorStart2, ancestorEnd2, - leftDoc, null, leftStart2, leftEnd2, - rightDoc, null, rightStart2, rightEnd2); - diff.fIsToken= true; - baseDiff.add(diff); - } - } - } //---- update UI stuff @@ -3629,16 +2822,8 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (fCopyDiffRightToLeftItem != null) ((Action)fCopyDiffRightToLeftItem.getAction()).setEnabled(rightToLeft); - boolean enableNavigation= false; - if (fCurrentDiff == null && fChangeDiffs != null && fChangeDiffs.size() > 0) - enableNavigation= true; - else if (fChangeDiffs != null && fChangeDiffs.size() > 1) - enableNavigation= true; - else if (fCurrentDiff != null && fCurrentDiff.fDiffs != null) - enableNavigation= true; - else if (fCurrentDiff != null && fCurrentDiff.fIsToken) - enableNavigation= true; - + boolean enableNavigation= isNavigationPossible(); + if (fNextDiff != null) { IAction a= fNextDiff.getAction(); a.setEnabled(enableNavigation || hasNextElement(true)); @@ -3667,14 +2852,14 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int unresolvedIncoming= 0; int unresolvedConflicting= 0; - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator + .hasNext();) { + Diff d = (Diff) iterator.next(); if (d.isIncomingOrConflicting() /* && useChange(d.fDirection) && !d.fIsWhitespace */) { incomingOrConflicting++; - if (!d.fResolved) { - if (d.fDirection == RangeDifference.CONFLICT) { + if (!d.isResolved()) { + if (d.getKind() == RangeDifference.CONFLICT) { unresolvedConflicting++; break; // we can stop here because a conflict has the maximum priority } @@ -3709,16 +2894,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { diffDescription= CompareMessages.TextMergeViewer_diffDescription_noDiff_format; } else { - if (diff.fIsToken) // we don't show special info for token diffs - diff= diff.fParent; + if (diff.isToken()) // we don't show special info for token diffs + diff= diff.getParent(); String format= CompareMessages.TextMergeViewer_diffDescription_diff_format; diffDescription= MessageFormat.format(format, new String[] { getDiffType(diff), // 0: diff type getDiffNumber(diff), // 1: diff number - getDiffRange(fLeft, diff.fLeftPos), // 2: left start line - getDiffRange(fRight, diff.fRightPos) // 3: left end line + getDiffRange(fLeft, diff.getPosition(LEFT_CONTRIBUTOR)), // 2: left start line + getDiffRange(fRight, diff.getPosition(RIGHT_CONTRIBUTOR)) // 3: left end line } ); } @@ -3741,7 +2926,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private String getDiffType(Diff diff) { String s= ""; //$NON-NLS-1$ - switch(diff.fDirection) { + switch(diff.getKind()) { case RangeDifference.LEFT: s= CompareMessages.TextMergeViewer_direction_outgoing; break; @@ -3759,10 +2944,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private String getDiffNumber(Diff diff) { // find the diff's number int diffNumber= 0; - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff d= (Diff) e.next(); + if (fMerger.hasChanges()) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff d = (Diff) iterator.next(); diffNumber++; if (d == diff) break; @@ -4036,9 +3220,9 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { Diff firstDiff= null; if (first) - firstDiff= findNext(fRight, fChangeDiffs, -1, -1, false); + firstDiff= findNext(fRight, -1, -1, false); else - firstDiff= findPrev(fRight, fChangeDiffs, 9999999, 9999999, false); + firstDiff= findPrev(fRight, 9999999, 9999999, false); setCurrentDiff(firstDiff, true); } @@ -4189,26 +3373,25 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { boolean showResolveUI= showResolveUI(); - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int lshift= fLeft.getVerticalScrollOffset(); int rshift= fRight.getVerticalScrollOffset(); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - fLeft.getLineRange(diff.fLeftPos, region); + fLeft.getLineRange(diff.getPosition(LEFT_CONTRIBUTOR), region); int ly= (region.x * lineHeightLeft) + lshift; int lh= region.y * lineHeightLeft; - fRight.getLineRange(diff.fRightPos, region); + fRight.getLineRange(diff.getPosition(RIGHT_CONTRIBUTOR), region); int ry= (region.x * lineHeightRight) + rshift; int rh= region.y * lineHeightRight; @@ -4336,20 +3519,20 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return; - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { int shift= tp.getVerticalScrollOffset() + (2-LW); Point region= new Point(0, 0); - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly2 && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), region); + tp.getLineRange(diff.getPosition(leg), region); int y= (region.x * lineHeight) + shift; int h= region.y * lineHeight; @@ -4378,7 +3561,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (! fHighlightRanges) return; - if (fChangeDiffs == null) + if (!fMerger.hasChanges()) return; Control canvas= (Control) event.widget; @@ -4395,17 +3578,17 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { shift+= fTopInset; Point range= new Point(0, 0); - - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); + + char leg = getLeg(tp); + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); if (diff.isDeleted()) continue; if (fShowCurrentOnly && !isCurrentDiff(diff)) continue; - tp.getLineRange(diff.getPosition(tp), range); + tp.getLineRange(diff.getPosition(leg), range); int y= (range.x * lineHeight) + shift; int h= range.y * lineHeight; @@ -4421,10 +3604,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private RGB getFillColor(Diff diff) { - boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; + boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff; RGB selected_fill= getBackground(null); if (isThreeWay() && !isIgnoreAncestor()) { - switch (diff.fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return selected ? selected_fill : INCOMING_FILL; @@ -4444,10 +3627,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private RGB getStrokeColor(Diff diff) { - boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; + boolean selected= fCurrentDiff != null && fCurrentDiff.getParent() == diff; if (isThreeWay() && !isIgnoreAncestor()) { - switch (diff.fDirection) { + switch (diff.getKind()) { case RangeDifference.RIGHT: if (fLeftIsLocal) return selected ? SELECTED_INCOMING : INCOMING; @@ -4501,12 +3684,13 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (part == null) return null; Point s = part.getSelectedRange(); + char leg = getLeg(part); for (;;) { diff = null; diff = internalGetNextDiff(down, deep, part, s); - if (diff != null && diff.fDirection == RangeDifference.ANCESTOR + if (diff != null && diff.getKind() == RangeDifference.ANCESTOR && !isAncestorVisible()) { - Position position = diff.getPosition(part); + Position position = diff.getPosition(leg); s = new Point(position.getOffset(), position.getLength()); diff= null; continue; @@ -4517,10 +3701,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff internalGetNextDiff(boolean down, boolean deep, MergeSourceViewer part, Point s) { - if (fChangeDiffs != null) { + if (fMerger.hasChanges()) { if (down) - return findNext(part, fChangeDiffs, s.x, s.x+s.y, deep); - return findPrev(part, fChangeDiffs, s.x, s.x+s.y, deep); + return findNext(part, s.x, s.x+s.y, deep); + return findPrev(part, s.x, s.x+s.y, deep); } return null; } @@ -4533,12 +3717,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } private Diff getWrappedDiff(Diff diff, boolean down) { - if (fChangeDiffs != null && fChangeDiffs.size() > 0) { - if (down) - return (Diff) fChangeDiffs.get(0); - return (Diff) fChangeDiffs.get(fChangeDiffs.size()-1); - } - return null; + return fMerger.getWrappedDiff(diff, down); } /* @@ -4558,7 +3737,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } if (diff != null) setCurrentDiff(diff, true, deep); - if (diff != null && diff.fDirection == RangeDifference.ANCESTOR + if (diff != null && diff.getKind() == RangeDifference.ANCESTOR && !isAncestorVisible()) continue; break; @@ -4662,83 +3841,16 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { * is returned. */ private Diff findDiff(MergeSourceViewer tp, int rangeStart, int rangeEnd) { - if (fChangeDiffs != null) { - Iterator e= fChangeDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - if (diff.overlaps(tp, rangeStart, rangeEnd)) - return diff; - } - } - return null; + char contributor = getLeg(tp); + return fMerger.findDiff(contributor, rangeStart, rangeEnd); } - private static Diff findNext(MergeSourceViewer tp, List v, int start, int end, boolean deep) { - for (int i= 0; i < v.size(); i++) { - Diff diff= (Diff) v.get(i); - Position p= diff.getPosition(tp); - if (p != null) { - int startOffset= p.getOffset(); - if (end < startOffset) // <= - return diff; - if (deep && diff.fDiffs != null) { - Diff d= null; - int endOffset= startOffset + p.getLength(); - if (start == startOffset && (end == endOffset || end == endOffset-1)) { - d= findNext(tp, diff.fDiffs, start-1, start-1, deep); - } else if (end < endOffset) { - d= findNext(tp, diff.fDiffs, start, end, deep); - } - if (d != null) - return d; - } - } - } - return null; + private Diff findNext(MergeSourceViewer tp, int start, int end, boolean deep) { + return fMerger.findNext(getLeg(tp), start, end, deep); } - private static Diff findPrev(MergeSourceViewer tp, List v, int start, int end, boolean deep) { - for (int i= v.size()-1; i >= 0; i--) { - Diff diff= (Diff) v.get(i); - Position p= diff.getPosition(tp); - if (p != null) { - int startOffset= p.getOffset(); - int endOffset= startOffset + p.getLength(); - if (start > endOffset) { - if (deep && diff.fDiffs != null) { - // If we are going deep, find the last change in the diff - return findPrev(tp, diff.fDiffs, end, end, deep); - } - return diff; - } - if (deep && diff.fDiffs != null) { - Diff d= null; - if (start == startOffset && end == endOffset) { - // A whole diff is selected so we'll fall through - // and go the the last change in the previous diff - } else if (start >= startOffset) { - // If we are at or before the first diff, select the - // entire diff so next and previous are symmetrical - if (isFirstDiff(tp, startOffset, diff.fDiffs)) { - return diff; - } - d= findPrev(tp, diff.fDiffs, start, end, deep); - } - if (d != null) - return d; - } - } - } - return null; - } - - private static boolean isFirstDiff(MergeSourceViewer tp, int startOffset, - ArrayList diffs) { - if (diffs.isEmpty()) - return false; - Diff diff = (Diff)diffs.get(0); - Position p= diff.getPosition(tp); - return (p.getOffset() >= startOffset); + private Diff findPrev(MergeSourceViewer tp, int start, int end, boolean deep) { + return fMerger.findPrev(getLeg(tp), start, end, deep); } /* @@ -4770,27 +3882,27 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { // before we set fCurrentDiff we change the selection // so that the paint code uses the old background colors // otherwise selection isn't drawn correctly - if (d.fIsToken || !fHighlightTokenChanges || deep || !d.hasChildren()) { + if (d.isToken() || !fHighlightTokenChanges || deep || !d.hasChildren()) { if (isThreeWay() && !isIgnoreAncestor()) - fAncestor.setSelection(d.fAncestorPos); - fLeft.setSelection(d.fLeftPos); - fRight.setSelection(d.fRightPos); + fAncestor.setSelection(d.getPosition(ANCESTOR_CONTRIBUTOR)); + fLeft.setSelection(d.getPosition(LEFT_CONTRIBUTOR)); + fRight.setSelection(d.getPosition(RIGHT_CONTRIBUTOR)); } else { if (isThreeWay() && !isIgnoreAncestor()) - fAncestor.setSelection(new Position(d.fAncestorPos.offset, 0)); - fLeft.setSelection(new Position(d.fLeftPos.offset, 0)); - fRight.setSelection(new Position(d.fRightPos.offset, 0)); + fAncestor.setSelection(new Position(d.getPosition(ANCESTOR_CONTRIBUTOR).offset, 0)); + fLeft.setSelection(new Position(d.getPosition(LEFT_CONTRIBUTOR).offset, 0)); + fRight.setSelection(new Position(d.getPosition(RIGHT_CONTRIBUTOR).offset, 0)); } // now switch diffs fCurrentDiff= d; - revealDiff(d, d.fIsToken); + revealDiff(d, d.isToken()); } else { fCurrentDiff= d; } - Diff d1= oldDiff != null ? oldDiff.fParent : null; - Diff d2= fCurrentDiff != null ? fCurrentDiff.fParent : null; + Diff d1= oldDiff != null ? oldDiff.getParent() : null; + Diff d2= fCurrentDiff != null ? fCurrentDiff.getParent() : null; if (d1 != d2) { updateDiffBackground(d1); updateDiffBackground(d2); @@ -4813,11 +3925,11 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (smart) { Point region= new Point(0, 0); // find the starting line of the diff in all text widgets - int ls= fLeft.getLineRange(d.fLeftPos, region).x; - int rs= fRight.getLineRange(d.fRightPos, region).x; + int ls= fLeft.getLineRange(d.getPosition(LEFT_CONTRIBUTOR), region).x; + int rs= fRight.getLineRange(d.getPosition(RIGHT_CONTRIBUTOR), region).x; if (isThreeWay() && !isIgnoreAncestor()) { - int as= fAncestor.getLineRange(d.fAncestorPos, region).x; + int as= fAncestor.getLineRange(d.getPosition(ANCESTOR_CONTRIBUTOR), region).x; if (as >= fAncestor.getTopIndex() && as <= fAncestor.getBottomIndex()) ancestorIsVisible= true; } @@ -4835,33 +3947,31 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { MergeSourceViewer allButThis= null; if (leftIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fLeft, fLeft.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(LEFT_CONTRIBUTOR, fLeft.getTopIndex()); allButThis= fLeft; } else if (rightIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fRight, fRight.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(RIGHT_CONTRIBUTOR, fRight.getTopIndex()); allButThis= fRight; } else if (ancestorIsVisible) { - avpos= lvpos= rvpos= realToVirtualPosition(fAncestor, fAncestor.getTopIndex()); + avpos= lvpos= rvpos= realToVirtualPosition(ANCESTOR_CONTRIBUTOR, fAncestor.getTopIndex()); allButThis= fAncestor; } else { - if (fAllDiffs != null) { - int vpos= 0; - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - if (diff == d) - break; - if (fSynchronizedScrolling) { - vpos+= diff.getMaxDiffHeight(); - } else { - avpos+= diff.getAncestorHeight(); - lvpos+= diff.getLeftHeight(); - rvpos+= diff.getRightHeight(); - } + int vpos= 0; + for (Iterator iterator = fMerger.rangesIterator(); iterator + .hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff == d) + break; + if (fSynchronizedScrolling) { + vpos+= diff.getMaxDiffHeight(); + } else { + avpos+= diff.getAncestorHeight(); + lvpos+= diff.getLeftHeight(); + rvpos+= diff.getRightHeight(); } - if (fSynchronizedScrolling) - avpos= lvpos= rvpos= vpos; } + if (fSynchronizedScrolling) + avpos= lvpos= rvpos= vpos; int delta= fRight.getViewportLines()/4; avpos-= delta; if (avpos < 0) @@ -4881,11 +3991,11 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } // horizontal scrolling - if (d.fIsToken) { + if (d.isToken()) { // we only scroll horizontally for token diffs - reveal(fAncestor, d.fAncestorPos); - reveal(fLeft, d.fLeftPos); - reveal(fRight, d.fRightPos); + reveal(fAncestor, d.getPosition(ANCESTOR_CONTRIBUTOR)); + reveal(fLeft, d.getPosition(LEFT_CONTRIBUTOR)); + reveal(fRight, d.getPosition(RIGHT_CONTRIBUTOR)); } else { // in all other cases we reset the horizontal offset hscroll(fAncestor); @@ -4916,14 +4026,13 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { //-------------------------------------------------------------------------------- void copyAllUnresolved(boolean leftToRight) { - if (fChangeDiffs != null && isThreeWay() && !isIgnoreAncestor()) { + if (fMerger.hasChanges() && isThreeWay() && !isIgnoreAncestor()) { IRewriteTarget target= leftToRight ? fRight.getRewriteTarget() : fLeft.getRewriteTarget(); boolean compoundChangeStarted= false; - Iterator e= fChangeDiffs.iterator(); try { - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - switch (diff.fDirection) { + for (Iterator iterator = fMerger.changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + switch (diff.getKind()) { case RangeDifference.LEFT: if (leftToRight) { if (!compoundChangeStarted) { @@ -5029,66 +4138,15 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (diff != null && !diff.isResolved()) { if (!validateChange(!leftToRight)) return false; - Position fromPos= null; - Position toPos= null; - IDocument fromDoc= null; - IDocument toDoc= null; - if (leftToRight) { fRight.setEnabled(true); - fromPos= diff.fLeftPos; - toPos= diff.fRightPos; - fromDoc= fLeft.getDocument(); - toDoc= fRight.getDocument(); } else { fLeft.setEnabled(true); - fromPos= diff.fRightPos; - toPos= diff.fLeftPos; - fromDoc= fRight.getDocument(); - toDoc= fLeft.getDocument(); - } - - if (fromDoc != null) { - - int fromStart= fromPos.getOffset(); - int fromLen= fromPos.getLength(); - - int toStart= toPos.getOffset(); - int toLen= toPos.getLength(); - - try { - String s= null; - - switch (diff.fDirection) { - case RangeDifference.RIGHT: - case RangeDifference.LEFT: - s= fromDoc.get(fromStart, fromLen); - break; - case RangeDifference.ANCESTOR: - break; - case RangeDifference.CONFLICT: - if (APPEND_CONFLICT) { - s= toDoc.get(toStart, toLen); - s+= fromDoc.get(fromStart, fromLen); - } else - s= fromDoc.get(fromStart, fromLen); - break; - } - if (s != null) { - toDoc.replace(toStart, toLen, s); - toPos.setOffset(toStart); - toPos.setLength(s.length()); - } - - } catch (BadLocationException e) { - // silently ignored - } } - - diff.setResolved(true); - updateResolveStatus(); - - return true; + boolean result = fMerger.copy(diff, leftToRight); + if (result) + updateResolveStatus(); + return result; } return false; } @@ -5104,36 +4162,6 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { } //---- scrolling - - /* - * Calculates virtual height (in lines) of views by adding the maximum of corresponding diffs. - */ - private int getVirtualHeight() { - int h= 1; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - h+= diff.getMaxDiffHeight(); - } - } - return h; - } - - /* - * Calculates height (in lines) of right view by adding the height of the right diffs. - */ - private int getRightHeight() { - int h= 1; - if (fAllDiffs != null) { - Iterator e= fAllDiffs.iterator(); - for (int i= 0; e.hasNext(); i++) { - Diff diff= (Diff) e.next(); - h+= diff.getRightHeight(); - } - } - return h; - } /* * The height of the TextEditors in lines. @@ -5160,35 +4188,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { /* * Returns the virtual position for the given view position. */ - private int realToVirtualPosition(MergeSourceViewer w, int vpos) { - - if (! fSynchronizedScrolling || fAllDiffs == null) + private int realToVirtualPosition(char contributor, int vpos) { + if (! fSynchronizedScrolling) return vpos; - - int viewPos= 0; // real view position - int virtualPos= 0; // virtual position - Point region= new Point(0, 0); - - Iterator e= fAllDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - Position pos= diff.getPosition(w); - w.getLineRange(pos, region); - int realHeight= region.y; - int virtualHeight= diff.getMaxDiffHeight(); - if (vpos <= viewPos + realHeight) { // OK, found! - vpos-= viewPos; // make relative to this slot - // now scale position within this slot to virtual slot - if (realHeight <= 0) - vpos= 0; - else - vpos= (vpos*virtualHeight)/realHeight; - return virtualPos+vpos; - } - viewPos+= realHeight; - virtualPos+= virtualHeight; - } - return virtualPos; + return fMerger.realToVirtualPosition(contributor, vpos); } private void scrollVertical(int avpos, int lvpos, int rvpos, MergeSourceViewer allBut) { @@ -5196,7 +4199,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int s= 0; if (fSynchronizedScrolling) { - s= getVirtualHeight() - rvpos; + s= fMerger.getVirtualHeight() - rvpos; int height= fRight.getViewportLines()/4; if (s < 0) s= 0; @@ -5208,21 +4211,21 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { if (isThreeWay() && allBut != fAncestor) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fAncestor, avpos+s)-s; + int y= virtualToRealPosition(ANCESTOR_CONTRIBUTOR, avpos+s)-s; fAncestor.vscroll(y); } } if (allBut != fLeft) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fLeft, lvpos+s)-s; + int y= virtualToRealPosition(LEFT_CONTRIBUTOR, lvpos+s)-s; fLeft.vscroll(y); } } if (allBut != fRight) { if (fSynchronizedScrolling || allBut == null) { - int y= virtualToRealPosition(fRight, rvpos+s)-s; + int y= virtualToRealPosition(RIGHT_CONTRIBUTOR, rvpos+s)-s; fRight.vscroll(y); } } @@ -5254,12 +4257,12 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { int ix= w.getTopIndex(); int ix2= w.getDocumentRegionOffset(); - int viewPosition= realToVirtualPosition(w, ix-ix2); + int viewPosition= realToVirtualPosition(getLeg(w), ix-ix2); scrollVertical(viewPosition, viewPosition, viewPosition, w); // scroll all but the given views if (fVScrollBar != null) { - int value= Math.max(0, Math.min(viewPosition, getVirtualHeight() - getViewportHeight())); + int value= Math.max(0, Math.min(viewPosition, fMerger.getVirtualHeight() - getViewportHeight())); fVScrollBar.setSelection(value); //refreshBirdEyeView(); } @@ -5270,7 +4273,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private void updateVScrollBar() { if (Utilities.okToUse(fVScrollBar) && fSynchronizedScrolling) { - int virtualHeight= getVirtualHeight(); + int virtualHeight= fMerger.getVirtualHeight(); int viewPortHeight= getViewportHeight(); int pageIncrement= viewPortHeight-1; int thumb= (viewPortHeight > virtualHeight) ? virtualHeight : viewPortHeight; @@ -5284,34 +4287,10 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { /* * maps given virtual position into a real view position of this view. */ - private int virtualToRealPosition(MergeSourceViewer part, int v) { - - if (! fSynchronizedScrolling || fAllDiffs == null) + private int virtualToRealPosition(char contributor, int v) { + if (! fSynchronizedScrolling) return v; - - int virtualPos= 0; - int viewPos= 0; - Point region= new Point(0, 0); - - Iterator e= fAllDiffs.iterator(); - while (e.hasNext()) { - Diff diff= (Diff) e.next(); - Position pos= diff.getPosition(part); - int viewHeight= part.getLineRange(pos, region).y; - int virtualHeight= diff.getMaxDiffHeight(); - if (v < (virtualPos + virtualHeight)) { - v-= virtualPos; // make relative to this slot - if (viewHeight <= 0) { - v= 0; - } else { - v= (int) (v * ((double)viewHeight/virtualHeight)); - } - return viewPos+v; - } - virtualPos+= virtualHeight; - viewPos+= viewHeight; - } - return viewPos; + return fMerger.virtualToRealPosition(contributor, v); } /* (non-Javadoc) @@ -5453,8 +4432,7 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { private void resetDiffs() { // clear stuff fCurrentDiff= null; - fChangeDiffs= null; - fAllDiffs= null; + fMerger.reset(); resetPositions(fLeft.getDocument()); resetPositions(fRight.getDocument()); resetPositions(fAncestor.getDocument()); @@ -5492,4 +4470,36 @@ public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { fFindReplaceTarget= new FindReplaceTarget(); return fFindReplaceTarget; } + + /* package */ char getLeg(MergeSourceViewer w) { + if (w == fLeft) + return LEFT_CONTRIBUTOR; + if (w == fRight) + return RIGHT_CONTRIBUTOR; + if (w == fAncestor) + return ANCESTOR_CONTRIBUTOR; + return ANCESTOR_CONTRIBUTOR; + } + + public boolean isCurrentDiff(Diff diff) { + if (diff == null) + return false; + if (diff == fCurrentDiff) + return true; + if (fCurrentDiff != null && fCurrentDiff.getParent() == diff) + return true; + return false; + } + + public boolean isNavigationPossible() { + if (fCurrentDiff == null && fMerger.hasChanges()) + return true; + else if (fMerger.changesCount() > 1) + return true; + else if (fCurrentDiff != null && fCurrentDiff.hasChildren()) + return true; + else if (fCurrentDiff != null && fCurrentDiff.isToken()) + return true; + return false; + } } diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java new file mode 100644 index 000000000..64290904a --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/merge/DocumentMerger.java @@ -0,0 +1,1338 @@ +/******************************************************************************* + * Copyright (c) 2007 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.internal.merge; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.contentmergeviewer.ITokenComparator; +import org.eclipse.compare.internal.*; +import org.eclipse.compare.rangedifferencer.*; +import org.eclipse.compare.structuremergeviewer.Differencer; +import org.eclipse.core.runtime.*; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.IProgressService; + +/** + * A document merger manages the differences between two documents + * for either a 2-way or 3-way comparison. + * <p> + * This class should not have any UI dependencies. + */ +public class DocumentMerger { + + private static final String DIFF_RANGE_CATEGORY = CompareUIPlugin.PLUGIN_ID + ".DIFF_RANGE_CATEGORY"; //$NON-NLS-1$ + + /** Selects between smartTokenDiff and mergingTokenDiff */ + private static final boolean USE_MERGING_TOKEN_DIFF= false; + + /** if true copying conflicts from one side to other concatenates both sides */ + private static final boolean APPEND_CONFLICT= true; + + /** All diffs for calculating scrolling position (includes line ranges without changes) */ + private ArrayList fAllDiffs; + /** Subset of above: just real differences. */ + private ArrayList fChangeDiffs; + + private final boolean fLeftIsLocal; + + private IDocumentMergerInput fInput; + + public interface IDocumentMergerInput { + + IDocument getDocument(char contributor); + + Position getRegion(char contributor); + + boolean isIgnoreAncestor(); + + boolean isThreeWay(); + + CompareConfiguration getCompareConfiguration(); + + ITokenComparator createTokenComparator(String s); + + boolean isHunkOnLeft(); + + int getHunkStart(); + + boolean isPatchHunk(); + + boolean isShowPseudoConflicts(); + + } + + public class Diff { + /** character range in ancestor document */ + Position fAncestorPos; + /** character range in left document */ + Position fLeftPos; + /** character range in right document */ + Position fRightPos; + /** if this is a TokenDiff fParent points to the enclosing LineDiff */ + Diff fParent; + /** if Diff has been resolved */ + boolean fResolved; + int fDirection; + boolean fIsToken= false; + /** child token diffs */ + ArrayList fDiffs; + boolean fIsWhitespace= false; + + /* + * Create Diff from two ranges and an optional parent diff. + */ + Diff(Diff parent, int dir, IDocument ancestorDoc, Position aRange, int ancestorStart, int ancestorEnd, + IDocument leftDoc, Position lRange, int leftStart, int leftEnd, + IDocument rightDoc, Position rRange, int rightStart, int rightEnd) { + fParent= parent != null ? parent : this; + fDirection= dir; + + fLeftPos= createPosition(leftDoc, lRange, leftStart, leftEnd); + fRightPos= createPosition(rightDoc, rRange, rightStart, rightEnd); + if (ancestorDoc != null) + fAncestorPos= createPosition(ancestorDoc, aRange, ancestorStart, ancestorEnd); + } + + public Position getPosition(char type) { + switch (type) { + case MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR: + return fAncestorPos; + case MergeViewerContentProvider.LEFT_CONTRIBUTOR: + return fLeftPos; + case MergeViewerContentProvider.RIGHT_CONTRIBUTOR: + return fRightPos; + } + return null; + } + + boolean isInRange(char type, int pos) { + Position p= getPosition(type); + return (pos >= p.offset) && (pos < (p.offset+p.length)); + } + + public String changeType() { + boolean leftEmpty= fLeftPos.length == 0; + boolean rightEmpty= fRightPos.length == 0; + + if (fDirection == RangeDifference.LEFT) { + if (!leftEmpty && rightEmpty) + return CompareMessages.TextMergeViewer_changeType_addition; + if (leftEmpty && !rightEmpty) + return CompareMessages.TextMergeViewer_changeType_deletion; + } else { + if (leftEmpty && !rightEmpty) + return CompareMessages.TextMergeViewer_changeType_addition; + if (!leftEmpty && rightEmpty) + return CompareMessages.TextMergeViewer_changeType_deletion; + } + return CompareMessages.TextMergeViewer_changeType_change; + } + + public Image getImage() { + int code= Differencer.CHANGE; + switch (fDirection) { + case RangeDifference.RIGHT: + code+= Differencer.LEFT; + break; + case RangeDifference.LEFT: + code+= Differencer.RIGHT; + break; + case RangeDifference.ANCESTOR: + case RangeDifference.CONFLICT: + code+= Differencer.CONFLICTING; + break; + } + if (code != 0) + return getCompareConfiguration().getImage(code); + return null; + } + + Position createPosition(IDocument doc, Position range, int start, int end) { + try { + int l= end-start; + if (range != null) { + int dl= range.length; + if (l > dl) + l= dl; + } else { + int dl= doc.getLength(); + if (start+l > dl) + l= dl-start; + } + + Position p= null; + try { + p= new Position(start, l); + } catch (RuntimeException ex) { + p= new Position(0, 0); + } + + try { + doc.addPosition(DIFF_RANGE_CATEGORY, p); + } catch (BadPositionCategoryException ex) { + // silently ignored + } + return p; + } catch (BadLocationException ee) { + // silently ignored + } + return null; + } + + void add(Diff d) { + if (fDiffs == null) + fDiffs= new ArrayList(); + fDiffs.add(d); + } + + public boolean isDeleted() { + if (fAncestorPos != null && fAncestorPos.isDeleted()) + return true; + return fLeftPos.isDeleted() || fRightPos.isDeleted(); + } + + void setResolved(boolean r) { + fResolved= r; + if (r) + fDiffs= null; + } + + public boolean isResolved() { + if (!fResolved && fDiffs != null) { + Iterator e= fDiffs.iterator(); + while (e.hasNext()) { + Diff d= (Diff) e.next(); + if (!d.isResolved()) + return false; + } + return true; + } + return fResolved; + } + +// private boolean isIncoming() { +// switch (fDirection) { +// case RangeDifference.RIGHT: +// if (fLeftIsLocal) +// return true; +// break; +// case RangeDifference.LEFT: +// if (!fLeftIsLocal) +// return true; +// break; +// } +// return false; +// } + + public boolean isIncomingOrConflicting() { + switch (fDirection) { + case RangeDifference.RIGHT: + if (fLeftIsLocal) + return true; + break; + case RangeDifference.LEFT: + if (!fLeftIsLocal) + return true; + break; + case RangeDifference.CONFLICT: + return true; + } + return false; + } + +// private boolean isUnresolvedIncoming() { +// if (fResolved) +// return false; +// return isIncoming(); +// } + + public boolean isUnresolvedIncomingOrConflicting() { + if (fResolved) + return false; + return isIncomingOrConflicting(); + } + + Position getPosition(int contributor) { + if (contributor == MergeViewerContentProvider.LEFT_CONTRIBUTOR) + return fLeftPos; + if (contributor == MergeViewerContentProvider.RIGHT_CONTRIBUTOR) + return fRightPos; + if (contributor == MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR) + return fAncestorPos; + return null; + } + + /* + * Returns true if given character range overlaps with this Diff. + */ + public boolean overlaps(int contributor, int start, int end) { + Position h= getPosition(contributor); + if (h != null) { + int ds= h.getOffset(); + int de= ds + h.getLength(); + if ((start < de) && (end >= ds)) + return true; + } + return false; + } + + public int getMaxDiffHeight() { + Point region= new Point(0, 0); + int h= getLineRange(getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR), fLeftPos, region).y; + if (isThreeWay()) + h= Math.max(h, getLineRange(getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR), fAncestorPos, region).y); + return Math.max(h, getLineRange(getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR), fRightPos, region).y); + } + + public int getAncestorHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR), fAncestorPos, region).y; + } + + public int getLeftHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR), fLeftPos, region).y; + } + + public int getRightHeight() { + Point region= new Point(0, 0); + return getLineRange(getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR), fRightPos, region).y; + } + + public Diff[] getChangeDiffs(int contributor, IRegion region) { + if (fDiffs != null && intersectsRegion(contributor, region)) { + List result = new ArrayList(); + for (Iterator iterator = fDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff.intersectsRegion(contributor, region)) { + result.add(diff); + } + } + return (Diff[]) result.toArray(new Diff[result.size()]); + } + return new Diff[0]; + } + + private boolean intersectsRegion(int contributor, IRegion region) { + Position p = getPosition(contributor); + if (p != null) + return p.overlapsWith(region.getOffset(), region.getLength()); + return false; + } + + public boolean hasChildren() { + return fDiffs != null && !fDiffs.isEmpty(); + } + + public int getKind() { + return fDirection; + } + + public boolean isToken() { + return fIsToken; + } + + public Diff getParent() { + return fParent; + } + + public Iterator childIterator() { + if (fDiffs == null) + return new ArrayList().iterator(); + return fDiffs.iterator(); + } + } + + public DocumentMerger(IDocumentMergerInput input) { + this.fInput = input; + fLeftIsLocal= Utilities.getBoolean(getCompareConfiguration(), "LEFT_IS_LOCAL", false); //$NON-NLS-1$ + } + + /** + * Perform a two level 2- or 3-way diff. + * The first level is based on line comparison, the second level on token comparison. + * @throws CoreException + */ + public void doDiff() throws CoreException { + + fChangeDiffs= new ArrayList(); + IDocument lDoc = getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + IDocument rDoc = getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + + if (lDoc == null || rDoc == null) + return; + + Position lRegion= getRegion(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + Position rRegion= getRegion(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + + IDocument aDoc = null; + Position aRegion= null; + if (isThreeWay() && !isIgnoreAncestor()) { + aDoc= getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + aRegion= getRegion(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + } + + resetPositions(lDoc); + resetPositions(rDoc); + resetPositions(aDoc); + + boolean ignoreWhiteSpace= isIgnoreWhitespace(); + + DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); + DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); + DocLineComparator sancestor= null; + if (aDoc != null) { + sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + if (isPatchHunk()) { + if (isHunkOnLeft()) { + sright= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + } else { + sleft= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + } + } + } + + final Object[] result= new Object[1]; + final DocLineComparator sa= sancestor, sl= sleft, sr= sright; + IRunnableWithProgress runnable= new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { + monitor.beginTask("Computing Differences...", maxWork(sa, sl, sr)); + try { + result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); + } catch (OutOfMemoryError ex) { + System.gc(); + throw new InvocationTargetException(ex); + } + if (monitor.isCanceled()) { // canceled + throw new InterruptedException(); + } + monitor.done(); + } + }; + + RangeDifference[] e= null; + try { + getCompareConfiguration().getContainer().run(true, true, runnable); + e= (RangeDifference[]) result[0]; + } catch (InvocationTargetException ex) { + // we create a NOCHANGE range for the whole document + Diff diff= new Diff(null, RangeDifference.NOCHANGE, + aDoc, aRegion, 0, aDoc != null ? aDoc.getLength() : 0, + lDoc, lRegion, 0, lDoc.getLength(), + rDoc, rRegion, 0, rDoc.getLength()); + + fAllDiffs = new ArrayList(); + fAllDiffs.add(diff); + throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, "Too many differences found", ex.getTargetException())); + } catch (InterruptedException ex) { + // + } + + ArrayList newAllDiffs = new ArrayList(); + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + + int ancestorStart= 0; + int ancestorEnd= 0; + if (sancestor != null) { + ancestorStart= sancestor.getTokenStart(es.ancestorStart()); + ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart= sleft.getTokenStart(es.leftStart()); + int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); + + int rightStart= sright.getTokenStart(es.rightStart()); + int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); + + if (isPatchHunk()) { + if (isHunkOnLeft()) { + rightStart = rightEnd = getHunkStart(); + } else { + leftStart = leftEnd = getHunkStart(); + } + } + + Diff diff= new Diff(null, es.kind(), + aDoc, aRegion, ancestorStart, ancestorEnd, + lDoc, lRegion, leftStart, leftEnd, + rDoc, rRegion, rightStart, rightEnd); + + newAllDiffs.add(diff); // remember all range diffs for scrolling + + if (isPatchHunk()) { + if (useChange(diff)) { + recordChangeDiff(diff); + } + } else { + if (ignoreWhiteSpace || useChange(es.kind())) { + + // Extract the string for each contributor. + String a= null; + if (sancestor != null) + a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); + String s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); + String d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); + + // Indicate whether all contributors are whitespace + if (ignoreWhiteSpace + && (a == null || a.trim().length() == 0) + && s.trim().length() == 0 + && d.trim().length() == 0) { + diff.fIsWhitespace= true; + } + + // If the diff is of interest, record it and generate the token diffs + if (useChange(diff)) { + recordChangeDiff(diff); + if (s.length() > 0 && d.length() > 0) { + if (a == null && sancestor != null) + a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); + if (USE_MERGING_TOKEN_DIFF) + mergingTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); + else + simpleTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); + } + } + } + } + } + fAllDiffs = newAllDiffs; + } + + public Diff findDiff(char type, int pos) throws CoreException { + + IDocument aDoc= null; + IDocument lDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + IDocument rDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + if (lDoc == null || rDoc == null) + return null; + + Position aRegion= null; + Position lRegion= null; + Position rRegion= null; + + boolean threeWay= isThreeWay(); + + if (threeWay && !isIgnoreAncestor()) + aDoc= getDocument(MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR); + + boolean ignoreWhiteSpace= isIgnoreWhitespace(); + + DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); + DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); + DocLineComparator sancestor= null; + if (aDoc != null) + sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); + + final Object[] result= new Object[1]; + final DocLineComparator sa= sancestor, sl= sleft, sr= sright; + IRunnableWithProgress runnable= new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { + monitor.beginTask("Finding Differences...", maxWork(sa, sl, sr)); + try { + result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); + } catch (OutOfMemoryError ex) { + System.gc(); + throw new InvocationTargetException(ex); + } + if (monitor.isCanceled()) { // canceled + throw new InterruptedException(); + } + monitor.done(); + } + }; + IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); + + RangeDifference[] e= null; + try { + progressService.run(true, true, runnable); + e= (RangeDifference[]) result[0]; + } catch (InvocationTargetException ex) { + throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, "Too many differences found", ex.getTargetException())); + } catch (InterruptedException ex) { + // + } + + if (e != null) { + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + + int kind= es.kind(); + + int ancestorStart= 0; + int ancestorEnd= 0; + if (sancestor != null) { + ancestorStart= sancestor.getTokenStart(es.ancestorStart()); + ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart= sleft.getTokenStart(es.leftStart()); + int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); + + int rightStart= sright.getTokenStart(es.rightStart()); + int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); + + Diff diff= new Diff(null, kind, + aDoc, aRegion, ancestorStart, ancestorEnd, + lDoc, lRegion, leftStart, leftEnd, + rDoc, rRegion, rightStart, rightEnd); + + if (diff.isInRange(type, pos)) + return diff; + } + } + + return null; + } + + private void recordChangeDiff(Diff diff) { + fChangeDiffs.add(diff); // here we remember only the real diffs + } + + private boolean isHunkOnLeft() { + return fInput.isHunkOnLeft(); + } + + private int getHunkStart() { + return fInput.getHunkStart(); + } + + private boolean isPatchHunk() { + return fInput.isPatchHunk(); + } + + private boolean isIgnoreWhitespace() { + return Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); + } + + private IDocument getDocument(char contributor) { + return fInput.getDocument(contributor); + } + + private Position getRegion(char contributor) { + return fInput.getRegion(contributor); + } + + public boolean isIgnoreAncestor() { + return fInput.isIgnoreAncestor(); + } + + public boolean isThreeWay() { + return fInput.isThreeWay(); + } + + /** + * Return the compare configuration associated with this merger. + * @return the compare configuration associated with this merger + */ + public CompareConfiguration getCompareConfiguration() { + return fInput.getCompareConfiguration(); + } + + /* + * Returns true if kind of change should be shown. + */ + public boolean useChange(Diff diff) { + if (diff.fIsWhitespace) + return false; + int kind = diff.getKind(); + return useChange(kind); + } + + private boolean useChange(int kind) { + if (kind == RangeDifference.NOCHANGE) + return false; + if (kind == RangeDifference.ANCESTOR) + return fInput.isShowPseudoConflicts(); + return true; + } + + private int getTokenEnd(ITokenComparator tc, int start, int count) { + if (count <= 0) + return tc.getTokenStart(start); + int index= start + count - 1; + return tc.getTokenStart(index) + tc.getTokenLength(index); + } + + private static int getTokenEnd2(ITokenComparator tc, int start, int length) { + return tc.getTokenStart(start + length); + } + + /** + * Returns the content of lines in the specified range as a String. + * This includes the line separators. + * + * @param doc the document from which to extract the characters + * @param start index of first line + * @param length number of lines + * @return the contents of the specified line range as a String + */ + private String extract2(IDocument doc, ITokenComparator tc, int start, int length) { + int count= tc.getRangeCount(); + if (length > 0 && count > 0) { + +// +// int startPos= tc.getTokenStart(start); +// int endPos= startPos; +// +// if (length > 1) +// endPos= tc.getTokenStart(start + (length-1)); +// endPos+= tc.getTokenLength(start + (length-1)); +// + + int startPos= tc.getTokenStart(start); + int endPos; + + if (length == 1) { + endPos= startPos + tc.getTokenLength(start); + } else { + endPos= tc.getTokenStart(start + length); + } + + try { + return doc.get(startPos, endPos - startPos); + } catch (BadLocationException e) { + // silently ignored + } + + } + return ""; //$NON-NLS-1$ + } + + private static IRegion toRegion(Position position) { + if (position != null) + return new Region(position.getOffset(), position.getLength()); + return null; + } + + /* + * Performs a "smart" token based 3-way diff on the character range specified by the given baseDiff. + * It is "smart" because it tries to minimize the number of token diffs by merging them. + */ + private void mergingTokenDiff(Diff baseDiff, + IDocument ancestorDoc, String a, + IDocument rightDoc, String d, + IDocument leftDoc, String s) { + ITokenComparator sa= null; + int ancestorStart= 0; + if (ancestorDoc != null) { + sa= createTokenComparator(a); + ancestorStart= baseDiff.fAncestorPos.getOffset(); + } + + int rightStart= baseDiff.fRightPos.getOffset(); + ITokenComparator sm= createTokenComparator(d); + + int leftStart= baseDiff.fLeftPos.getOffset(); + ITokenComparator sy= createTokenComparator(s); + + RangeDifference[] r= RangeDifferencer.findRanges(sa, sy, sm); + for (int i= 0; i < r.length; i++) { + RangeDifference es= r[i]; + // determine range of diffs in one line + int start= i; + int leftLine= -1; + int rightLine= -1; + try { + leftLine= leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart())); + rightLine= rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart())); + } catch (BadLocationException e) { + // silently ignored + } + i++; + for (; i < r.length; i++) { + es= r[i]; + try { + if (leftLine != leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart()))) + break; + if (rightLine != rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart()))) + break; + } catch (BadLocationException e) { + // silently ignored + } + } + int end= i; + + // find first diff from left + RangeDifference first= null; + for (int ii= start; ii < end; ii++) { + es= r[ii]; + if (useChange(es.kind())) { + first= es; + break; + } + } + + // find first diff from mine + RangeDifference last= null; + for (int ii= end-1; ii >= start; ii--) { + es= r[ii]; + if (useChange(es.kind())) { + last= es; + break; + } + } + + if (first != null && last != null) { + + int ancestorStart2= 0; + int ancestorEnd2= 0; + if (ancestorDoc != null) { + ancestorStart2= ancestorStart+sa.getTokenStart(first.ancestorStart()); + ancestorEnd2= ancestorStart+getTokenEnd(sa, last.ancestorStart(), last.ancestorLength()); + } + + int leftStart2= leftStart+sy.getTokenStart(first.leftStart()); + int leftEnd2= leftStart+getTokenEnd(sy, last.leftStart(), last.leftLength()); + + int rightStart2= rightStart+sm.getTokenStart(first.rightStart()); + int rightEnd2= rightStart+getTokenEnd(sm, last.rightStart(), last.rightLength()); + Diff diff= new Diff(baseDiff, first.kind(), + ancestorDoc, null, ancestorStart2, ancestorEnd2, + leftDoc, null, leftStart2, leftEnd2, + rightDoc, null, rightStart2, rightEnd2); + diff.fIsToken= true; + baseDiff.add(diff); + } + } + } + + /* + * Performs a token based 3-way diff on the character range specified by the given baseDiff. + */ + private void simpleTokenDiff(final Diff baseDiff, + IDocument ancestorDoc, String a, + IDocument rightDoc, String d, + IDocument leftDoc, String s) { + + int ancestorStart= 0; + ITokenComparator sa= null; + if (ancestorDoc != null) { + ancestorStart= baseDiff.fAncestorPos.getOffset(); + sa= createTokenComparator(a); + } + + int rightStart= baseDiff.fRightPos.getOffset(); + ITokenComparator sm= createTokenComparator(d); + + int leftStart= baseDiff.fLeftPos.getOffset(); + ITokenComparator sy= createTokenComparator(s); + + RangeDifference[] e= RangeDifferencer.findRanges(sa, sy, sm); + for (int i= 0; i < e.length; i++) { + RangeDifference es= e[i]; + int kind= es.kind(); + if (kind != RangeDifference.NOCHANGE) { + + int ancestorStart2= ancestorStart; + int ancestorEnd2= ancestorStart; + if (ancestorDoc != null) { + ancestorStart2 += sa.getTokenStart(es.ancestorStart()); + ancestorEnd2 += getTokenEnd(sa, es.ancestorStart(), es.ancestorLength()); + } + + int leftStart2= leftStart + sy.getTokenStart(es.leftStart()); + int leftEnd2= leftStart + getTokenEnd(sy, es.leftStart(), es.leftLength()); + + int rightStart2= rightStart + sm.getTokenStart(es.rightStart()); + int rightEnd2= rightStart + getTokenEnd(sm, es.rightStart(), es.rightLength()); + + Diff diff= new Diff(baseDiff, kind, + ancestorDoc, null, ancestorStart2, ancestorEnd2, + leftDoc, null, leftStart2, leftEnd2, + rightDoc, null, rightStart2, rightEnd2); + + // ensure that token diff is smaller than basediff + int leftS= baseDiff.fLeftPos.offset; + int leftE= baseDiff.fLeftPos.offset+baseDiff.fLeftPos.length; + int rightS= baseDiff.fRightPos.offset; + int rightE= baseDiff.fRightPos.offset+baseDiff.fRightPos.length; + if (leftS != leftStart2 || leftE != leftEnd2 || + rightS != rightStart2 || rightE != rightEnd2) { + diff.fIsToken= true; + // add to base Diff + baseDiff.add(diff); + } + } + } + } + + private ITokenComparator createTokenComparator(String s) { + return fInput.createTokenComparator(s); + } + + private static int maxWork(IRangeComparator a, IRangeComparator l, IRangeComparator r) { + int ln= l.getRangeCount(); + int rn= r.getRangeCount(); + if (a != null) { + int an= a.getRangeCount(); + return (2 * Math.max(an, ln)) + (2 * Math.max(an, rn)); + } + return 2 * Math.max(ln, rn); + } + + private void resetPositions(IDocument doc) { + if (doc == null) + return; + try { + doc.removePositionCategory(DIFF_RANGE_CATEGORY); + } catch (BadPositionCategoryException e) { + // Ignore + } + doc.addPositionCategory(DIFF_RANGE_CATEGORY); + } + + /* + * Returns the start line and the number of lines which correspond to the given position. + * Starting line number is 0 based. + */ + protected Point getLineRange(IDocument doc, Position p, Point region) { + + if (p == null || doc == null) { + region.x= 0; + region.y= 0; + return region; + } + + int start= p.getOffset(); + int length= p.getLength(); + + int startLine= 0; + try { + startLine= doc.getLineOfOffset(start); + } catch (BadLocationException e) { + // silently ignored + } + + int lineCount= 0; + + if (length == 0) { +// // if range length is 0 and if range starts a new line +// try { +// if (start == doc.getLineStartOffset(startLine)) { +// lines--; +// } +// } catch (BadLocationException e) { +// lines--; +// } + + } else { + int endLine= 0; + try { + endLine= doc.getLineOfOffset(start + length - 1); // why -1? + } catch (BadLocationException e) { + // silently ignored + } + lineCount= endLine-startLine+1; + } + + region.x= startLine; + region.y= lineCount; + return region; + } + + public Diff findDiff(Position p, boolean left) { + for (Iterator iterator = fAllDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + Position diffPos; + if (left) { + diffPos = diff.fLeftPos; + } else { + diffPos = diff.fRightPos; + } + // If the element falls within a diff, highlight that diff + if (diffPos.offset + diffPos.length >= p.offset && diff.fDirection != RangeDifference.NOCHANGE) + return diff; + // Otherwise, highlight the first diff after the elements position + if (diffPos.offset >= p.offset) + return diff; + } + return null; + } + + public void reset() { + fChangeDiffs= null; + fAllDiffs= null; + } + + /** + * Returns the virtual position for the given view position. + * @param contributor + * @param vpos + * @return the virtual position for the given view position + */ + public int realToVirtualPosition(char contributor, int vpos) { + + if (fAllDiffs == null) + return vpos; + + int viewPos= 0; // real view position + int virtualPos= 0; // virtual position + Point region= new Point(0, 0); + + Iterator e= fAllDiffs.iterator(); + while (e.hasNext()) { + Diff diff= (Diff) e.next(); + Position pos= diff.getPosition(contributor); + getLineRange(getDocument(contributor),pos, region); + int realHeight= region.y; + int virtualHeight= diff.getMaxDiffHeight(); + if (vpos <= viewPos + realHeight) { // OK, found! + vpos-= viewPos; // make relative to this slot + // now scale position within this slot to virtual slot + if (realHeight <= 0) + vpos= 0; + else + vpos= (vpos*virtualHeight)/realHeight; + return virtualPos+vpos; + } + viewPos+= realHeight; + virtualPos+= virtualHeight; + } + return virtualPos; + } + + /** + * maps given virtual position into a real view position of this view. + * @param contributor + * @param v + * @return the real view position + */ + public int virtualToRealPosition(char contributor, int v) { + + if (fAllDiffs == null) + return v; + + int virtualPos= 0; + int viewPos= 0; + Point region= new Point(0, 0); + + Iterator e= fAllDiffs.iterator(); + while (e.hasNext()) { + Diff diff= (Diff) e.next(); + Position pos= diff.getPosition(contributor); + int viewHeight= getLineRange(getDocument(contributor), pos, region).y; + int virtualHeight= diff.getMaxDiffHeight(); + if (v < (virtualPos + virtualHeight)) { + v-= virtualPos; // make relative to this slot + if (viewHeight <= 0) { + v= 0; + } else { + v= (int) (v * ((double)viewHeight/virtualHeight)); + } + return viewPos+v; + } + virtualPos+= virtualHeight; + viewPos+= viewHeight; + } + return viewPos; + } + + /* + * Calculates virtual height (in lines) of views by adding the maximum of corresponding diffs. + */ + public int getVirtualHeight() { + int h= 1; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + h+= diff.getMaxDiffHeight(); + } + } + return h; + } + + /* + * Calculates height (in lines) of right view by adding the height of the right diffs. + */ + public int getRightHeight() { + int h= 1; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + h+= diff.getRightHeight(); + } + } + return h; + } + + public int findInsertionPoint(Diff diff, char type) { + if (diff != null) { + switch (type) { + case MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR: + if (diff.fAncestorPos != null) + return diff.fAncestorPos.offset; + break; + case MergeViewerContentProvider.LEFT_CONTRIBUTOR: + if (diff.fLeftPos != null) + return diff.fLeftPos.offset; + break; + case MergeViewerContentProvider.RIGHT_CONTRIBUTOR: + if (diff.fRightPos != null) + return diff.fRightPos.offset; + break; + } + } + return 0; + } + + public Diff[] getChangeDiffs(char contributor, IRegion region) { + if (fChangeDiffs == null) + return new Diff[0]; + List intersectingDiffs = new ArrayList(); + for (Iterator iterator = fChangeDiffs.iterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + Diff[] changeDiffs = diff.getChangeDiffs(contributor, region); + for (int i = 0; i < changeDiffs.length; i++) { + Diff changeDiff = changeDiffs[i]; + intersectingDiffs.add(changeDiff); + } + } + return (Diff[]) intersectingDiffs.toArray(new Diff[intersectingDiffs.size()]); + } + + public Diff findDiff(int viewportHeight, boolean synchronizedScrolling, Point size, int my) { + int virtualHeight= synchronizedScrolling ? getVirtualHeight() : getRightHeight(); + if (virtualHeight < viewportHeight) + return null; + + int yy, hh; + int y= 0; + if (fAllDiffs != null) { + Iterator e= fAllDiffs.iterator(); + for (int i= 0; e.hasNext(); i++) { + Diff diff= (Diff) e.next(); + int h= synchronizedScrolling ? diff.getMaxDiffHeight() + : diff.getRightHeight(); + if (useChange(diff.getKind()) && !diff.fIsWhitespace) { + + yy= (y*size.y)/virtualHeight; + hh= (h*size.y)/virtualHeight; + if (hh < 3) + hh= 3; + + if (my >= yy && my < yy+hh) + return diff; + } + y+= h; + } + } + return null; + } + + public boolean hasChanges() { + return fChangeDiffs != null && !fChangeDiffs.isEmpty(); + } + + public Iterator changesIterator() { + if (fChangeDiffs == null) + return new ArrayList().iterator(); + return fChangeDiffs.iterator(); + } + + public Iterator rangesIterator() { + if (fAllDiffs == null) + return new ArrayList().iterator(); + return fAllDiffs.iterator(); + } + + public boolean isFirstChildDiff(char contributor, int startOffset, + Diff diff) { + if (!diff.hasChildren()) + return false; + Diff d = (Diff)diff.fDiffs.get(0); + Position p= d.getPosition(contributor); + return (p.getOffset() >= startOffset); + } + + public Diff getWrappedDiff(Diff diff, boolean down) { + if (fChangeDiffs != null && fChangeDiffs.size() > 0) { + if (down) + return (Diff) fChangeDiffs.get(0); + return (Diff) fChangeDiffs.get(fChangeDiffs.size()-1); + } + return null; + } + + /* + * Copy the contents of the given diff from one side to the other but + * doesn't reveal anything. + * Returns true if copy was successful. + */ + public boolean copy(Diff diff, boolean leftToRight) { + + if (diff != null && !diff.isResolved()) { + Position fromPos= null; + Position toPos= null; + IDocument fromDoc= null; + IDocument toDoc= null; + + if (leftToRight) { + fromPos= diff.getPosition(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + toPos= diff.getPosition(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + fromDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + toDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + } else { + fromPos= diff.getPosition(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + toPos= diff.getPosition(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + fromDoc= getDocument(MergeViewerContentProvider.RIGHT_CONTRIBUTOR); + toDoc= getDocument(MergeViewerContentProvider.LEFT_CONTRIBUTOR); + } + + if (fromDoc != null) { + + int fromStart= fromPos.getOffset(); + int fromLen= fromPos.getLength(); + + int toStart= toPos.getOffset(); + int toLen= toPos.getLength(); + + try { + String s= null; + + switch (diff.getKind()) { + case RangeDifference.RIGHT: + case RangeDifference.LEFT: + s= fromDoc.get(fromStart, fromLen); + break; + case RangeDifference.ANCESTOR: + break; + case RangeDifference.CONFLICT: + if (APPEND_CONFLICT) { + s= toDoc.get(toStart, toLen); + s+= fromDoc.get(fromStart, fromLen); + } else + s= fromDoc.get(fromStart, fromLen); + break; + } + if (s != null) { + toDoc.replace(toStart, toLen, s); + toPos.setOffset(toStart); + toPos.setLength(s.length()); + } + + } catch (BadLocationException e) { + // silently ignored + } + } + + diff.setResolved(true); + return true; + } + return false; + } + + public int changesCount() { + if (fChangeDiffs == null) + return 0; + return fChangeDiffs.size(); + } + + public Diff findDiff(char contributor, int rangeStart, int rangeEnd) { + if (hasChanges()) { + for (Iterator iterator = changesIterator(); iterator.hasNext();) { + Diff diff = (Diff) iterator.next(); + if (diff.isDeleted() || diff.getKind() == RangeDifference.NOCHANGE) + continue; + if (diff.overlaps(contributor, rangeStart, rangeEnd)) + return diff; + } + } + return null; + } + + public Diff findDiff(char contributor, Position range) { + int start= range.getOffset(); + int end= start + range.getLength(); + return findDiff(contributor, start, end); + } + + public Diff findNext(char contributor, int start, int end, boolean deep) { + return findNext(contributor, fChangeDiffs, start, end, deep); + } + + private Diff findNext(char contributor, List v, int start, int end, boolean deep) { + if (v == null) + return null; + for (int i= 0; i < v.size(); i++) { + Diff diff= (Diff) v.get(i); + Position p= diff.getPosition(contributor); + if (p != null) { + int startOffset= p.getOffset(); + if (end < startOffset) // <= + return diff; + if (deep && diff.hasChildren()) { + Diff d= null; + int endOffset= startOffset + p.getLength(); + if (start == startOffset && (end == endOffset || end == endOffset-1)) { + d= findNext(contributor, diff.fDiffs, start-1, start-1, deep); + } else if (end < endOffset) { + d= findNext(contributor, diff.fDiffs, start, end, deep); + } + if (d != null) + return d; + } + } + } + return null; + } + + public Diff findPrev(char contributor, int start, int end, boolean deep) { + return findPrev(contributor, fChangeDiffs, start, end, deep); + } + + private Diff findPrev(char contributor, List v, int start, int end, boolean deep) { + if (v == null) + return null; + for (int i= v.size()-1; i >= 0; i--) { + Diff diff= (Diff) v.get(i); + Position p= diff.getPosition(contributor); + if (p != null) { + int startOffset= p.getOffset(); + int endOffset= startOffset + p.getLength(); + if (start > endOffset) { + if (deep && diff.hasChildren()) { + // If we are going deep, find the last change in the diff + return findPrev(contributor, diff.fDiffs, end, end, deep); + } + return diff; + } + if (deep && diff.hasChildren()) { + Diff d= null; + if (start == startOffset && end == endOffset) { + // A whole diff is selected so we'll fall through + // and go the the last change in the previous diff + } else if (start >= startOffset) { + // If we are at or before the first diff, select the + // entire diff so next and previous are symmetrical + if (isFirstChildDiff(contributor, startOffset, diff)) { + return diff; + } + d= findPrev(contributor, diff.fDiffs, start, end, deep); + } + if (d != null) + return d; + } + } + } + return null; + } + +} |