public void setCurrentRevision(JMRevision currentRevision)

package org.jmeld.model;

import org.jmeld.diff.JMChunk;
import org.jmeld.diff.JMDelta;
import org.jmeld.diff.JMRevision;
import org.jmeld.ui.BufferDiffPanel;
import org.jmeld.ui.FilePanel;
import org.jmeld.ui.text.BufferDocumentIF;
import org.jmeld.ui.util.Colors;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Modelo de levenstein
 * User: alberto
 * Date: 7/12/12
 * Time: 16:40
 */
public class LevenshteinTableModel extends DefaultTableModel {

    String origin;

    String destiny;

    private JMRevision currentRevision;

    private FilePanel[] filePanels;

    private HashMap<Point, Color> routeDiff;

    private HashMap<Point, MatteBorder> borderChunks;

    private HashMap<Point, MatteBorder> borderSelections;

    private boolean showSelectionPath;

    public void buildModel() {
        if (!isAllDataAvaliable()) {
            return;
        }
        borderSelections = new HashMap<>();
        setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
        buildSolutionPath();
        int rowCount = getRowCount();
        int columnCount = getColumnCount();
        for (int columna = 0; columna < columnCount; columna++) {
            if (columna < 2) {
                setValueAt("", 0, columna);
            } else {
                setValueAt(destiny.charAt(columna - 2), 0, columna);
            }
        }
        for (int fila = 0; fila < rowCount; fila++) {
            if (fila < 2) {
                setValueAt("", fila, 0);
            } else {
                setValueAt(origin.charAt(fila - 2), fila, 0);
            }
        }
        int minLength = rowCount > columnCount ? columnCount : rowCount;
        for (int diagonal = 1; diagonal < minLength; diagonal++) {
            if (diagonal == 1) {
                setValueAt(0, diagonal, diagonal);
            } else {
                Object o = getValueAt(diagonal - 1, diagonal - 1);
                int incremento;
                if (origin.charAt(diagonal - 2) == destiny.charAt(diagonal - 2)) {
                    incremento = 0;
                } else {
                    incremento = 1;
                }
                setValueAt((Integer) o + incremento, diagonal, diagonal);
            }
            for (int columna = diagonal + 1; columna < columnCount; columna++) {
                setValueAt((Integer) getValueAt(diagonal, columna - 1) + 1, diagonal, columna);
            }
            for (int fila = diagonal + 1; fila < rowCount; fila++) {
                setValueAt((Integer) getValueAt(fila - 1, diagonal) + 1, fila, diagonal);
            }
        }
    }

    private boolean isAllDataAvaliable() {
        return getFilePanels() != null && getCurrentRevision() != null && origin != null && destiny != null;
    }

    class ColorPoint extends Point {

        Color color;

        public ColorPoint(int x, int y, Color color) {
            super(x, y);
            this.color = color;
        }
    }

    private void buildSolutionPath() {
        BufferDocumentIF originalBufferDocument = filePanels[BufferDiffPanel.LEFT].getBufferDocument();
        BufferDocumentIF revisedBufferDocument = filePanels[BufferDiffPanel.RIGHT].getBufferDocument();
        java.util.List<JMDelta> deltas = currentRevision.getDeltas();
        routeDiff = new HashMap<>();
        borderChunks = new HashMap<>();
        int xOffset = 0;
        int yOffset = 0;
        for (Iterator<JMDelta> iterator = deltas.iterator(); iterator.hasNext(); ) {
            JMDelta next = iterator.next();
            JMChunk original = next.getOriginal();
            JMChunk revised = next.getRevised();
            int originalLines = originalBufferDocument.getNumberOfLines();
            int revisedLines = revisedBufferDocument.getNumberOfLines();
            int offsetForLineOriginal;
            if (original.getAnchor() == originalLines) {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor() - 1) + 1;
            } else {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
            }
            int offsetForLineRevised;
            if (revised.getAnchor() == revisedLines) {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor() - 1) + 1;
            } else {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
            }
            for (int i = 0; i < offsetForLineOriginal - xOffset; i++) {
                routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
            }
            if (next.isAdd()) {
                int lineNumber = revised.getAnchor() + revised.getSize() - 1;
                int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) + +revisedBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < yOffsetForLineEnd - offsetForLineRevised; i++) {
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
                    } else if (i == yOffsetForLineEnd - offsetForLineRevised - 1) {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 0, Color.BLACK);
                    }
                    Point point = new Point(offsetForLineOriginal - 1, i + offsetForLineRevised);
                    addBorderChunks(point, border);
                    routeDiff.put(point, Colors.ADDED);
                }
                xOffset = offsetForLineOriginal;
                yOffset = yOffsetForLineEnd;
            } else if (next.isDelete()) {
                int lineNumber = original.getAnchor() + original.getSize() - 1;
                int xOffsetForLine = originalBufferDocument.getOffsetForLine(lineNumber) + originalBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < xOffsetForLine - offsetForLineOriginal; i++) {
                    Point point = new Point(i + offsetForLineOriginal, offsetForLineRevised - 1);
                    routeDiff.put(point, Colors.DELETED);
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK);
                    } else if (i == xOffsetForLine - offsetForLineOriginal - 1) {
                        border = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(0, 2, 0, 2, Color.BLACK);
                    }
                    addBorderChunks(point, border);
                }
                xOffset = xOffsetForLine;
                yOffset = offsetForLineRevised;
            } else if (next.isChange()) {
                List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
                xOffset = offsetForLineOriginal;
                yOffset = offsetForLineRevised;
                for (Iterator<JMDelta> jmDeltaIterator = changedDeltas.iterator(); jmDeltaIterator.hasNext(); ) {
                    JMDelta changeDelta = jmDeltaIterator.next();
                    JMChunk originalChange = changeDelta.getOriginal();
                    JMChunk revisedChange = changeDelta.getRevised();
                    int sameChars = originalChange.getAnchor() - xOffset;
                    for (int i = 0; i < sameChars; i++) {
                        routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
                    }
                    xOffset += sameChars;
                    yOffset += sameChars;
                    int removeFromOrigin = originalChange.getSize();
                    int addFromRevised = revisedChange.getSize();
                    for (int i = 0; i < removeFromOrigin; i++) {
                        Point point = new Point(i + xOffset, yOffset - 1);
                        routeDiff.put(point, Colors.DELETED);
                        MatteBorder border;
                        if (i == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == removeFromOrigin - 1) {
                            border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                            addBorderChunks(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
                            border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    xOffset += removeFromOrigin;
                    if (addFromRevised == 0) {
                        Point point = new Point(xOffset - 1, yOffset - 1);
                        MatteBorder border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                        addBorderChunks(point, border);
                    }
                    for (int i = 0; i < addFromRevised; i++) {
                        Point point = new Point(xOffset - 1, i + yOffset);
                        routeDiff.put(point, Colors.ADDED);
                        MatteBorder border;
                        if (i == 0 && removeFromOrigin == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i - 1 + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == addFromRevised - 1) {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    yOffset += addFromRevised;
                }
            }
        }
        int xSize = originalBufferDocument.getDocument().getLength();
        for (int i = 0; i < xSize - xOffset; i++) {
            routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
        }
    }

    private void addBorderChunks(Point point, MatteBorder border) {
        MatteBorder oldborder = borderChunks.get(point);
        if (oldborder != null) {
            Insets oldborderInsets = oldborder.getBorderInsets();
            Insets borderInsets = border.getBorderInsets();
            if (oldborderInsets.top == 0 && borderInsets.top > 0) {
                oldborderInsets.top = borderInsets.top;
            }
            if (oldborderInsets.left == 0 && borderInsets.left > 0) {
                oldborderInsets.left = borderInsets.left;
            }
            if (oldborderInsets.right == 0 && borderInsets.right > 0) {
                oldborderInsets.right = borderInsets.right;
            }
            if (oldborderInsets.bottom == 0 && borderInsets.bottom > 0) {
                oldborderInsets.bottom = borderInsets.bottom;
            }
            border = BorderFactory.createMatteBorder(oldborderInsets.top, oldborderInsets.left, oldborderInsets.bottom, oldborderInsets.right, border.getMatteColor());
        }
        borderChunks.put(point, border);
    }

    private Vector newVector(int size) {
        Vector vector = new Vector(size);
        vector.setSize(size);
        return vector;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
        buildModel();
    }

    public String getDestiny() {
        return destiny;
    }

    public void setDestiny(String destiny) {
        this.destiny = destiny;
        buildModel();
    }

    public DefaultTableCellRenderer getCellRenderer() {
        return new DefaultTableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if ("\n".equals(value.toString())) {
                    value = "\\n";
                }
                Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = Color.WHITE;
                if (row < 2 && column < 2) {
                    if (row == column) {
                        background = Color.GREEN;
                    } else {
                        background = Color.BLUE;
                    }
                } else {
                    if (row > 1) {
                        if (column > 1) {
                            if (origin.charAt(row - 2) == destiny.charAt(column - 2)) {
                                background = Color.ORANGE;
                            }
                        }
                    }
                    if (row == 0 || column == 0) {
                        background = new Color(0x550099FF, true);
                    }
                }
                if (isSelected || table.isColumnSelected(column)) {
                    Color newColor = Color.CYAN;
                    Color mixColor = Color.WHITE;
                    background = new Color(background.getRed() * newColor.getRed() / mixColor.getRed(), background.getGreen() * newColor.getGreen() / mixColor.getGreen(), background.getBlue() * newColor.getBlue() / mixColor.getBlue());
                }
                Point point = new Point(row - 2, column - 2);
                if (showSelectionPath) {
                    Color color = routeDiff.get(point);
                    if (color != null) {
                        background = color;
                    }
                }
                Border border = borderChunks.get(point);
                Border borderSelection = borderSelections.get(point);
                if (border == null) {
                    if (borderSelection != null) {
                        border = borderSelection;
                    }
                } else {
                    if (borderSelection != null) {
                        border = new CompoundBorder(border, borderSelection);
                    }
                }
                if (border != null) {
                    ((JLabel) tableCellRendererComponent).setBorder(border);
                }
                tableCellRendererComponent.setBackground(background);
                ((JLabel) tableCellRendererComponent).setHorizontalAlignment(SwingConstants.CENTER);
                return tableCellRendererComponent;
            }
        };
    }

{
        this.currentRevision = currentRevision;
        buildModel();
    }

    public JMRevision getCurrentRevision() {
        return currentRevision;
    }

    public void setFilePanels(FilePanel[] filePanels) {
        this.filePanels = filePanels;
        buildModel();
    }

    public FilePanel[] getFilePanels() {
        return filePanels;
    }

    public boolean isShowSelectionPath() {
        return showSelectionPath;
    }

    public void setShowSelectionPath(boolean showSelectionPath) {
        this.showSelectionPath = showSelectionPath;
    }

    public HashMap<Point, MatteBorder> getBorderSelections() {
        return borderSelections;
    }

    public void setBorderSelections(HashMap<Point, MatteBorder> borderSelection) {
        this.borderSelections = borderSelection;
    }
}


