diff --git a/src/org/gsoft/showcase/diff/gui/Colors.java b/src/org/gsoft/showcase/diff/gui/Colors.java new file mode 100644 index 0000000..d937a2b --- /dev/null +++ b/src/org/gsoft/showcase/diff/gui/Colors.java @@ -0,0 +1,14 @@ +package org.gsoft.showcase.diff.gui; + +import java.awt.*; + +public final class Colors { + public static final Color DELETED_LINES_HIGHLIGHT_COLOR = new Color(250, 180, 170); + public static final Color INSERTED_LINES_HIGHLIGHT_COLOR = new Color(174, 255, 202); + public static final Color MODIFIED_LINES_HIGHLIGHT_COLOR = new Color(221, 226, 255); + public static final Color MODIFIED_CHARS_HIGHLIGHT_COLOR = new Color(187, 211, 255); + + private Colors() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/gsoft/showcase/diff/gui/components/DiffMatchingImagePanel.java b/src/org/gsoft/showcase/diff/gui/components/DiffMatchingImagePanel.java index d968540..691c959 100644 --- a/src/org/gsoft/showcase/diff/gui/components/DiffMatchingImagePanel.java +++ b/src/org/gsoft/showcase/diff/gui/components/DiffMatchingImagePanel.java @@ -1,11 +1,13 @@ package org.gsoft.showcase.diff.gui.components; -import org.gsoft.showcase.diff.gui.forms.DiffForm; +import org.gsoft.showcase.diff.gui.logic.DiffItemPosition; import javax.swing.*; import java.awt.*; import java.util.List; +import static org.gsoft.showcase.diff.gui.Colors.*; + public class DiffMatchingImagePanel extends JPanel { private static final int TOP_PADDING = 2; // TODO calculate this @@ -16,7 +18,7 @@ public class DiffMatchingImagePanel extends JPanel { // // TODO use dedicated type to avoid confusion // - private List itemPositions; + private List itemPositions; public DiffMatchingImagePanel() { super(new BorderLayout()); @@ -38,7 +40,7 @@ public void paint(Graphics g) { return; } - for (DiffPanesScrollController.DiffItemPosition itemPosition : itemPositions) { + for (DiffItemPosition itemPosition : itemPositions) { int[] xs, ys; switch (itemPosition.getType()) { @@ -49,21 +51,21 @@ public void paint(Graphics g) { xs = new int[] { 0, getWidth(), getWidth(), 0}; ys = new int[] { itemPosition.getStartA() + TOP_PADDING, itemPosition.getStartB() + TOP_PADDING, itemPosition.getEndB() + TOP_PADDING, itemPosition.getEndA() + TOP_PADDING}; - g.setColor(DiffForm.MODIFIED_LINES_HIGHLIGHT_COLOR); + g.setColor(MODIFIED_LINES_HIGHLIGHT_COLOR); break; case INSERT: xs = new int[] { 0, getWidth(), getWidth()}; ys = new int[] { itemPosition.getStartA() + TOP_PADDING, itemPosition.getStartB() + TOP_PADDING, itemPosition.getEndB() + TOP_PADDING}; - g.setColor(DiffForm.INSERTED_LINES_HIGHLIGHT_COLOR); + g.setColor(INSERTED_LINES_HIGHLIGHT_COLOR); break; case DELETE: xs = new int[] { 0, getWidth(), 0}; ys = new int[] { itemPosition.getStartA() + TOP_PADDING, itemPosition.getStartB() + TOP_PADDING, itemPosition.getEndA() + TOP_PADDING}; - g.setColor(DiffForm.DELETED_LINES_HIGHLIGHT_COLOR); + g.setColor(DELETED_LINES_HIGHLIGHT_COLOR); break; default: @@ -74,11 +76,11 @@ public void paint(Graphics g) { } } - public List getItemPositions() { + public List getItemPositions() { return itemPositions; } - public void setItemPositions(List itemPositions) { + public void setItemPositions(List itemPositions) { this.itemPositions = itemPositions; } } diff --git a/src/org/gsoft/showcase/diff/gui/components/DiffPanesScrollController.java b/src/org/gsoft/showcase/diff/gui/components/DiffPanesScrollController.java index 20adf10..0eacc30 100644 --- a/src/org/gsoft/showcase/diff/gui/components/DiffPanesScrollController.java +++ b/src/org/gsoft/showcase/diff/gui/components/DiffPanesScrollController.java @@ -1,6 +1,7 @@ package org.gsoft.showcase.diff.gui.components; -import org.gsoft.showcase.diff.gui.forms.DiffForm; +import org.gsoft.showcase.diff.gui.logic.DiffItemPosition; +import org.gsoft.showcase.diff.gui.logic.ExtendedDiffItemType; import javax.swing.*; import javax.swing.event.ChangeEvent; @@ -13,42 +14,6 @@ import java.util.List; public final class DiffPanesScrollController { - public static final class DiffItemPosition { - private final int startA, startB; - private final int endA, endB; - private final DiffForm.ExtendedDiffItemType type; - - public DiffItemPosition(int startA, int startB, - int endA, int endB, - DiffForm.ExtendedDiffItemType type) { - this.startA = startA; - this.startB = startB; - this.endA = endA; - this.endB = endB; - this.type = type; - } - - public int getStartA() { - return startA; - } - - public int getStartB() { - return startB; - } - - public int getEndA() { - return endA; - } - - public int getEndB() { - return endB; - } - - public DiffForm.ExtendedDiffItemType getType() { - return type; - } - } - private static final class LinkedScrollRange { final int startThis; final int endThis; @@ -117,7 +82,7 @@ public void scrollToPreviousChange() { DiffItemPosition previousItem = diffItemPositions.get(currentDiffItemIndex - 1); - if (previousItem.type == DiffForm.ExtendedDiffItemType.EQUAL) { + if (previousItem.getType() == ExtendedDiffItemType.EQUAL) { if (currentDiffItemIndex == 1) { return; // no previous item } @@ -136,7 +101,7 @@ public void scrollToNextChange() { DiffItemPosition nextItem = diffItemPositions.get(currentDiffItemIndex + 1); - if (nextItem.type == DiffForm.ExtendedDiffItemType.EQUAL) { + if (nextItem.getType() == ExtendedDiffItemType.EQUAL) { if (currentDiffItemIndex == diffItemPositions.size() - 2) { return; // no next item } @@ -231,14 +196,14 @@ private void updateScrollRanges() throws BadLocationException { for (int i = 0; i < diffItemPositions.size(); i++) { DiffItemPosition item = diffItemPositions.get(i); - switch (item.type) { + switch (item.getType()) { case EQUAL: case MODIFIED: - Rectangle firstCharRectA = textAreaA.modelToView(item.startA); - Rectangle lastCharRectA = textAreaA.modelToView(item.endA); + Rectangle firstCharRectA = textAreaA.modelToView(item.getStartA()); + Rectangle lastCharRectA = textAreaA.modelToView(item.getEndA()); - Rectangle firstCharRectB = textAreaB.modelToView(item.startB); - Rectangle lastCharRectB = textAreaB.modelToView(item.endB); + Rectangle firstCharRectB = textAreaB.modelToView(item.getStartB()); + Rectangle lastCharRectB = textAreaB.modelToView(item.getEndB()); scrollRangesA.add(new LinkedScrollRange( firstCharRectA.getLocation().y, @@ -257,10 +222,10 @@ private void updateScrollRanges() throws BadLocationException { break; case DELETE: - firstCharRectA = textAreaA.modelToView(item.startA); - lastCharRectA = textAreaA.modelToView(item.endA); + firstCharRectA = textAreaA.modelToView(item.getStartA()); + lastCharRectA = textAreaA.modelToView(item.getEndA()); - firstCharRectB = textAreaB.modelToView(item.startB); + firstCharRectB = textAreaB.modelToView(item.getStartB()); scrollRangesA.add(new LinkedScrollRange( firstCharRectA.getLocation().y, @@ -272,10 +237,10 @@ private void updateScrollRanges() throws BadLocationException { break; case INSERT: - firstCharRectB = textAreaB.modelToView(item.startB); - lastCharRectB = textAreaB.modelToView(item.endB); + firstCharRectB = textAreaB.modelToView(item.getStartB()); + lastCharRectB = textAreaB.modelToView(item.getEndB()); - firstCharRectA = textAreaA.modelToView(item.startA); + firstCharRectA = textAreaA.modelToView(item.getStartA()); scrollRangesB.add(new LinkedScrollRange( firstCharRectB.getLocation().y, @@ -287,7 +252,7 @@ private void updateScrollRanges() throws BadLocationException { break; default: - throw new RuntimeException("unexpected diff item type: " + item.type); + throw new RuntimeException("unexpected diff item type: " + item.getType()); } } @@ -301,7 +266,7 @@ private void scrollLeftPaneToCurrentDiffItemPosition() { Rectangle rect; try { - rect = textAreaA.modelToView(diffItemPositions.get(currentDiffItemIndex).startA); + rect = textAreaA.modelToView(diffItemPositions.get(currentDiffItemIndex).getStartA()); } catch (BadLocationException e) { throw new RuntimeException(e); } @@ -340,14 +305,14 @@ private List getDiffItemPositionsInViewport() throws BadLocati for (int i = minItemIndex; i <= maxItemIndex; i++) { DiffItemPosition position = diffItemPositions.get(i); - Rectangle endARect = textAreaA.modelToView(position.endA); - Rectangle endBRect = textAreaB.modelToView(position.endB); + Rectangle endARect = textAreaA.modelToView(position.getEndA()); + Rectangle endBRect = textAreaB.modelToView(position.getEndB()); result.add(new DiffItemPosition( - textAreaA.modelToView(position.startA).y - viewportAPosition, - textAreaB.modelToView(position.startB).y - viewportBPosition, + textAreaA.modelToView(position.getStartA()).y - viewportAPosition, + textAreaB.modelToView(position.getStartB()).y - viewportBPosition, endARect.y + endARect.height - viewportAPosition, endBRect.y + endBRect.height - viewportBPosition, - position.type + position.getType() )); } diff --git a/src/org/gsoft/showcase/diff/gui/forms/DiffForm.java b/src/org/gsoft/showcase/diff/gui/forms/DiffForm.java index f150c90..d47ab67 100644 --- a/src/org/gsoft/showcase/diff/gui/forms/DiffForm.java +++ b/src/org/gsoft/showcase/diff/gui/forms/DiffForm.java @@ -3,12 +3,14 @@ import org.gsoft.showcase.diff.generators.DiffGeneratorUtils; import org.gsoft.showcase.diff.generators.DiffGeneratorUtils.LinesEncoding; import org.gsoft.showcase.diff.generators.DiffItem; -import org.gsoft.showcase.diff.generators.DiffItemType; import org.gsoft.showcase.diff.generators.impl.MyersDiffGenerator; import org.gsoft.showcase.diff.gui.components.DiffMatchingImagePanel; import org.gsoft.showcase.diff.gui.components.DiffPanesScrollController; import org.gsoft.showcase.diff.gui.components.InsertOrDeletePointHighlighter; import org.gsoft.showcase.diff.gui.components.WholeLineHighlightPainter; +import org.gsoft.showcase.diff.gui.logic.ByLineDiffItem; +import org.gsoft.showcase.diff.gui.logic.DiffItemPosition; +import org.gsoft.showcase.diff.gui.logic.ExtendedDiffItemType; import javax.swing.*; import javax.swing.text.BadLocationException; @@ -21,12 +23,9 @@ import java.util.List; import java.util.stream.Collectors; -public class DiffForm extends JFrame { - public static final Color DELETED_LINES_HIGHLIGHT_COLOR = new Color(250, 180, 170); - public static final Color INSERTED_LINES_HIGHLIGHT_COLOR = new Color(174, 255, 202); - public static final Color MODIFIED_LINES_HIGHLIGHT_COLOR = new Color(221, 226, 255); - public static final Color MODIFIED_CHARS_HIGHLIGHT_COLOR = new Color(187, 211, 255); +import static org.gsoft.showcase.diff.gui.Colors.*; +public class DiffForm extends JFrame { private static class TextPosition { final int start, end; @@ -36,32 +35,6 @@ private static class TextPosition { } } - /** - * Extends {@link DiffItemType} with MODIFIED item type. - */ - public enum ExtendedDiffItemType { - EQUAL, - INSERT, - DELETE, - MODIFIED - } - - /** - * TODO convert to type hierarchy - */ - private static final class ByLineDiffItem { - final ExtendedDiffItemType type; - final String[] strings; - final List byCharDiffItems; - - private ByLineDiffItem(ExtendedDiffItemType type, String[] strings, - List byCharDiffItems) { - this.type = type; - this.strings = strings; - this.byCharDiffItems = byCharDiffItems != null ? new ArrayList<>(byCharDiffItems) : null; - } - } - private final List diffItems; private JPanel rootPanel; @@ -88,7 +61,7 @@ public DiffForm(String fileAPath, String fileBPath, this.diffItems = convertByLineDiffItems(byLineDiffItems, linesEncoding); - List diffItemPositions; + List diffItemPositions; try { diffItemPositions = populateDiffAreas(); @@ -177,17 +150,17 @@ private List convertByLineDiffItems(List plainItems, private ByLineDiffItem createModifiedItem(ByLineDiffItem firstItem, ByLineDiffItem secondItem) { ByLineDiffItem deleteItem, insertItem; - if ((firstItem.type == ExtendedDiffItemType.DELETE) && (secondItem.type == ExtendedDiffItemType.INSERT)) { + if ((firstItem.getType() == ExtendedDiffItemType.DELETE) && (secondItem.getType() == ExtendedDiffItemType.INSERT)) { deleteItem = firstItem; insertItem = secondItem; - } else if ((firstItem.type == ExtendedDiffItemType.INSERT) && (secondItem.type == ExtendedDiffItemType.DELETE)) { + } else if ((firstItem.getType() == ExtendedDiffItemType.INSERT) && (secondItem.getType() == ExtendedDiffItemType.DELETE)) { deleteItem = secondItem; insertItem = firstItem; } else { throw new IllegalArgumentException("items must only be inserts or deletes!"); } - List byCharPlainItems = produceByCharDiff(deleteItem.strings, insertItem.strings); + List byCharPlainItems = produceByCharDiff(deleteItem.getStrings(), insertItem.getStrings()); return new ByLineDiffItem(ExtendedDiffItemType.MODIFIED, null, byCharPlainItems); } @@ -200,44 +173,44 @@ private List produceByCharDiff(String[] stringsA, String[] stringsB) { DiffGeneratorUtils.encodeString(a), DiffGeneratorUtils.encodeString(b)); } - private List populateDiffAreas() throws BadLocationException { + private List populateDiffAreas() throws BadLocationException { textAreaA = makeTextArea(); textAreaB = makeTextArea(); - List diffItemPositions = new ArrayList<>(); + List diffItemPositions = new ArrayList<>(); for (ByLineDiffItem item : diffItems) { - switch (item.type) { + switch (item.getType()) { case EQUAL: - TextPosition positionA = addLinesToTextArea(textAreaA, item.strings); - TextPosition positionB = addLinesToTextArea(textAreaB, item.strings); + TextPosition positionA = addLinesToTextArea(textAreaA, item.getStrings()); + TextPosition positionB = addLinesToTextArea(textAreaB, item.getStrings()); - diffItemPositions.add(new DiffPanesScrollController.DiffItemPosition( - positionA.start, positionB.start, positionA.end, positionB.end, item.type)); + diffItemPositions.add(new DiffItemPosition( + positionA.start, positionB.start, positionA.end, positionB.end, item.getType())); break; case DELETE: - positionA = addLinesToTextArea(textAreaA, item.strings); + positionA = addLinesToTextArea(textAreaA, item.getStrings()); int nextCharPositionB = textAreaB.getLineCount() != 0 ? textAreaB.getLineEndOffset(textAreaB.getLineCount() - 1) + 1 : 0; - diffItemPositions.add(new DiffPanesScrollController.DiffItemPosition( - positionA.start, nextCharPositionB, positionA.end, nextCharPositionB, item.type)); + diffItemPositions.add(new DiffItemPosition( + positionA.start, nextCharPositionB, positionA.end, nextCharPositionB, item.getType())); break; case INSERT: - positionB = addLinesToTextArea(textAreaB, item.strings); + positionB = addLinesToTextArea(textAreaB, item.getStrings()); int nextCharPositionA = textAreaA.getLineCount() != 0 ? textAreaA.getLineEndOffset(textAreaA.getLineCount() - 1) + 1 : 0; - diffItemPositions.add(new DiffPanesScrollController.DiffItemPosition( - nextCharPositionA, positionB.start, nextCharPositionA, positionB.end, item.type)); + diffItemPositions.add(new DiffItemPosition( + nextCharPositionA, positionB.start, nextCharPositionA, positionB.end, item.getType())); break; @@ -246,7 +219,7 @@ private List populateDiffAreas() thr break; default: - throw new RuntimeException("unexpected diff item type: " + item.type); + throw new RuntimeException("unexpected diff item type: " + item.getType()); } } @@ -255,7 +228,7 @@ private List populateDiffAreas() thr // doing it in a separate pass // for (int i = 0; i < diffItems.size(); i++) { - DiffPanesScrollController.DiffItemPosition itemPos = diffItemPositions.get(i); + DiffItemPosition itemPos = diffItemPositions.get(i); switch (itemPos.getType()) { case EQUAL: // no highlight necessary @@ -291,7 +264,7 @@ private List populateDiffAreas() thr return diffItemPositions; } - private void highlightByLineDiffItem(DiffPanesScrollController.DiffItemPosition item, + private void highlightByLineDiffItem(DiffItemPosition item, Highlighter.HighlightPainter highlightPainterA, Highlighter.HighlightPainter highlightPainterB) throws BadLocationException { @@ -301,7 +274,7 @@ private void highlightByLineDiffItem(DiffPanesScrollController.DiffItemPosition highlightPainterB); } - private DiffPanesScrollController.DiffItemPosition addModifiedLines(ByLineDiffItem modifiedItem) + private DiffItemPosition addModifiedLines(ByLineDiffItem modifiedItem) throws BadLocationException { int previousLineCountA = textAreaA.getLineCount(); if (previousLineCountA != 1) { @@ -313,7 +286,7 @@ private DiffPanesScrollController.DiffItemPosition addModifiedLines(ByLineDiffIt textAreaB.append("\n"); } - for (DiffItem byCharItem : modifiedItem.byCharDiffItems) { + for (DiffItem byCharItem : modifiedItem.getByCharDiffItems()) { String decodedString = DiffGeneratorUtils.decodeString(byCharItem.getChars()); switch (byCharItem.getType()) { case EQUAL: @@ -340,12 +313,12 @@ private DiffPanesScrollController.DiffItemPosition addModifiedLines(ByLineDiffIt TextPosition positionB = new TextPosition(textAreaB.getLineStartOffset(previousLineCountB), textAreaB.getLineEndOffset(textAreaB.getLineCount() - 1)); - return new DiffPanesScrollController.DiffItemPosition( + return new DiffItemPosition( positionA.start, positionB.start, positionA.end, positionB.end, ExtendedDiffItemType.MODIFIED); } - private void highlightByCharModifications(DiffPanesScrollController.DiffItemPosition position, + private void highlightByCharModifications(DiffItemPosition position, ByLineDiffItem modifiedItem) throws BadLocationException { int posB = position.getStartB(); @@ -355,7 +328,7 @@ private void highlightByCharModifications(DiffPanesScrollController.DiffItemPosi // int[] pendingHighlightPositions = null; - for (DiffItem byCharItem : modifiedItem.byCharDiffItems) { + for (DiffItem byCharItem : modifiedItem.getByCharDiffItems()) { switch (byCharItem.getType()) { case EQUAL: posB += byCharItem.getChars().length; diff --git a/src/org/gsoft/showcase/diff/gui/logic/ByLineDiffItem.java b/src/org/gsoft/showcase/diff/gui/logic/ByLineDiffItem.java new file mode 100644 index 0000000..4114897 --- /dev/null +++ b/src/org/gsoft/showcase/diff/gui/logic/ByLineDiffItem.java @@ -0,0 +1,58 @@ +package org.gsoft.showcase.diff.gui.logic; + +import org.gsoft.showcase.diff.generators.DiffItem; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Logically extends {@link DiffItem}. + * + * TODO convert to type hierarchy? + */ +public final class ByLineDiffItem { + private final ExtendedDiffItemType type; + + /** + * Not set for ExtendedDiffItemType.MODIFIED + */ + private final String[] strings; + + /** + * Only set for ExtendedDiffItemType.MODIFIED + */ + private final List byCharDiffItems; + + public ByLineDiffItem(ExtendedDiffItemType type, String[] strings, + List byCharDiffItems) { + if ((strings != null) && (type == ExtendedDiffItemType.MODIFIED)) { + throw new IllegalArgumentException("strings parameter is forbidden for MODIFIED items"); + } + if ((byCharDiffItems != null) && (type != ExtendedDiffItemType.MODIFIED)) { + throw new IllegalArgumentException("byCharDiffItems parameter is only allowed for MODIFIED items"); + } + + this.type = type; + this.strings = strings; + this.byCharDiffItems = byCharDiffItems != null ? new ArrayList<>(byCharDiffItems) : null; + } + + public ExtendedDiffItemType getType() { + return type; + } + + public String[] getStrings() { + if (strings == null) { + return null; + } + return strings.clone(); + } + + public List getByCharDiffItems() { + if (byCharDiffItems == null) { + return null; + } + return Collections.unmodifiableList(byCharDiffItems); + } +} diff --git a/src/org/gsoft/showcase/diff/gui/logic/DiffItemPosition.java b/src/org/gsoft/showcase/diff/gui/logic/DiffItemPosition.java new file mode 100644 index 0000000..8444604 --- /dev/null +++ b/src/org/gsoft/showcase/diff/gui/logic/DiffItemPosition.java @@ -0,0 +1,37 @@ +package org.gsoft.showcase.diff.gui.logic; + +public final class DiffItemPosition { + private final int startA, startB; + private final int endA, endB; + private final ExtendedDiffItemType type; + + public DiffItemPosition(int startA, int startB, + int endA, int endB, + ExtendedDiffItemType type) { + this.startA = startA; + this.startB = startB; + this.endA = endA; + this.endB = endB; + this.type = type; + } + + public int getStartA() { + return startA; + } + + public int getStartB() { + return startB; + } + + public int getEndA() { + return endA; + } + + public int getEndB() { + return endB; + } + + public ExtendedDiffItemType getType() { + return type; + } +} diff --git a/src/org/gsoft/showcase/diff/gui/logic/ExtendedDiffItemType.java b/src/org/gsoft/showcase/diff/gui/logic/ExtendedDiffItemType.java new file mode 100644 index 0000000..3e5da46 --- /dev/null +++ b/src/org/gsoft/showcase/diff/gui/logic/ExtendedDiffItemType.java @@ -0,0 +1,13 @@ +package org.gsoft.showcase.diff.gui.logic; + +import org.gsoft.showcase.diff.generators.DiffItemType; + +/** + * Extends {@link DiffItemType} with MODIFIED item type. + */ +public enum ExtendedDiffItemType { + EQUAL, + INSERT, + DELETE, + MODIFIED +}