package ru.batrdmi.svnplugin;
import com.mxgraph.model.mxCell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxRectangle;
import org.jetbrains.annotations.Nullable;
import ru.batrdmi.svnplugin.logic.Revision;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RevisionHighlighter extends MouseAdapter {
public enum State {OFF, ON, PARTIAL}
private static final String HIGHLIGHTED_PROPERTY = "highlighted";
private final mxGraphComponent gc;
private mxCell highlightedEdge;
public RevisionHighlighter(mxGraphComponent gc) {
this.gc = gc;
}
@Override
public void mouseExited(MouseEvent e) {
mouseOver(null);
}
@Override
public void mouseMoved(MouseEvent e) {
mxCell cell = (mxCell) gc.getCellAt(e.getX(), e.getY());
mouseOver(cell);
}
private void mouseOver(@Nullable mxCell cell) {
RevisionGraphModel model = (RevisionGraphModel) gc.getGraph();
Set<mxCell> cellsToRepaint = new HashSet<mxCell>();
if (cell != highlightedEdge) {
if (highlightedEdge != null) {
cellsToRepaint.addAll(highlightEdge(model, highlightedEdge, false));
}
if (cell != null && isHighlightable(cell)) {
highlightedEdge = cell;
cellsToRepaint.addAll(highlightEdge(model, highlightedEdge, true));
} else {
highlightedEdge = null;
}
}
if (!cellsToRepaint.isEmpty()) {
mxRectangle bounds = model.getPaintBounds(cellsToRepaint.toArray());
model.repaint(bounds);
}
}
private static boolean isHighlightable(mxCell cell) {
return cell.isEdge() && !cell.getStyle().equals(SVNRevisionGraph.IN_BRANCH_LINK_STYLE);
}
private static Set<mxCell> highlightEdge(RevisionGraphModel model, mxCell edge, boolean on) {
Set<mxCell> changedCells = new HashSet<mxCell>();
Revision targetRev = ((RevisionGraphModel.Node)edge.getTarget().getValue()).revisions.get(0);
List<Revision> copiedOrMergedRevisions = targetRev.getCopiedOrMergedRevisions();
for (Revision r : copiedOrMergedRevisions) {
mxCell cell = model.getCellForRevision(r);
if (cell != null) {
changedCells.add(cell);
}
}
for (mxCell cell : changedCells) {
List<Revision> cellRevs = ((RevisionGraphModel.Node)cell.getValue()).revisions;
highlightCell(cell, !on ? State.OFF : copiedOrMergedRevisions.containsAll(cellRevs) ? State.ON : State.PARTIAL);
}
highlightCell(edge, !on ? State.OFF : State.ON);
changedCells.add(edge);
return changedCells;
}
public static State getState(mxCell cell) {
Object state = ((RevisionGraphModel.Node) cell.getValue()).properties.get(HIGHLIGHTED_PROPERTY);
return (state instanceof State) ? (State) state : State.OFF;
}
private static void highlightCell(mxCell cell, State state) {
Map<String, Object> props = ((RevisionGraphModel.Node) cell.getValue()).properties;
if (state == State.OFF) {
props.remove(HIGHLIGHTED_PROPERTY);
} else {
props.put(HIGHLIGHTED_PROPERTY, state);
}
}
}