{
        Vector vector = new Vector(size);
        vector.setSize(size);
        return vector;
    }

package org.jmeld.model;

import org.jmeld.diff.JMChunk;
import org.jmeld.diff.JMDelta;
import org.jmeld.diff.JMRevision;
import org.jmeld.ui.BufferDiffPanel;
import org.jmeld.ui.FilePanel;
import org.jmeld.ui.text.BufferDocumentIF;
import org.jmeld.ui.util.Colors;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Modelo de levenstein
 * User: alberto
 * Date: 7/12/12
 * Time: 16:40
 */
public class LevenshteinTableModel extends DefaultTableModel {

    String origin;

    String destiny;

    private JMRevision currentRevision;

    private FilePanel[] filePanels;

    private HashMap<Point, Color> routeDiff;

    private HashMap<Point, MatteBorder> borderChunks;

    private HashMap<Point, MatteBorder> borderSelections;

    private boolean showSelectionPath;

    public void buildModel() {
        if (!isAllDataAvaliable()) {
            return;
        }
        borderSelections = new HashMap<>();
        setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
        buildSolutionPath();
        int rowCount = getRowCount();
        int columnCount = getColumnCount();
        for (int columna = 0; columna < columnCount; columna++) {
            if (columna < 2) {
                setValueAt("", 0, columna);
            } else {
                setValueAt(destiny.charAt(columna - 2), 0, columna);
            }
        }
        for (int fila = 0; fila < rowCount; fila++) {
            if (fila < 2) {
                setValueAt("", fila, 0);
            } else {
                setValueAt(origin.charAt(fila - 2), fila, 0);
            }
        }
        int minLength = rowCount > columnCount ? columnCount : rowCount;
        for (int diagonal = 1; diagonal < minLength; diagonal++) {
            if (diagonal == 1) {
                setValueAt(0, diagonal, diagonal);
            } else {
                Object o = getValueAt(diagonal - 1, diagonal - 1);
                int incremento;
                if (origin.charAt(diagonal - 2) == destiny.charAt(diagonal - 2)) {
                    incremento = 0;
                } else {
                    incremento = 1;
                }
                setValueAt((Integer) o + incremento, diagonal, diagonal);
            }
            for (int columna = diagonal + 1; columna < columnCount; columna++) {
                setValueAt((Integer) getValueAt(diagonal, columna - 1) + 1, diagonal, columna);
            }
            for (int fila = diagonal + 1; fila < rowCount; fila++) {
                setValueAt((Integer) getValueAt(fila - 1, diagonal) + 1, fila, diagonal);
            }
        }
    }

    private boolean isAllDataAvaliable() {
        return getFilePanels() != null && getCurrentRevision() != null && origin != null && destiny != null;
    }

    class ColorPoint extends Point {

        Color color;

        public ColorPoint(int x, int y, Color color) {
            super(x, y);
            this.color = color;
        }
    }

