Skip to content

Commit

Permalink
Show resolution path on chunk editor
Browse files Browse the repository at this point in the history
relates to #4
  • Loading branch information
albfan committed Dec 20, 2015
1 parent 0798ba9 commit c9a503d
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 19 deletions.
217 changes: 204 additions & 13 deletions src/main/java/org/jmeld/model/LevenshteinTableModel.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
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.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.Vector;
import java.util.*;
import java.util.List;

/**
* Modelo de levenstein
Expand All @@ -15,16 +25,18 @@
public class LevenshteinTableModel extends DefaultTableModel {
String origin;
String destiny;
private JMRevision currentRevision;
private FilePanel[] filePanels;
private HashMap<Point,Color> routeDiff;
private HashMap<Point, Border> borderChunks;
private boolean showSelectionPath;

public LevenshteinTableModel(String origin, String destiny) {
super();
this.origin = origin;
this.destiny = destiny;
buildModel();
}

private void buildModel() {
public void buildModel() {
if (!isAllDataAvaliable()) {
return;
}
setDataVector(newVector(origin.length() + 2), newVector(destiny.length() + 2));
buildSolutionPath();
int rowCount = getRowCount();
int columnCount = getColumnCount();

Expand Down Expand Up @@ -73,6 +85,142 @@ private void buildModel() {
}
}

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 offsetForLineOriginal = originalBufferDocument.getOffsetForLine(original.getAnchor());
int 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 yOffsetForLine = revisedBufferDocument.getOffsetForLine(revised.getAnchor());
int lineNumber = revised.getAnchor() + revised.getSize() - 1;
int yOffsetForLineEnd = revisedBufferDocument.getOffsetForLine(lineNumber) +
+ revisedBufferDocument.getLineText(lineNumber).length();
for (int i = 0; i < yOffsetForLineEnd - yOffsetForLine; i++) {
Border border;
if (i == 0) {
border = BorderFactory.createMatteBorder(2, 2, 2, 0, Color.BLACK);
} else if (i == yOffsetForLineEnd - yOffsetForLine - 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 + yOffsetForLine);
borderChunks.put(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);
Border 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);
}
borderChunks.put(point, border);
}
xOffset = xOffsetForLine;
yOffset = offsetForLineRevised;
} else if (next.isChange()) {
List<JMDelta> changedDeltas = next.getChangeRevision().getDeltas();
int startOffset = 0;
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 = offsetForLineOriginal;
yOffset = offsetForLineRevised;
for (int i = 0; i < sameChars - startOffset; i++) {
routeDiff.put(new Point(i + xOffset + startOffset, i + yOffset + startOffset), Color.GRAY);
}
startOffset = sameChars + originalChange.getSize();
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);
Border 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);
}
borderChunks.put(new Point(i + xOffset, yOffset + j), border);
}
border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
} else if (i == removeFromOrigin - 1) {
border = BorderFactory.createMatteBorder(0, 2, 2, 0, Color.BLACK);
} else {
border = BorderFactory.createMatteBorder(0, 0, 0, 2, Color.BLACK);
borderChunks.put(new Point(i + xOffset, yOffset - 1 + addFromRevised), border);
border = BorderFactory.createMatteBorder(0, 2, 0, 0, Color.BLACK);
}
borderChunks.put(point, border);
}
xOffset += removeFromOrigin;
for (int i = 0; i < addFromRevised; i++) {
Point point = new Point(xOffset - 1, i + yOffset);
routeDiff.put(point, Colors.ADDED);
Border border;
/*if (i == 0) {
border = BorderFactory.createMatteBorder(2, 2, 0, 0, Color.BLACK);
} else */
if (i == addFromRevised - 1) {
border = BorderFactory.createMatteBorder(0, 0, 2, 2, Color.BLACK);
} else {
border = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLACK);
}
borderChunks.put(point, border);
}
yOffset+=addFromRevised;
//offsetForLineRevised++;
}
}
}
int xSize = originalBufferDocument.getDocument().getLength();
for (int i = 0; i < xSize - xOffset; i++) {
routeDiff.put(new Point(i + xOffset, i + yOffset), Color.GRAY);
}
}

