/*******************************************************************************
* Copyright (c) 2013 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures;
import org.eclipse.draw2d.AbstractPointListShape;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Polygon;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.Shape;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.ICompareColor;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg.Sign;
import org.eclipse.swt.graphics.Color;
/**
* Class which allows to manage the look of edges decorators.<br>
* Phantoms are simple lines with bendpoints. Markers are polygons around the focused edge.
*
* @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
*/
public class EdgeFigure extends DecoratorFigure {
/** A child figure to fill background of the polygon with a transparent color (for marker). */
private AbstractPointListShape fChildMarkerFigure;
/**
* Constructor.
*
* @param difference
* The difference related to this edge decorator.
* @param isThreeWay
* The kind of comparison.
* @param compareColor
* The compare color used to color this decorator.
* @param reference
* The figure used as reference to draw this decorator.
* @param bounds
* The bounds of this edge decorator.
* @param isPhantom
* True if it is the phantom version which has to be drawn, False for the marker version.
*/
public EdgeFigure(Diff difference, boolean isThreeWay, ICompareColor compareColor, IFigure reference,
Rectangle bounds, boolean isPhantom) {
super(difference, isThreeWay, compareColor, reference, bounds, isPhantom);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#createFigureForPhantom()
* It draws a simple line (with bend points) for the phantom.
*/
@Override
protected AbstractPointListShape createFigureForPhantom() {
return new PolylineConnection();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#createFigureForMarker()
* It creates a polygon shape around the object of interest (an edge for i.e.).
*/
@Override
protected AbstractPointListShape createFigureForMarker() {
return new Polygon();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#buildFigureForPhantom()
* It retrieves the bend points from the reference figure to draw the phantom.
*/
@Override
protected void buildFigureForPhantom() {
if (getReference() instanceof PolylineConnection) {
((PolylineConnection)getMainFigure())
.setPoints(((PolylineConnection)getReference()).getPoints().getCopy());
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#buildFigureForMarker()
* It buils the marker thanks to 2 figures: the main one to define contours and a child one to fill
* the shape with a transparent color.
*/
@Override
protected void buildFigureForMarker() {
((Shape)getMainFigure()).setOpaque(false);
((Shape)getMainFigure()).setFill(false);
buildPolygon((AbstractPointListShape)getMainFigure());
fChildMarkerFigure = createFigureForMarker();
buildPolygon(fChildMarkerFigure);
getMainFigure().add(fChildMarkerFigure);
}
/**
* It builds the polygon figure (for the marker).
*
* @param polygon
* the polygon figure.
*/
private void buildPolygon(AbstractPointListShape polygon) {
PointList refPoints = ((PolylineConnection)getReference()).getPoints();
int nbPoints = refPoints.size();
PointList targetPoints = new PointList();
LineSeg previousTargetSeg = null;
for (int i = 0; i < nbPoints; i++) {
Point start = refPoints.getPoint(i);
if (i + 1 < nbPoints) {
Point end = refPoints.getPoint(i + 1);
LineSeg segRef = new LineSeg(start, end);
previousTargetSeg = computePoints(targetPoints, previousTargetSeg, segRef);
} else if (previousTargetSeg != null) {
targetPoints.addPoint(previousTargetSeg.getTerminus());
}
}
previousTargetSeg = null;
for (int i = nbPoints - 1; i >= 0; i--) {
Point start = refPoints.getPoint(i);
if (i - 1 >= 0) {
Point end = refPoints.getPoint(i - 1);
LineSeg segRef = new LineSeg(start, end);
previousTargetSeg = computePoints(targetPoints, previousTargetSeg, segRef);
} else if (previousTargetSeg != null) {
targetPoints.addPoint(previousTargetSeg.getTerminus());
}
}
polygon.setPoints(targetPoints);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#highlightForMarker(org.eclipse.draw2d.IFigure)
*/
@Override
protected void highlightForMarker(IFigure figure) {
Color strokeColor = getStrokeColor(true);
((AbstractPointListShape)figure).setForegroundColor(strokeColor);
((AbstractPointListShape)figure).setLineWidth(((Shape)figure).getLineWidth() + 1);
fChildMarkerFigure.setForegroundColor(strokeColor);
fChildMarkerFigure.setBackgroundColor(strokeColor);
fChildMarkerFigure.setAlpha(getAlpha());
fChildMarkerFigure.setFill(true);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diagram.ide.ui.internal.contentmergeviewer.diagram.figures.DecoratorFigure#unhighlightForMarker(org.eclipse.draw2d.IFigure)
*/
@Override
protected void unhighlightForMarker(IFigure figure) {
Color strokeColor = getStrokeColor(false);
((AbstractPointListShape)figure).setForegroundColor(strokeColor);
((AbstractPointListShape)figure).setLineWidth(((Shape)figure).getLineWidth() - 1);
fChildMarkerFigure.setForegroundColor(strokeColor);
fChildMarkerFigure.setBackgroundColor(strokeColor);
fChildMarkerFigure.setFill(false);
}
/**
* Compute the points to add to the polygon being drawn, from the given line segment (<code>lineSeg</code>
* ) of the focused edge. The points are added in the given point list.
*
* @param targetPoints
* The list of polygon points updated by the call of this method.
* @param previousTargetSeg
* The previous computed polygon segment.
* @param segRef
* The current line segment of the focused edge.
* @return A new computed segment for the polygon.
*/
private LineSeg computePoints(PointList targetPoints, LineSeg previousTargetSeg, LineSeg segRef) {
// Compute a parallel segment to the given one (segRef)
Point target = segRef.locatePoint(0.0, getDecoratorThickness(), Sign.POSITIVE);
LineSeg targetSeg = segRef.getParallelLineSegThroughPoint(target);
if (previousTargetSeg != null) {
Point instersection = targetSeg.intersect(previousTargetSeg, 1);
if (instersection != null) {
// This segment intersects with the previous one
targetPoints.addPoint(instersection);
} else {
// This segment does not intersect with the previous one
targetPoints.addPoint(previousTargetSeg.getTerminus());
targetPoints.addPoint(targetSeg.getOrigin());
}
} else {
// It is the fist point of the focused edge.
targetPoints.addPoint(targetSeg.getOrigin());
}
return targetSeg;
}
}