    private void buildSolutionPath() {
        BufferDocumentIF originalBufferDocument = filePanels[BufferDiffPanel.LEFT].getBufferDocument();
        BufferDocumentIF revisedBufferDocument = filePanels[BufferDiffPanel.RIGHT].getBufferDocument();
        java.util.List<JMDelta> deltas = currentRevision.getDeltas();
        routeDiff = new HashMap<>();
        borderChunks = new HashMap<>();
        int xOffset = 0;
        int yOffset = 0;
        for (Iterator<JMDelta> iterator = deltas.iterator(); iterator.hasNext(); ) {
            JMDelta next = iterator.next();
            JMChunk original = next.getOriginal();
            JMChunk revised = next.getRevised();
            int originalLines = originalBufferDocument.getNumberOfLines();
            int revisedLines = revisedBufferDocument.getNumberOfLines();
            int offsetForLineOriginal;
            if (original.getAnchor() == originalLines) {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor() - 1) + 1;
            } else {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
            }
            int offsetForLineRevised;
            if (revised.getAnchor() == revisedLines) {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor() - 1) + 1;
            } else {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
            }
            for (int i = 0; i < offsetForLineOriginal - xOffset; i++) {
                routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
            }
            if (next.isAdd()) {
                int lineNumber = revised.getAnchor() + revised.getSize() - 1;
                int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) + +revisedBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < yOffsetForLineEnd - offsetForLineRevised; i++) {
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
                    } else if (i == yOffsetForLineEnd - offsetForLineRevised - 1) {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 0, Color.BLACK);
                    }
                    Point point = new Point(offsetForLineOriginal - 1, i + offsetForLineRevised);
                    addBorderChunks(point, border);
                    routeDiff.put(point, Colors.ADDED);
                }
                xOffset = offsetForLineOriginal;
                yOffset = yOffsetForLineEnd;
            } else if (next.isDelete()) {
                int lineNumber = original.getAnchor() + original.getSize() - 1;
                int xOffsetForLine = originalBufferDocument.getOffsetForLine(lineNumber) + originalBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < xOffsetForLine - offsetForLineOriginal; i++) {
                    Point point = new Point(i + offsetForLineOriginal, offsetForLineRevised - 1);
                    routeDiff.put(point, Colors.DELETED);
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK);
                    } else if (i == xOffsetForLine - offsetForLineOriginal - 1) {
                        border = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(0, 2, 0, 2, Color.BLACK);
                    }
                    addBorderChunks(point, border);
                }
                xOffset = xOffsetForLine;
                yOffset = offsetForLineRevised;
            } else if (next.isChange()) {
                List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
                xOffset = offsetForLineOriginal;
                yOffset = offsetForLineRevised;
                for (Iterator<JMDelta> jmDeltaIterator = changedDeltas.iterator(); jmDeltaIterator.hasNext(); ) {
                    JMDelta changeDelta = jmDeltaIterator.next();
                    JMChunk originalChange = changeDelta.getOriginal();
                    JMChunk revisedChange = changeDelta.getRevised();
                    int sameChars = originalChange.getAnchor() - xOffset;
                    for (int i = 0; i < sameChars; i++) {
                        routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
                    }
                    xOffset += sameChars;
                    yOffset += sameChars;
                    int removeFromOrigin = originalChange.getSize();
                    int addFromRevised = revisedChange.getSize();
                    for (int i = 0; i < removeFromOrigin; i++) {
                        Point point = new Point(i + xOffset, yOffset - 1);
                        routeDiff.put(point, Colors.DELETED);
                        MatteBorder border;
                        if (i == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == removeFromOrigin - 1) {
                            border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                            addBorderChunks(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
                            border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    xOffset += removeFromOrigin;
                    if (addFromRevised == 0) {
                        Point point = new Point(xOffset - 1, yOffset - 1);
                        MatteBorder border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                        addBorderChunks(point, border);
                    }
                    for (int i = 0; i < addFromRevised; i++) {
                        Point point = new Point(xOffset - 1, i + yOffset);
                        routeDiff.put(point, Colors.ADDED);
                        MatteBorder border;
                        if (i == 0 && removeFromOrigin == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i - 1 + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == addFromRevised - 1) {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    yOffset += addFromRevised;
                }
            }
        }
        int xSize = originalBufferDocument.getDocument().getLength();
        for (int i = 0; i < xSize - xOffset; i++) {
            routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
        }
    }

    private void addBorderChunks(Point point, MatteBorder border) {
        MatteBorder oldborder = borderChunks.get(point);
        if (oldborder != null) {
            Insets oldborderInsets = oldborder.getBorderInsets();
            Insets borderInsets = border.getBorderInsets();
            if (oldborderInsets.top == 0 && borderInsets.top > 0) {
                oldborderInsets.top = borderInsets.top;
            }
            if (oldborderInsets.left == 0 && borderInsets.left > 0) {
                oldborderInsets.left = borderInsets.left;
            }
            if (oldborderInsets.right == 0 && borderInsets.right > 0) {
                oldborderInsets.right = borderInsets.right;
            }
            if (oldborderInsets.bottom == 0 && borderInsets.bottom > 0) {
                oldborderInsets.bottom = borderInsets.bottom;
            }
            border = BorderFactory.createMatteBorder(oldborderInsets.top, oldborderInsets.left, oldborderInsets.bottom, oldborderInsets.right, border.getMatteColor());
        }
        borderChunks.put(point, border);
    }

    private Vector newVector(int size)

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
        buildModel();
    }

    public String getDestiny() {
        return destiny;
    }

    public void setDestiny(String destiny) {
        this.destiny = destiny;
        buildModel();
    }

    public DefaultTableCellRenderer getCellRenderer() {
        return new DefaultTableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if ("\n".equals(value.toString())) {
                    value = "\\n";
                }
                Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = Color.WHITE;
                if (row < 2 && column < 2) {
                    if (row == column) {
                        background = Color.GREEN;
                    } else {
                        background = Color.BLUE;
                    }
                } else {
                    if (row > 1) {
                        if (column > 1) {
                            if (origin.charAt(row - 2) == destiny.charAt(column - 2)) {
                                background = Color.ORANGE;
                            }
                        }
                    }
                    if (row == 0 || column == 0) {
                        background = new Color(0x550099FF, true);
                    }
                }
                if (isSelected || table.isColumnSelected(column)) {
                    Color newColor = Color.CYAN;
                    Color mixColor = Color.WHITE;
                    background = new Color(background.getRed() * newColor.getRed() / mixColor.getRed(), background.getGreen() * newColor.getGreen() / mixColor.getGreen(), background.getBlue() * newColor.getBlue() / mixColor.getBlue());
                }
                Point point = new Point(row - 2, column - 2);
                if (showSelectionPath) {
                    Color color = routeDiff.get(point);
                    if (color != null) {
                        background = color;
                    }
                }
                Border border = borderChunks.get(point);
                Border borderSelection = borderSelections.get(point);
                if (border == null) {
                    if (borderSelection != null) {
                        border = borderSelection;
                    }
                } else {
                    if (borderSelection != null) {
                        border = new CompoundBorder(border, borderSelection);
                    }
                }
                if (border != null) {
                    ((JLabel) tableCellRendererComponent).setBorder(border);
                }
                tableCellRendererComponent.setBackground(background);
                ((JLabel) tableCellRendererComponent).setHorizontalAlignment(SwingConstants.CENTER);
                return tableCellRendererComponent;
            }
        };
    }

    public void setCurrentRevision(JMRevision currentRevision) {
        this.currentRevision = currentRevision;
        buildModel();
    }

    public JMRevision getCurrentRevision() {
        return currentRevision;
    }

    public void setFilePanels(FilePanel[] filePanels) {
        this.filePanels = filePanels;
        buildModel();
    }

    public FilePanel[] getFilePanels() {
        return filePanels;
    }

    public boolean isShowSelectionPath() {
        return showSelectionPath;
    }

    public void setShowSelectionPath(boolean showSelectionPath) {
        this.showSelectionPath = showSelectionPath;
    }

    public HashMap<Point, MatteBorder> getBorderSelections() {
        return borderSelections;
    }

    public void setBorderSelections(HashMap<Point, MatteBorder> borderSelection) {
        this.borderSelections = borderSelection;
    }
}


        BufferDocumentIF originalBufferDocument = filePanels[BufferDiffPanel.LEFT].getBufferDocument();
        BufferDocumentIF revisedBufferDocument = filePanels[BufferDiffPanel.RIGHT].getBufferDocument();
        java.util.List<JMDelta> deltas = currentRevision.getDeltas();