private Vector newVector(int size) {
Vector vector = new Vector(size);
vector.setSize(size);
Expand Down Expand Up @@ -101,13 +249,16 @@ 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 != 1 || column != 1) {
background = Color.BLUE;
} else {
if (row == column) {
background = Color.GREEN;
} else {
background = Color.BLUE;
}
} else {
if (row > 1) {
Expand All @@ -121,18 +272,58 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
if (row == 0 || column == 0) {
background = new Color(0x550099FF, true);
}

}
if (isSelected) {
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);
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;
}
}
67 changes: 61 additions & 6 deletions src/main/java/org/jmeld/ui/BufferDiffPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
import org.jmeld.util.node.JMDiffNode;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.BadLocationException;
Expand Down Expand Up @@ -70,6 +69,7 @@ public class BufferDiffPanel extends AbstractContentPanel implements Configurati
private boolean showTree;
private boolean showLevenstein;
private JSplitPane splitPane;
private JCheckBox checkSolutionPath;


BufferDiffPanel(JMeldPanel mainPanel) {
Expand Down Expand Up @@ -251,8 +251,7 @@ public void diff() {
bd2 = filePanels[RIGHT].getBufferDocument();

if (bd1 != null && bd2 != null) {
try {
currentRevision = diff.diff(bd1.getLines(), bd2.getLines()
try {currentRevision = diff.diff(bd1.getLines(), bd2.getLines()
, getDiffNode().getIgnore());

reDisplay();
Expand Down Expand Up @@ -414,9 +413,58 @@ public void stateChanged(ChangeEvent e) {
JPanel panelGraph = new JPanel(new BorderLayout());
panelGraph.add(new JScrollPane(levensteinGraphTable));
JPanel bPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));

Box box = Box.createHorizontalBox();
bPanel.add(new JLabel("Min Column Width"));
bPanel.add(spinner);
panelGraph.add(bPanel, BorderLayout.SOUTH);
box.add(bPanel);
box.add(Box.createHorizontalGlue());
checkSolutionPath = new JCheckBox("Show solution path");
checkSolutionPath.setSelected(true);
checkSolutionPath.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
((LevenshteinTableModel) levensteinGraphTable.getModel())
.setShowSelectionPath(checkSolutionPath.isSelected());
levensteinGraphTable.repaint();
}
});
box.add(checkSolutionPath);
box.add(Box.createHorizontalGlue());

final JLabel cellSelected = new JLabel("(,)");
box.add(cellSelected);
ListSelectionListener listSelectionListener = new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int originOffset = levensteinGraphTable.getSelectedRow() - 2;
int revisedOffset = levensteinGraphTable.getSelectedColumn() - 2;
cellSelected.setText("(" + originOffset + "," + revisedOffset + ")");
//TODO: Highlight position.
levensteinGraphTable.repaint();
}
};
levensteinGraphTable.getColumnModel().getSelectionModel()
.addListSelectionListener(listSelectionListener);
levensteinGraphTable.getSelectionModel()
.addListSelectionListener(listSelectionListener);
filePanels[LEFT].getEditor().addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
levensteinGraphTable.changeSelection(e.getDot() + 2, levensteinGraphTable.getSelectedColumn(), false, false);
levensteinGraphTable.changeSelection(e.getMark() + 2, levensteinGraphTable.getSelectedColumn(), false, true);
levensteinGraphTable.repaint();
}
});
filePanels[RIGHT].getEditor().addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
levensteinGraphTable.changeSelection(levensteinGraphTable.getSelectedRow(), e.getDot() + 2, false, false);
levensteinGraphTable.changeSelection(levensteinGraphTable.getSelectedRow(), e.getMark() + 2, false, true);
levensteinGraphTable.repaint();
}
});
panelGraph.add(box, BorderLayout.SOUTH);
return panelGraph;
}

Expand All @@ -426,7 +474,14 @@ private void refreshLevensteinModel() {
try {
PlainDocument orgDoc = filePanels[LEFT].getBufferDocument().getDocument();
PlainDocument revDoc = filePanels[RIGHT].getBufferDocument().getDocument();
LevenshteinTableModel model = new LevenshteinTableModel(orgDoc.getText(0, orgDoc.getLength()), revDoc.getText(0, revDoc.getLength()));
LevenshteinTableModel model = new LevenshteinTableModel();
model.setOrigin(orgDoc.getText(0, orgDoc.getLength()));
model.setDestiny(revDoc.getText(0, revDoc.getLength()));
//Add to renderer instead
model.setCurrentRevision(currentRevision);
model.setFilePanels(filePanels);
model.setShowSelectionPath(checkSolutionPath.isSelected());
model.buildModel();

levensteinGraphTable.setModel(model);
levensteinGraphTable.setDefaultRenderer(Object.class, model.getCellRenderer());
Expand Down

0 comments on commit c9a503d

Please sign in to comment.