package jetbrains.mps.vcs.diff.ui.common;
/*Generated by MPS */
import javax.swing.JComponent;
import jetbrains.mps.ide.tooltips.TooltipComponent;
import java.util.Map;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Dimension;
import jetbrains.mps.ide.tooltips.MPSToolTipManager;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.LinkedHashMap;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple;
import jetbrains.mps.smodel.ModelAccess;
import java.util.HashMap;
import jetbrains.mps.internal.collections.runtime.IterableUtils;
import jetbrains.mps.internal.collections.runtime.ISelector;
import jetbrains.mps.vcs.diff.changes.ModelChange;
import java.awt.Graphics;
import jetbrains.mps.internal.collections.runtime.IMapping;
import javax.swing.JViewport;
import java.awt.event.MouseEvent;
import java.awt.Point;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
public class DiffEditorSeparator extends JComponent implements TooltipComponent {
private static final int WIDTH = 30;
private ChangeGroupLayout myChangeGroupLayout;
private Map<ChangeGroup, Tuples._2<Bounds, Bounds>> myGroupsWithBounds;
private Map<ChangeGroup, String> myChangeGroupDescriptions;
public DiffEditorSeparator(ChangeGroupLayout changeGroupLayout) {
myChangeGroupLayout = changeGroupLayout;
ChangeListener viewportListener = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
invalidateAndRepaint();
}
};
getLeftViewport().addChangeListener(viewportListener);
getRightViewport().addChangeListener(viewportListener);
setMinimumSize(new Dimension(WIDTH, 1));
setPreferredSize(new Dimension(WIDTH, 1));
myChangeGroupLayout.addInvalidateListener(new ChangeGroupInvalidateListener() {
public void changeGroupsInvalidated() {
invalidateAndRepaint();
}
});
MPSToolTipManager.getInstance().registerComponent(this);
}
private void ensureBoundsCalculated() {
if (myGroupsWithBounds != null) {
return;
}
myGroupsWithBounds = MapSequence.fromMap(new LinkedHashMap<ChangeGroup, Tuples._2<Bounds, Bounds>>(16, (float) 0.75, false));
int leftOffset = getOffset(getLeftViewport());
int rightOffset = getOffset(getRightViewport());
for (ChangeGroup group : ListSequence.fromList(myChangeGroupLayout.getChangeGroups())) {
int leftStart = (int) group.getLeftBounds().start() + leftOffset;
int leftEnd = (int) group.getLeftBounds().end() + leftOffset;
int rightStart = (int) group.getRightBounds().start() + rightOffset;
int rightEnd = (int) group.getRightBounds().end() + rightOffset;
MapSequence.fromMap(myGroupsWithBounds).put(group, MultiTuple.<Bounds,Bounds>from(new Bounds(leftStart, leftEnd), new Bounds(rightStart, rightEnd)));
}
ModelAccess.instance().runReadAction(new Runnable() {
public void run() {
myChangeGroupDescriptions = MapSequence.fromMap(new HashMap<ChangeGroup, String>());
for (ChangeGroup group : ListSequence.fromList(myChangeGroupLayout.getChangeGroups())) {
MapSequence.fromMap(myChangeGroupDescriptions).put(group, IterableUtils.join(ListSequence.fromList(group.getChanges()).select(new ISelector<ModelChange, String>() {
public String select(ModelChange ch) {
return ch.getDescription();
}
}), "\n\n"));
}
}
});
}
@Override
protected void paintComponent(Graphics g) {
synchronized (this) {
ensureBoundsCalculated();
for (IMapping<ChangeGroup, Tuples._2<Bounds, Bounds>> groupWithBounds : MapSequence.fromMap(myGroupsWithBounds)) {
Bounds left = groupWithBounds.value()._0();
Bounds right = groupWithBounds.value()._1();
int[] xx = new int[]{0, getWidth(), getWidth(), 0};
int[] yy = new int[]{(int) left.start(), (int) right.start(), (int) right.end(), (int) left.end()};
g.setColor(ChangeColors.get(groupWithBounds.key().getChangeType()));
g.fillPolygon(xx, yy, 4);
g.setColor(ChangeColors.get(groupWithBounds.key().getChangeType()).darker());
g.drawLine(0, (int) left.start(), getWidth() - 1, (int) right.start());
g.drawLine(0, (int) left.end(), getWidth() - 1, (int) right.end());
}
}
}
private void invalidateAndRepaint() {
synchronized (this) {
myGroupsWithBounds = null;
myChangeGroupDescriptions = null;
}
repaint();
}
private JViewport getLeftViewport() {
return myChangeGroupLayout.getLeftComponent().getViewport();
}
private JViewport getRightViewport() {
return myChangeGroupLayout.getRightComponent().getViewport();
}
private int getOffset(JViewport viewport) {
return -viewport.getViewPosition().y + myChangeGroupLayout.getEditorVerticalOffset();
}
@Override
public String getMPSTooltipText(MouseEvent mouseEvent) {
synchronized (this) {
ensureBoundsCalculated();
final Point p = mouseEvent.getPoint();
IMapping<ChangeGroup, Tuples._2<Bounds, Bounds>> group = MapSequence.fromMap(myGroupsWithBounds).findFirst(new IWhereFilter<IMapping<ChangeGroup, Tuples._2<Bounds, Bounds>>>() {
public boolean accept(IMapping<ChangeGroup, Tuples._2<Bounds, Bounds>> g) {
Bounds left = g.value()._0();
Bounds right = g.value()._1();
int v1 = vectorProduct((int) left.start(), (int) right.start(), p.x, p.y);
int v2 = vectorProduct((int) left.end(), (int) right.end(), p.x, p.y);
return v1 > 0 && v2 < 0;
}
});
if (group == null) {
return null;
} else {
return MapSequence.fromMap(myChangeGroupDescriptions).get(group.key());
}
}
}
public void dispose() {
MPSToolTipManager.getInstance().unregisterComponent(this);
}
private int vectorProduct(int left, int right, int x, int y) {
int x1 = getWidth();
int y1 = right - left;
int x2 = x;
int y2 = y - left;
int z = x1 * y2 - x2 * y1;
return z;
}
}