package org.jmeld.model;

import org.jmeld.diff.JMChunk;
import org.jmeld.diff.JMDelta;
import org.jmeld.diff.JMRevision;
import org.jmeld.ui.BufferDiffPanel;
import org.jmeld.ui.FilePanel;
import org.jmeld.ui.text.BufferDocumentIF;
import org.jmeld.ui.util.Colors;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Modelo de levenstein
 * User: alberto
 * Date: 7/12/12
 * Time: 16:40
 */
public class LevenshteinTableModel extends DefaultTableModel {

    String origin;

    String destiny;

    private JMRevision currentRevision;

    private FilePanel[] filePanels;

    private HashMap<Point, Color> routeDiff;

    private HashMap<Point, MatteBorder> borderChunks;

    private HashMap<Point, MatteBorder> borderSelections;

    private boolean showSelectionPath;

    public void buildModel() {
        if (!isAllDataAvaliable()) {
            return;
        }
        borderSelections = new HashMap<>();
        setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
        buildSolutionPath();
        int rowCount = getRowCount();
        int columnCount = getColumnCount();
        for (int columna = 0; columna < columnCount; columna++) {
            if (columna < 2) {
                setValueAt("", 0, columna);
            } else {
                setValueAt(destiny.charAt(columna - 2), 0, columna);
            }
        }
        for (int fila = 0; fila < rowCount; fila++) {
            if (fila < 2) {
                setValueAt("", fila, 0);
            } else {
                setValueAt(origin.charAt(fila - 2), fila, 0);
            }
        }
        int minLength = rowCount > columnCount ? columnCount : rowCount;
        for (int diagonal = 1; diagonal < minLength; diagonal++) {
            if (diagonal == 1) {
                setValueAt(0, diagonal, diagonal);
            } else {
                Object o = getValueAt(diagonal - 1, diagonal - 1);
                int incremento;
                if (origin.charAt(diagonal - 2) == destiny.charAt(diagonal - 2)) {
                    incremento = 0;
                } else {
                    incremento = 1;
                }
                setValueAt((Integer) o + incremento, diagonal, diagonal);
            }
            for (int columna = diagonal + 1; columna < columnCount; columna++) {
                setValueAt((Integer) getValueAt(diagonal, columna - 1) + 1, diagonal, columna);
            }
            for (int fila = diagonal + 1; fila < rowCount; fila++) {
                setValueAt((Integer) getValueAt(fila - 1, diagonal) + 1, fila, diagonal);
            }
        }
    }

    private boolean isAllDataAvaliable() {
        return getFilePanels() != null && getCurrentRevision() != null && origin != null && destiny != null;
    }

    class ColorPoint extends Point {

        Color color;

        public ColorPoint(int x, int y, Color color) {
            super(x, y);
            this.color = color;
        }
    }

    private void buildSolutionPath() {

        routeDiff = new HashMap<>();
        borderChunks = new HashMap<>();
        int xOffset = 0;
        int yOffset = 0;
        for (Iterator<JMDelta> iterator = deltas.iterator(); iterator.hasNext(); ) {
            JMDelta next = iterator.next();
            JMChunk original = next.getOriginal();
            JMChunk revised = next.getRevised();
            int originalLines = originalBufferDocument.getNumberOfLines();
            int revisedLines = revisedBufferDocument.getNumberOfLines();
            int offsetForLineOriginal;
            if (original.getAnchor() == originalLines) {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor() - 1) + 1;
            } else {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
            }
            int offsetForLineRevised;
            if (revised.getAnchor() == revisedLines) {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor() - 1) + 1;
            } else {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
            }
            for (int i = 0; i < offsetForLineOriginal - xOffset; i++) {
                routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
            }
            if (next.isAdd()) {
                int lineNumber = revised.getAnchor() + revised.getSize() - 1;
                int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) + +revisedBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < yOffsetForLineEnd - offsetForLineRevised; i++) {
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
                    } else if (i == yOffsetForLineEnd - offsetForLineRevised - 1) {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 0, Color.BLACK);
                    }
                    Point point = new Point(offsetForLineOriginal - 1, i + offsetForLineRevised);
                    addBorderChunks(point, border);
                    routeDiff.put(point, Colors.ADDED);
                }
                xOffset = offsetForLineOriginal;
                yOffset = yOffsetForLineEnd;
            } else if (next.isDelete()) {
                int lineNumber = original.getAnchor() + original.getSize() - 1;
                int xOffsetForLine = originalBufferDocument.getOffsetForLine(lineNumber) + originalBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < xOffsetForLine - offsetForLineOriginal; i++) {
                    Point point = new Point(i + offsetForLineOriginal, offsetForLineRevised - 1);
                    routeDiff.put(point, Colors.DELETED);
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK);
                    } else if (i == xOffsetForLine - offsetForLineOriginal - 1) {
                        border = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(0, 2, 0, 2, Color.BLACK);
                    }
                    addBorderChunks(point, border);
                }
                xOffset = xOffsetForLine;
                yOffset = offsetForLineRevised;
            } else if (next.isChange()) {
                List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
                xOffset = offsetForLineOriginal;
                yOffset = offsetForLineRevised;
                for (Iterator<JMDelta> jmDeltaIterator = changedDeltas.iterator(); jmDeltaIterator.hasNext(); ) {
                    JMDelta changeDelta = jmDeltaIterator.next();
                    JMChunk originalChange = changeDelta.getOriginal();
                    JMChunk revisedChange = changeDelta.getRevised();
                    int sameChars = originalChange.getAnchor() - xOffset;
                    for (int i = 0; i < sameChars; i++) {
                        routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
                    }
                    xOffset += sameChars;
                    yOffset += sameChars;
                    int removeFromOrigin = originalChange.getSize();
                    int addFromRevised = revisedChange.getSize();
                    for (int i = 0; i < removeFromOrigin; i++) {
                        Point point = new Point(i + xOffset, yOffset - 1);
                        routeDiff.put(point, Colors.DELETED);
                        MatteBorder border;
                        if (i == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == removeFromOrigin - 1) {
                            border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                            addBorderChunks(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
                            border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    xOffset += removeFromOrigin;
                    if (addFromRevised == 0) {
                        Point point = new Point(xOffset - 1, yOffset - 1);
                        MatteBorder border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                        addBorderChunks(point, border);
                    }
                    for (int i = 0; i < addFromRevised; i++) {
                        Point point = new Point(xOffset - 1, i + yOffset);
                        routeDiff.put(point, Colors.ADDED);
                        MatteBorder border;
                        if (i == 0 && removeFromOrigin == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i - 1 + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == addFromRevised - 1) {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    yOffset += addFromRevised;
                }
            }
        }
        int xSize = originalBufferDocument.getDocument().getLength();
        for (int i = 0; i < xSize - xOffset; i++) {
            routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
        }
    }

    private void addBorderChunks(Point point, MatteBorder border) {
        MatteBorder oldborder = borderChunks.get(point);
        if (oldborder != null) {
            Insets oldborderInsets = oldborder.getBorderInsets();
            Insets borderInsets = border.getBorderInsets();
            if (oldborderInsets.top == 0 && borderInsets.top > 0) {
                oldborderInsets.top = borderInsets.top;
            }
            if (oldborderInsets.left == 0 && borderInsets.left > 0) {
                oldborderInsets.left = borderInsets.left;
            }
            if (oldborderInsets.right == 0 && borderInsets.right > 0) {
                oldborderInsets.right = borderInsets.right;
            }
            if (oldborderInsets.bottom == 0 && borderInsets.bottom > 0) {
                oldborderInsets.bottom = borderInsets.bottom;
            }
            border = BorderFactory.createMatteBorder(oldborderInsets.top, oldborderInsets.left, oldborderInsets.bottom, oldborderInsets.right, border.getMatteColor());
        }
        borderChunks.put(point, border);
    }

    private Vector newVector(int size) {
        Vector vector = new Vector(size);
        vector.setSize(size);
        return vector;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
        buildModel();
    }

    public String getDestiny() {
        return destiny;
    }

    public void setDestiny(String destiny) {
        this.destiny = destiny;
        buildModel();
    }

    public DefaultTableCellRenderer getCellRenderer() {
        return new DefaultTableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if ("\n".equals(value.toString())) {
                    value = "\\n";
                }
                Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = Color.WHITE;
                if (row < 2 && column < 2) {
                    if (row == column) {
                        background = Color.GREEN;
                    } else {
                        background = Color.BLUE;
                    }
                } else {
                    if (row > 1) {
                        if (column > 1) {
                            if (origin.charAt(row - 2) == destiny.charAt(column - 2)) {
                                background = Color.ORANGE;
                            }
                        }
                    }
                    if (row == 0 || column == 0) {
                        background = new Color(0x550099FF, true);
                    }
                }
                if (isSelected || table.isColumnSelected(column)) {
                    Color newColor = Color.CYAN;
                    Color mixColor = Color.WHITE;
                    background = new Color(background.getRed() * newColor.getRed() / mixColor.getRed(), background.getGreen() * newColor.getGreen() / mixColor.getGreen(), background.getBlue() * newColor.getBlue() / mixColor.getBlue());
                }
                Point point = new Point(row - 2, column - 2);
                if (showSelectionPath) {
                    Color color = routeDiff.get(point);
                    if (color != null) {
                        background = color;
                    }
                }
                Border border = borderChunks.get(point);
                Border borderSelection = borderSelections.get(point);
                if (border == null) {
                    if (borderSelection != null) {
                        border = borderSelection;
                    }
                } else {
                    if (borderSelection != null) {
                        border = new CompoundBorder(border, borderSelection);
                    }
                }
                if (border != null) {
                    ((JLabel) tableCellRendererComponent).setBorder(border);
                }
                tableCellRendererComponent.setBackground(background);
                ((JLabel) tableCellRendererComponent).setHorizontalAlignment(SwingConstants.CENTER);
                return tableCellRendererComponent;
            }
        };
    }

    public void setCurrentRevision(JMRevision currentRevision) {
        this.currentRevision = currentRevision;
        buildModel();
    }

    public JMRevision getCurrentRevision() {
        return currentRevision;
    }

    public void setFilePanels(FilePanel[] filePanels) {
        this.filePanels = filePanels;
        buildModel();
    }

    public FilePanel[] getFilePanels() {
        return filePanels;
    }

    public boolean isShowSelectionPath() {
        return showSelectionPath;
    }

    public void setShowSelectionPath(boolean showSelectionPath) {
        this.showSelectionPath = showSelectionPath;
    }

    public HashMap<Point, MatteBorder> getBorderSelections() {
        return borderSelections;
    }

    public void setBorderSelections(HashMap<Point, MatteBorder> borderSelection) {
        this.borderSelections = borderSelection;
    }
}


routeDiff = new HashMap<>();
        borderChunks = new HashMap<>();
        int xOffset = 0;
        int yOffset = 0;

package org.jmeld.model;

import org.jmeld.diff.JMChunk;
import org.jmeld.diff.JMDelta;
import org.jmeld.diff.JMRevision;
import org.jmeld.ui.BufferDiffPanel;
import org.jmeld.ui.FilePanel;
import org.jmeld.ui.text.BufferDocumentIF;
import org.jmeld.ui.util.Colors;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Modelo de levenstein
 * User: alberto
 * Date: 7/12/12
 * Time: 16:40
 */
public class LevenshteinTableModel extends DefaultTableModel {

    String origin;

    String destiny;

    private JMRevision currentRevision;

    private FilePanel[] filePanels;

    private HashMap<Point, Color> routeDiff;

    private HashMap<Point, MatteBorder> borderChunks;

    private HashMap<Point, MatteBorder> borderSelections;

    private boolean showSelectionPath;

    public void buildModel() {
        if (!isAllDataAvaliable()) {
            return;
        }
        borderSelections = new HashMap<>();
        setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
        buildSolutionPath();
        int rowCount = getRowCount();
        int columnCount = getColumnCount();
        for (int columna = 0; columna < columnCount; columna++) {
            if (columna < 2) {
                setValueAt("", 0, columna);
            } else {
                setValueAt(destiny.charAt(columna - 2), 0, columna);
            }
        }
        for (int fila = 0; fila < rowCount; fila++) {
            if (fila < 2) {
                setValueAt("", fila, 0);
            } else {
                setValueAt(origin.charAt(fila - 2), fila, 0);
            }
        }
        int minLength = rowCount > columnCount ? columnCount : rowCount;
        for (int diagonal = 1; diagonal < minLength; diagonal++) {
            if (diagonal == 1) {
                setValueAt(0, diagonal, diagonal);
            } else {
                Object o = getValueAt(diagonal - 1, diagonal - 1);
                int incremento;
                if (origin.charAt(diagonal - 2) == destiny.charAt(diagonal - 2)) {
                    incremento = 0;
                } else {
                    incremento = 1;
                }
                setValueAt((Integer) o + incremento, diagonal, diagonal);
            }
            for (int columna = diagonal + 1; columna < columnCount; columna++) {
                setValueAt((Integer) getValueAt(diagonal, columna - 1) + 1, diagonal, columna);
            }
            for (int fila = diagonal + 1; fila < rowCount; fila++) {
                setValueAt((Integer) getValueAt(fila - 1, diagonal) + 1, fila, diagonal);
            }
        }
    }

    private boolean isAllDataAvaliable() {
        return getFilePanels() != null && getCurrentRevision() != null && origin != null && destiny != null;
    }

    class ColorPoint extends Point {

        Color color;

        public ColorPoint(int x, int y, Color color) {
            super(x, y);
            this.color = color;
        }
    }

    private void buildSolutionPath() {
        BufferDocumentIF originalBufferDocument = filePanels[BufferDiffPanel.LEFT].getBufferDocument();
        BufferDocumentIF revisedBufferDocument = filePanels[BufferDiffPanel.RIGHT].getBufferDocument();
        java.util.List<JMDelta> deltas = currentRevision.getDeltas();

        for (Iterator<JMDelta> iterator = deltas.iterator(); iterator.hasNext(); ) {
            JMDelta next = iterator.next();
            JMChunk original = next.getOriginal();
            JMChunk revised = next.getRevised();
            int originalLines = originalBufferDocument.getNumberOfLines();
            int revisedLines = revisedBufferDocument.getNumberOfLines();
            int offsetForLineOriginal;
            if (original.getAnchor() == originalLines) {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor() - 1) + 1;
            } else {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
            }
            int offsetForLineRevised;
            if (revised.getAnchor() == revisedLines) {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor() - 1) + 1;
            } else {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
            }
            for (int i = 0; i < offsetForLineOriginal - xOffset; i++) {
                routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
            }
            if (next.isAdd()) {
                int lineNumber = revised.getAnchor() + revised.getSize() - 1;
                int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) + +revisedBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < yOffsetForLineEnd - offsetForLineRevised; i++) {
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
                    } else if (i == yOffsetForLineEnd - offsetForLineRevised - 1) {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 0, Color.BLACK);
                    }
                    Point point = new Point(offsetForLineOriginal - 1, i + offsetForLineRevised);
                    addBorderChunks(point, border);
                    routeDiff.put(point, Colors.ADDED);
                }
                xOffset = offsetForLineOriginal;
                yOffset = yOffsetForLineEnd;
            } else if (next.isDelete()) {
                int lineNumber = original.getAnchor() + original.getSize() - 1;
                int xOffsetForLine = originalBufferDocument.getOffsetForLine(lineNumber) + originalBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < xOffsetForLine - offsetForLineOriginal; i++) {
                    Point point = new Point(i + offsetForLineOriginal, offsetForLineRevised - 1);
                    routeDiff.put(point, Colors.DELETED);
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK);
                    } else if (i == xOffsetForLine - offsetForLineOriginal - 1) {
                        border = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(0, 2, 0, 2, Color.BLACK);
                    }
                    addBorderChunks(point, border);
                }
                xOffset = xOffsetForLine;
                yOffset = offsetForLineRevised;
            } else if (next.isChange()) {
                List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
                xOffset = offsetForLineOriginal;
                yOffset = offsetForLineRevised;
                for (Iterator<JMDelta> jmDeltaIterator = changedDeltas.iterator(); jmDeltaIterator.hasNext(); ) {
                    JMDelta changeDelta = jmDeltaIterator.next();
                    JMChunk originalChange = changeDelta.getOriginal();
                    JMChunk revisedChange = changeDelta.getRevised();
                    int sameChars = originalChange.getAnchor() - xOffset;
                    for (int i = 0; i < sameChars; i++) {
                        routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
                    }
                    xOffset += sameChars;
                    yOffset += sameChars;
                    int removeFromOrigin = originalChange.getSize();
                    int addFromRevised = revisedChange.getSize();
                    for (int i = 0; i < removeFromOrigin; i++) {
                        Point point = new Point(i + xOffset, yOffset - 1);
                        routeDiff.put(point, Colors.DELETED);
                        MatteBorder border;
                        if (i == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == removeFromOrigin - 1) {
                            border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                            addBorderChunks(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
                            border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    xOffset += removeFromOrigin;
                    if (addFromRevised == 0) {
                        Point point = new Point(xOffset - 1, yOffset - 1);
                        MatteBorder border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                        addBorderChunks(point, border);
                    }
                    for (int i = 0; i < addFromRevised; i++) {
                        Point point = new Point(xOffset - 1, i + yOffset);
                        routeDiff.put(point, Colors.ADDED);
                        MatteBorder border;
                        if (i == 0 && removeFromOrigin == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i - 1 + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == addFromRevised - 1) {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    yOffset += addFromRevised;
                }
            }
        }
        int xSize = originalBufferDocument.getDocument().getLength();
        for (int i = 0; i < xSize - xOffset; i++) {
            routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
        }
    }

    private void addBorderChunks(Point point, MatteBorder border) {
        MatteBorder oldborder = borderChunks.get(point);
        if (oldborder != null) {
            Insets oldborderInsets = oldborder.getBorderInsets();
            Insets borderInsets = border.getBorderInsets();
            if (oldborderInsets.top == 0 && borderInsets.top > 0) {
                oldborderInsets.top = borderInsets.top;
            }
            if (oldborderInsets.left == 0 && borderInsets.left > 0) {
                oldborderInsets.left = borderInsets.left;
            }
            if (oldborderInsets.right == 0 && borderInsets.right > 0) {
                oldborderInsets.right = borderInsets.right;
            }
            if (oldborderInsets.bottom == 0 && borderInsets.bottom > 0) {
                oldborderInsets.bottom = borderInsets.bottom;
            }
            border = BorderFactory.createMatteBorder(oldborderInsets.top, oldborderInsets.left, oldborderInsets.bottom, oldborderInsets.right, border.getMatteColor());
        }
        borderChunks.put(point, border);
    }

    private Vector newVector(int size) {
        Vector vector = new Vector(size);
        vector.setSize(size);
        return vector;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
        buildModel();
    }

    public String getDestiny() {
        return destiny;
    }

    public void setDestiny(String destiny) {
        this.destiny = destiny;
        buildModel();
    }

    public DefaultTableCellRenderer getCellRenderer() {
        return new DefaultTableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if ("\n".equals(value.toString())) {
                    value = "\\n";
                }
                Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = Color.WHITE;
                if (row < 2 && column < 2) {
                    if (row == column) {
                        background = Color.GREEN;
                    } else {
                        background = Color.BLUE;
                    }
                } else {
                    if (row > 1) {
                        if (column > 1) {
                            if (origin.charAt(row - 2) == destiny.charAt(column - 2)) {
                                background = Color.ORANGE;
                            }
                        }
                    }
                    if (row == 0 || column == 0) {
                        background = new Color(0x550099FF, true);
                    }
                }
                if (isSelected || table.isColumnSelected(column)) {
                    Color newColor = Color.CYAN;
                    Color mixColor = Color.WHITE;
                    background = new Color(background.getRed() * newColor.getRed() / mixColor.getRed(), background.getGreen() * newColor.getGreen() / mixColor.getGreen(), background.getBlue() * newColor.getBlue() / mixColor.getBlue());
                }
                Point point = new Point(row - 2, column - 2);
                if (showSelectionPath) {
                    Color color = routeDiff.get(point);
                    if (color != null) {
                        background = color;
                    }
                }
                Border border = borderChunks.get(point);
                Border borderSelection = borderSelections.get(point);
                if (border == null) {
                    if (borderSelection != null) {
                        border = borderSelection;
                    }
                } else {
                    if (borderSelection != null) {
                        border = new CompoundBorder(border, borderSelection);
                    }
                }
                if (border != null) {
                    ((JLabel) tableCellRendererComponent).setBorder(border);
                }
                tableCellRendererComponent.setBackground(background);
                ((JLabel) tableCellRendererComponent).setHorizontalAlignment(SwingConstants.CENTER);
                return tableCellRendererComponent;
            }
        };
    }

    public void setCurrentRevision(JMRevision currentRevision) {
        this.currentRevision = currentRevision;
        buildModel();
    }

    public JMRevision getCurrentRevision() {
        return currentRevision;
    }

    public void setFilePanels(FilePanel[] filePanels) {
        this.filePanels = filePanels;
        buildModel();
    }

    public FilePanel[] getFilePanels() {
        return filePanels;
    }

    public boolean isShowSelectionPath() {
        return showSelectionPath;
    }

    public void setShowSelectionPath(boolean showSelectionPath) {
        this.showSelectionPath = showSelectionPath;
    }

    public HashMap<Point, MatteBorder> getBorderSelections() {
        return borderSelections;
    }

    public void setBorderSelections(HashMap<Point, MatteBorder> borderSelection) {
        this.borderSelections = borderSelection;
    }
}


for (Iterator<JMDelta> iterator = deltas.iterator(); iterator.hasNext(); ) {
            JMDelta next = iterator.next();
            JMChunk original = next.getOriginal();
            JMChunk revised = next.getRevised();
            int originalLines = originalBufferDocument.getNumberOfLines();
            int revisedLines = revisedBufferDocument.getNumberOfLines();
            int offsetForLineOriginal;
            if (original.getAnchor() == originalLines) {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor() - 1) + 1;
            } else {
                offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
            }
            int offsetForLineRevised;
            if (revised.getAnchor() == revisedLines) {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor() - 1) + 1;
            } else {
                offsetForLineRevised = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
            }
            for (int i = 0; i < offsetForLineOriginal - xOffset; i++) {
                routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
            }
            if (next.isAdd()) {
                int lineNumber = revised.getAnchor() + revised.getSize() - 1;
                int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) + +revisedBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < yOffsetForLineEnd - offsetForLineRevised; i++) {
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
                    } else if (i == yOffsetForLineEnd - offsetForLineRevised - 1) {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(2, 0, 2, 0, Color.BLACK);
                    }
                    Point point = new Point(offsetForLineOriginal - 1, i + offsetForLineRevised);
                    addBorderChunks(point, border);
                    routeDiff.put(point, Colors.ADDED);
                }
                xOffset = offsetForLineOriginal;
                yOffset = yOffsetForLineEnd;
            } else if (next.isDelete()) {
                int lineNumber = original.getAnchor() + original.getSize() - 1;
                int xOffsetForLine = originalBufferDocument.getOffsetForLine(lineNumber) + originalBufferDocument.getLineText(lineNumber).length();
                for (int i = 0; i < xOffsetForLine - offsetForLineOriginal; i++) {
                    Point point = new Point(i + offsetForLineOriginal, offsetForLineRevised - 1);
                    routeDiff.put(point, Colors.DELETED);
                    MatteBorder border;
                    if (i == 0) {
                        border = BorderFactory.createMatteBorder(2, 2, 0, 2, Color.BLACK);
                    } else if (i == xOffsetForLine - offsetForLineOriginal - 1) {
                        border = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.BLACK);
                    } else {
                        border = BorderFactory.createMatteBorder(0, 2, 0, 2, Color.BLACK);
                    }
                    addBorderChunks(point, border);
                }
                xOffset = xOffsetForLine;
                yOffset = offsetForLineRevised;
            } else if (next.isChange()) {
                List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
                xOffset = offsetForLineOriginal;
                yOffset = offsetForLineRevised;
                for (Iterator<JMDelta> jmDeltaIterator = changedDeltas.iterator(); jmDeltaIterator.hasNext(); ) {
                    JMDelta changeDelta = jmDeltaIterator.next();
                    JMChunk originalChange = changeDelta.getOriginal();
                    JMChunk revisedChange = changeDelta.getRevised();
                    int sameChars = originalChange.getAnchor() - xOffset;
                    for (int i = 0; i < sameChars; i++) {
                        routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
                    }
                    xOffset += sameChars;
                    yOffset += sameChars;
                    int removeFromOrigin = originalChange.getSize();
                    int addFromRevised = revisedChange.getSize();
                    for (int i = 0; i < removeFromOrigin; i++) {
                        Point point = new Point(i + xOffset, yOffset - 1);
                        routeDiff.put(point, Colors.DELETED);
                        MatteBorder border;
                        if (i == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == removeFromOrigin - 1) {
                            border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                            addBorderChunks(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
                            border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    xOffset += removeFromOrigin;
                    if (addFromRevised == 0) {
                        Point point = new Point(xOffset - 1, yOffset - 1);
                        MatteBorder border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
                        addBorderChunks(point, border);
                    }
                    for (int i = 0; i < addFromRevised; i++) {
                        Point point = new Point(xOffset - 1, i + yOffset);
                        routeDiff.put(point, Colors.ADDED);
                        MatteBorder border;
                        if (i == 0 && removeFromOrigin == 0) {
                            for (int j = 0; j < addFromRevised; j++) {
                                if (j == addFromRevised - 1) {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 2, Color.BLACK);
                                } else {
                                    border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK);
                                }
                                addBorderChunks(new Point(i - 1 + xOffset, yOffset + j), border);
                            }
                            border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
                            addBorderChunks(point, border);
                        }
                        if (i == addFromRevised - 1) {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
                        } else {
                            border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
                        }
                        addBorderChunks(point, border);
                    }
                    yOffset += addFromRevised;
                }
            }
        }
        int xSize = originalBufferDocument.getDocument().getLength();
        for (int i = 0; i < xSize - xOffset; i++) {
            routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
        }
    }

package org.jmeld.model;

import org.jmeld.diff.JMChunk;
import org.jmeld.diff.JMDelta;
import org.jmeld.diff.JMRevision;
import org.jmeld.ui.BufferDiffPanel;
import org.jmeld.ui.FilePanel;
import org.jmeld.ui.text.BufferDocumentIF;
import org.jmeld.ui.util.Colors;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Modelo de levenstein
 * User: alberto
 * Date: 7/12/12
 * Time: 16:40
 */
public class LevenshteinTableModel extends DefaultTableModel {

    String origin;

    String destiny;

    private JMRevision currentRevision;

    private FilePanel[] filePanels;

    private HashMap<Point, Color> routeDiff;

    private HashMap<Point, MatteBorder> borderChunks;

    private HashMap<Point, MatteBorder> borderSelections;

    private boolean showSelectionPath;

    public void buildModel() {
        if (!isAllDataAvaliable()) {
            return;
        }
        borderSelections = new HashMap<>();
        setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
        buildSolutionPath();
        int rowCount = getRowCount();
        int columnCount = getColumnCount();
        for (int columna = 0; columna < columnCount; columna++) {
            if (columna < 2) {
                setValueAt("", 0, columna);
            } else {
                setValueAt(destiny.charAt(columna - 2), 0, columna);
            }
        }
        for (int fila = 0; fila < rowCount; fila++) {
            if (fila < 2) {
                setValueAt("", fila, 0);
            } else {
                setValueAt(origin.charAt(fila - 2), fila, 0);
            }
        }
        int minLength = rowCount > columnCount ? columnCount : rowCount;
        for (int diagonal = 1; diagonal < minLength; diagonal++) {
            if (diagonal == 1) {
                setValueAt(0, diagonal, diagonal);
            } else {
                Object o = getValueAt(diagonal - 1, diagonal - 1);
                int incremento;
                if (origin.charAt(diagonal - 2) == destiny.charAt(diagonal - 2)) {
                    incremento = 0;
                } else {
                    incremento = 1;
                }
                setValueAt((Integer) o + incremento, diagonal, diagonal);
            }
            for (int columna = diagonal + 1; columna < columnCount; columna++) {
                setValueAt((Integer) getValueAt(diagonal, columna - 1) + 1, diagonal, columna);
            }
            for (int fila = diagonal + 1; fila < rowCount; fila++) {
                setValueAt((Integer) getValueAt(fila - 1, diagonal) + 1, fila, diagonal);
            }
        }
    }

    private boolean isAllDataAvaliable() {
        return getFilePanels() != null && getCurrentRevision() != null && origin != null && destiny != null;
    }

    class ColorPoint extends Point {

        Color color;

        public ColorPoint(int x, int y, Color color) {
            super(x, y);
            this.color = color;
        }
    }

    private void buildSolutionPath() {
        BufferDocumentIF originalBufferDocument = filePanels[BufferDiffPanel.LEFT].getBufferDocument();
        BufferDocumentIF revisedBufferDocument = filePanels[BufferDiffPanel.RIGHT].getBufferDocument();
        java.util.List<JMDelta> deltas = currentRevision.getDeltas();
        routeDiff = new HashMap<>();
        borderChunks = new HashMap<>();
        int xOffset = 0;
        int yOffset = 0;

    private void addBorderChunks(Point point, MatteBorder border) {
        MatteBorder oldborder = borderChunks.get(point);
        if (oldborder != null) {
            Insets oldborderInsets = oldborder.getBorderInsets();
            Insets borderInsets = border.getBorderInsets();
            if (oldborderInsets.top == 0 && borderInsets.top > 0) {
                oldborderInsets.top = borderInsets.top;
            }
            if (oldborderInsets.left == 0 && borderInsets.left > 0) {
                oldborderInsets.left = borderInsets.left;
            }
            if (oldborderInsets.right == 0 && borderInsets.right > 0) {
                oldborderInsets.right = borderInsets.right;
            }
            if (oldborderInsets.bottom == 0 && borderInsets.bottom > 0) {
                oldborderInsets.bottom = borderInsets.bottom;
            }
            border = BorderFactory.createMatteBorder(oldborderInsets.top, oldborderInsets.left, oldborderInsets.bottom, oldborderInsets.right, border.getMatteColor());
        }
        borderChunks.put(point, border);
    }

    private Vector newVector(int size) {
        Vector vector = new Vector(size);
        vector.setSize(size);
        return vector;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
        buildModel();
    }

    public String getDestiny() {
        return destiny;
    }

    public void setDestiny(String destiny) {
        this.destiny = destiny;
        buildModel();
    }

    public DefaultTableCellRenderer getCellRenderer() {
        return new DefaultTableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                if ("\n".equals(value.toString())) {
                    value = "\\n";
                }
                Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = Color.WHITE;
                if (row < 2 && column < 2) {
                    if (row == column) {
                        background = Color.GREEN;
                    } else {
                        background = Color.BLUE;
                    }
                } else {
                    if (row > 1) {
                        if (column > 1) {
                            if (origin.charAt(row - 2) == destiny.charAt(column - 2)) {
                                background = Color.ORANGE;
                            }
                        }
                    }
                    if (row == 0 || column == 0) {
                        background = new Color(0x550099FF, true);
                    }
                }
                if (isSelected || table.isColumnSelected(column)) {
                    Color newColor = Color.CYAN;
                    Color mixColor = Color.WHITE;
                    background = new Color(background.getRed() * newColor.getRed() / mixColor.getRed(), background.getGreen() * newColor.getGreen() / mixColor.getGreen(), background.getBlue() * newColor.getBlue() / mixColor.getBlue());
                }
                Point point = new Point(row - 2, column - 2);
                if (showSelectionPath) {
                    Color color = routeDiff.get(point);
                    if (color != null) {
                        background = color;
                    }
                }
                Border border = borderChunks.get(point);
                Border borderSelection = borderSelections.get(point);
                if (border == null) {
                    if (borderSelection != null) {
                        border = borderSelection;
                    }
                } else {
                    if (borderSelection != null) {
                        border = new CompoundBorder(border, borderSelection);
                    }
                }
                if (border != null) {
                    ((JLabel) tableCellRendererComponent).setBorder(border);
                }
                tableCellRendererComponent.setBackground(background);
                ((JLabel) tableCellRendererComponent).setHorizontalAlignment(SwingConstants.CENTER);
                return tableCellRendererComponent;
            }
        };
    }

    public void setCurrentRevision(JMRevision currentRevision) {
        this.currentRevision = currentRevision;
        buildModel();
    }

    public JMRevision getCurrentRevision() {
        return currentRevision;
    }

    public void setFilePanels(FilePanel[] filePanels) {
        this.filePanels = filePanels;
        buildModel();
    }

    public FilePanel[] getFilePanels() {
        return filePanels;
    }

    public boolean isShowSelectionPath() {
        return showSelectionPath;
    }

    public void setShowSelectionPath(boolean showSelectionPath) {
        this.showSelectionPath = showSelectionPath;
    }

    public HashMap<Point, MatteBorder> getBorderSelections() {
        return borderSelections;
    }

    public void setBorderSelections(HashMap<Point, MatteBorder> borderSelection) {
        this.borderSelections = borderSelection;
    }
}