org.jgraph.graph.EdgeRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ingeniasjgraphmod Show documentation
Show all versions of ingeniasjgraphmod Show documentation
A modified version of some JGraph files
The newest version!
/*
* $Id: EdgeRenderer.java,v 1.19 2008/05/20 18:21:48 david Exp $ *
* Copyright (c) 2001-2007 Gaudenz Alder
*
* See LICENSE file in distribution for licensing details of this source file
*/
package org.jgraph.graph;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.UIManager;
import org.jgraph.JGraph;
import org.jgraph.util.Bezier;
import org.jgraph.util.Spline2D;
/**
* This renderer displays entries that implement the CellView interface.
*
* @version 1.0 1/1/02
* @author Gaudenz Alder
*/
public class EdgeRenderer extends JComponent implements CellViewRenderer,
Serializable {
/** Static Graphics used for Font Metrics */
protected static transient Graphics fontGraphics;
// Headless environment does not allow graphics
static {
try {
fontGraphics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB)
.getGraphics();
} catch (Error e) {
// No font graphics
fontGraphics = null;
}
}
/** When zooming a graph the font size jumps at certain zoom levels rather than
* scaling smoothly. Sometimes the zoom on the font is more than the component zoom
* and cropping occurs. This buffer allows for the maximum occurance of this
*/
public static double LABELWIDTHBUFFER = 1.1;
/** A switch for painting the extra labels */
public boolean simpleExtraLabels = true;
/** Override this if you want the extra labels to appear in a special fontJ */
public Font extraLabelFont = null;
/** Reference to the font metrics of the above */
protected transient FontMetrics metrics;
/** Cache the current graph for drawing */
protected transient WeakReference graph;
/** Cache the current edgeview for drawing */
private transient EdgeView view;
/** Painting attributes of the current edgeview */
protected transient int beginDeco, endDeco, beginSize, endSize, lineStyle;
/** Width of the current edge view */
protected transient float lineWidth;
/**
* Boolean attributes of the current edgeview. Fill flags are checked for
* valid decorations.
*/
protected transient boolean labelBorder, beginFill, endFill, focus,
selected, preview, opaque, childrenSelected, labelTransformEnabled,
isMoveBelowZero;
/**
* Color attributes of the current edgeview. This components foreground is
* set to the edgecolor, the fontColor is in an extra variable. If the
* fontColor is null, the current foreground is used. The default background
* instead is used for text and is not visible if the label is not visible
* or if opaque is true.
*/
protected transient Color borderColor, defaultForeground,
defaultBackground, fontColor;
/** Contains the current dash pattern. Null means no pattern. */
protected transient float[] lineDash;
/** Contains the current dash offset. Null means no offset. */
protected transient float dashOffset = 0.0f;
/** The gradient color of the edge */
protected transient Color gradientColor = null;
/** The color of the graph grid */
protected transient Color gridColor = null;
/** The color of the second available handle */
protected transient Color lockedHandleColor = null;
/** The color of highlighted cells */
protected transient Color highlightColor = null;
/** Cached bezier curve */
protected transient Bezier bezier;
/** Cached spline curve */
protected transient Spline2D spline;
/**
* Constructs a renderer that may be used to render edges.
*/
public EdgeRenderer() {
defaultForeground = UIManager.getColor("Tree.textForeground");
defaultBackground = UIManager.getColor("Tree.textBackground");
}
/**
* Sets view to work with, caching necessary values until the next call of
* this method or until some other methods with explicitly specified
* different view
*/
synchronized void setView(CellView value) {
if (value instanceof EdgeView) {
view = (EdgeView) value;
installAttributes(view);
} else {
view = null;
}
}
/**
* Configure and return the renderer based on the passed in components. The
* value is typically set from messaging the graph with
* convertValueToString
.
*
* @param graph
* the graph that that defines the rendering context.
* @param view
* the cell view that should be rendered.
* @param sel
* whether the object is selected.
* @param focus
* whether the object has the focus.
* @param preview
* whether we are drawing a preview.
* @return the component used to render the value.
*/
public Component getRendererComponent(JGraph graph, CellView view,
boolean sel, boolean focus, boolean preview) {
if (view instanceof EdgeView && graph != null) {
this.gridColor = graph.getGridColor();
this.lockedHandleColor = graph.getLockedHandleColor();
this.highlightColor = graph.getHighlightColor();
this.isMoveBelowZero = graph.isMoveBelowZero();
this.graph = new WeakReference(graph);
this.focus = focus;
this.selected = sel;
this.preview = preview;
this.childrenSelected = graph.getSelectionModel()
.isChildrenSelected(view.getCell());
setView(view);
return this;
}
return null;
}
/**
* Returns true if the edge shape intersects the given rectangle.
*/
public boolean intersects(JGraph graph, CellView value, Rectangle rect) {
if (value instanceof EdgeView && graph != null && value != null) {
setView(value);
// If we have two control points, we can get rid of hit
// detection on do an intersection test on the two diagonals
// of rect and the line between the two points
EdgeView edgeView = (EdgeView) value;
if (edgeView.getPointCount() == 2) {
Point2D p0 = edgeView.getPoint(0);
Point2D p1 = edgeView.getPoint(1);
if (rect.intersectsLine(p0.getX(), p0.getY(), p1.getX(), p1
.getY()))
return true;
} else {
Graphics2D g2 = (Graphics2D) graph.getGraphics();
if (g2.hit(rect, view.getShape(), true))
return true;
}
Rectangle2D r = getLabelBounds(graph, view);
if (r != null && r.intersects(rect))
return true;
Object[] labels = GraphConstants.getExtraLabels(view
.getAllAttributes());
if (labels != null) {
for (int i = 0; i < labels.length; i++) {
r = getExtraLabelBounds(graph, view, i);
if (r != null && r.intersects(rect))
return true;
}
}
}
return false;
}
/**
* Returns the bounds of the edge shape.
*/
public Rectangle2D getBounds(CellView value) {
if (value instanceof EdgeView && value != null) {
// No need to call setView as getPaintBounds will
view = (EdgeView) value;
Rectangle2D r = getPaintBounds(view);
JGraph graph = null;
if (this.graph != null) {
graph = (JGraph)this.graph.get();
}
Rectangle2D rect = getLabelBounds(graph, view);
if (rect != null)
Rectangle2D.union(r, rect, r);
Object[] labels = GraphConstants.getExtraLabels(view
.getAllAttributes());
if (labels != null) {
for (int i = 0; i < labels.length; i++) {
rect = getExtraLabelBounds(graph, view, i);
if (rect != null)
Rectangle2D.union(r, rect, r);
}
}
int b = (int) Math.ceil(lineWidth);
r.setFrame(r.getX() - b, r.getY() - b, r.getWidth() + 2 * b, r
.getHeight()
+ 2 * b);
return r;
}
return null;
}
private boolean isLabelTransformEnabled() {
return labelTransformEnabled;
}
/**
* Estimates whether the transform for label should be applied. With the
* transform, the label will be painted along the edge. To apply transform,
* rotate graphics by the angle returned from {@link #getLabelAngle}
*
* @return true, if transform can be applied, false otherwise
*/
private boolean isLabelTransform(String label) {
if (!isLabelTransformEnabled()) {
return false;
}
Point2D p = getLabelPosition(view);
if (p != null && label != null && label.length() > 0) {
int sw = metrics.stringWidth(label);
Point2D p1 = view.getPoint(0);
Point2D p2 = view.getPoint(view.getPointCount() - 1);
double length = Math.sqrt((p2.getX() - p1.getX())
* (p2.getX() - p1.getX()) + (p2.getY() - p1.getY())
* (p2.getY() - p1.getY()));
if (!(length <= Double.NaN || length < sw)) {
return true;
}
}
return false;
}
/**
* Calculates the angle at which graphics should be rotated to paint label
* along the edge. Before calling this method always check that transform
* should be applied using {@linkisLabelTransform}
*
* @return the value of the angle, 0 if the angle is zero or can't be
* calculated
*/
private double getLabelAngle(String label) {
Point2D p = getLabelPosition(view);
double angle = 0;
if (p != null && label != null && label.length() > 0) {
int sw = metrics.stringWidth(label);
// Note: For control points you may want to choose other
// points depending on the segment the label is in.
Point2D p1 = view.getPoint(0);
Point2D p2 = view.getPoint(view.getPointCount() - 1);
// Length of the edge
double length = Math.sqrt((p2.getX() - p1.getX())
* (p2.getX() - p1.getX()) + (p2.getY() - p1.getY())
* (p2.getY() - p1.getY()));
if (!(length <= Double.NaN || length < sw)) { // Label fits into
// edge's length
// To calculate projections of edge
double cos = (p2.getX() - p1.getX()) / length;
double sin = (p2.getY() - p1.getY()) / length;
// Determine angle
angle = Math.acos(cos);
if (sin < 0) { // Second half
angle = 2 * Math.PI - angle;
}
}
if (angle > Math.PI / 2 && angle <= Math.PI * 3 / 2) {
angle -= Math.PI;
}
}
return angle;
}
/**
* Returns the label bounds of the specified view in the given graph.
*/
public Rectangle2D getLabelBounds(JGraph paintingContext, EdgeView view) {
if (paintingContext == null && graph != null) {
JGraph graph = (JGraph)this.graph.get();
paintingContext = graph;
}
// No need to call setView as getLabelPosition will
String label = (paintingContext != null) ? paintingContext
.convertValueToString(view) : String.valueOf(view.getCell());
if (label != null) {
Point2D p = getLabelPosition(view);
Dimension d = getLabelSize(view, label);
return getLabelBounds(p, d, label);
} else {
return null;
}
}
/**
* Returns the label bounds of the specified view in the given graph. Note:
* The index is the position of the String object for the label in the extra
* labels array of the view.
*/
public Rectangle2D getExtraLabelBounds(JGraph paintingContext,
EdgeView view, int index) {
if (paintingContext == null && graph != null) {
JGraph graph = (JGraph)this.graph.get();
paintingContext = graph;
}
setView(view);
Object[] labels = GraphConstants
.getExtraLabels(view.getAllAttributes());
if (labels != null && index < labels.length) {
Point2D p = getExtraLabelPosition(this.view, index);
Dimension d = getExtraLabelSize(paintingContext, this.view, index);
String label = (paintingContext != null) ? paintingContext
.convertValueToString(labels[index]) : String
.valueOf(labels[index]);
return getLabelBounds(p, d, label);
}
return new Rectangle2D.Double(getX(), getY(), 0, 0);
}
/**
* Returns the label bounds of the specified view in the given graph.
*/
public Rectangle2D getLabelBounds(Point2D p, Dimension d, String label) {
if (label != null && isLabelTransform(label)) {
// With transform label is rotated, so we should
// rotate the rectangle (sw, sh) and return the
// bounding rectangle
double angle = getLabelAngle(label);
if (angle < 0)
angle = -angle;
if (angle > Math.PI / 2)
angle %= Math.PI / 2;
double yside = Math.abs(Math.cos(angle) * d.height
+ Math.sin(angle) * d.width);
double xside = Math.abs(d.width * Math.cos(angle) + d.height
* Math.sin(angle));
// Getting maximum is not good, but I don't want to be
// drown in calculations
if (xside > yside)
yside = xside;
if (yside > xside)
xside = yside;
angle = getLabelAngle(label);
// Increasing by height is safe, but I think the precise
// value is font.descent layed on edge vector and
// projected on each axis
d.width = (int) xside + d.height;
d.height = (int) yside + d.height;
}
if (p != null && d != null) {
double x = Math.max(0, p.getX() - (d.width / 2));
double y = Math.max(0, p.getY() - (d.height / 2));
return new Rectangle2D.Double(x, y, d.width + 1, d.height + 1);
}
return null;
}
/**
* Returns the label position of the specified view in the given graph.
*/
public Point2D getLabelPosition(EdgeView view) {
setView(view);
return getLabelPosition(view.getLabelPosition());
}
/**
* Returns the label position of the specified view in the given graph.
*/
public Point2D getExtraLabelPosition(EdgeView view, int index) {
setView(view);
Point2D[] pts = GraphConstants.getExtraLabelPositions(view
.getAllAttributes());
if (pts != null && index < pts.length)
return getLabelPosition(pts[index]);
return null;
}
/**
* Returns the label position of the specified view in the given graph.
*/
protected synchronized Point2D getLabelPosition(Point2D pos) {
EdgeView view=this.view;
if (view!=null){
Rectangle2D tmp = getPaintBounds(view);
int unit = GraphConstants.PERMILLE;
Point2D p0 = view.getPoint(0);
if (pos != null && tmp != null && p0 != null) {
if (!isLabelTransformEnabled()) {
return view.getAbsoluteLabelPositionFromRelative(pos);
} else {
Point2D vector = view.getLabelVector();
if (vector!=null) {
double dx = vector.getX();
double dy = vector.getY();
double len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
double x = p0.getX() + (dx * pos.getX() / unit);
double y = p0.getY() + (dy * pos.getX() / unit);
x += (-dy * pos.getY() / len);
y += (dx * pos.getY() / len);
return new Point2D.Double(x, y);
} else {
return new Point2D.Double(p0.getX() + pos.getX(), p0.getY()
+ pos.getY());
}
}else
return pos;
}
}
}
return null;
}
/**
* Returns the label size of the specified view in the given graph.
*/
public Dimension getExtraLabelSize(JGraph paintingContext, EdgeView view,
int index) {
Object[] labels = GraphConstants
.getExtraLabels(view.getAllAttributes());
if (labels != null && index < labels.length) {
String label = (paintingContext != null) ? paintingContext
.convertValueToString(labels[index]) : String
.valueOf(labels[index]);
return getLabelSize(view, label);
}
return null;
}
/**
* Returns the label size of the specified view in the given graph.
*/
public Dimension getLabelSize(EdgeView view, String label) {
if (label != null && fontGraphics != null) {
fontGraphics.setFont(GraphConstants
.getFont(view.getAllAttributes()));
metrics = fontGraphics.getFontMetrics();
int sw = (int)(metrics.stringWidth(label) * LABELWIDTHBUFFER);
int sh = metrics.getHeight();
return new Dimension(sw, sh);
}
return null;
}
/**
* Installs the attributes of specified cell in this renderer instance. This
* means, retrieve every published key from the cells hashtable and set
* global variables or superclass properties accordingly.
*
* @param view
* the cell view to retrieve the attribute values from.
*/
protected void installAttributes(CellView view) {
Map map = view.getAllAttributes();
beginDeco = GraphConstants.getLineBegin(map);
beginSize = GraphConstants.getBeginSize(map);
beginFill = GraphConstants.isBeginFill(map) && isFillable(beginDeco);
endDeco = GraphConstants.getLineEnd(map);
endSize = GraphConstants.getEndSize(map);
endFill = GraphConstants.isEndFill(map) && isFillable(endDeco);
lineWidth = GraphConstants.getLineWidth(map);
Edge.Routing routing = GraphConstants.getRouting(map);
lineStyle = (routing != null && view instanceof EdgeView) ? routing
.getPreferredLineStyle((EdgeView) view)
: Edge.Routing.NO_PREFERENCE;
if (lineStyle == Edge.Routing.NO_PREFERENCE)
lineStyle = GraphConstants.getLineStyle(map);
lineDash = GraphConstants.getDashPattern(map);
dashOffset = GraphConstants.getDashOffset(map);
borderColor = GraphConstants.getBorderColor(map);
Color foreground = GraphConstants.getLineColor(map);
setForeground((foreground != null) ? foreground : defaultForeground);
Color background = GraphConstants.getBackground(map);
setBackground((background != null) ? background : defaultBackground);
Color gradientColor = GraphConstants.getGradientColor(map);
setGradientColor(gradientColor);
setOpaque(GraphConstants.isOpaque(map));
setFont(GraphConstants.getFont(map));
Color tmp = GraphConstants.getForeground(map);
fontColor = (tmp != null) ? tmp : getForeground();
labelTransformEnabled = GraphConstants.isLabelAlongEdge(map);
}
protected boolean isFillable(int decoration) {
return !(decoration == GraphConstants.ARROW_SIMPLE
|| decoration == GraphConstants.ARROW_LINE || decoration == GraphConstants.ARROW_DOUBLELINE);
}
/**
* Returns the bounds of the edge shape without label
*/
public Rectangle2D getPaintBounds(EdgeView view) {
Rectangle2D rec = null;
setView(view);
if (view.getShape() != null && view.getShape().getBounds()!=null)
rec = view.getShape().getBounds();
else
rec = new Rectangle2D.Double(0, 0, 0, 0);
return rec;
}
/**
* Paint the renderer.
*/
public void paint(Graphics g) {
if (view.isLeaf()) {
Shape edgeShape = view.getShape();
// Sideeffect: beginShape, lineShape, endShape
if (edgeShape != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
int c = BasicStroke.CAP_BUTT;
int j = BasicStroke.JOIN_MITER;
setOpaque(false);
super.paint(g);
translateGraphics(g);
g.setColor(getForeground());
if (lineWidth > 0) {
// g2.setStroke(new BasicStroke(lineWidth, c, j));
if (gradientColor != null && !preview) {
g2.setPaint(new GradientPaint(0, 0, getBackground(),
getWidth(), getHeight(), gradientColor, true));
}
if (view.beginShape != null) {
if (beginFill)
g2.fill(view.beginShape);
g2.draw(view.beginShape);
}
if (view.endShape != null) {
if (endFill)
g2.fill(view.endShape);
g2.draw(view.endShape);
}
if (lineDash != null) // Dash For Line Only
g2.setStroke(new BasicStroke(lineWidth, c, j, 10.0f,
lineDash, dashOffset));
if (view.lineShape != null)
g2.draw(view.lineShape);
}
if (selected) { // Paint Selected
g2.setStroke(GraphConstants.SELECTION_STROKE);
g2.setColor(highlightColor);
if (view.beginShape != null)
g2.draw(view.beginShape);
if (view.lineShape != null)
g2.draw(view.lineShape);
if (view.endShape != null)
g2.draw(view.endShape);
}
g2.setStroke(new BasicStroke(1));
g
.setFont((extraLabelFont != null) ? extraLabelFont
: getFont());
Object[] labels = GraphConstants.getExtraLabels(view
.getAllAttributes());
JGraph graph = (JGraph)this.graph.get();
if (labels != null) {
for (int i = 0; i < labels.length; i++)
paintLabel(g, graph.convertValueToString(labels[i]),
getExtraLabelPosition(view, i),
false || !simpleExtraLabels);
}
if (graph.getEditingCell() != view.getCell()) {
g.setFont(getFont());
Object label = graph.convertValueToString(view);
if (label != null) {
paintLabel(g, label.toString(), getLabelPosition(view),
true);
}
}
}
} else {
paintSelectionBorder(g);
}
}
/**
* Provided for subclassers to paint a selection border.
*/
protected void paintSelectionBorder(Graphics g) {
((Graphics2D) g).setStroke(GraphConstants.SELECTION_STROKE);
if (childrenSelected)
g.setColor(gridColor);
else if (focus && selected)
g.setColor(lockedHandleColor);
else if (selected)
g.setColor(highlightColor);
if (childrenSelected || selected) {
Dimension d = getSize();
g.drawRect(0, 0, d.width - 1, d.height - 1);
}
}
// This if for subclassers that to not want the graphics
// to be relative to the top, left corner of this component.
// Note: Override this method with an empty implementation
// if you want absolute positions for your edges
protected void translateGraphics(Graphics g) {
g.translate(-getX(), -getY());
}
/**
* Paint the specified label for the current edgeview.
*/
protected void paintLabel(Graphics g, String label, Point2D p,
boolean mainLabel) {
if (p != null && label != null && label.length() > 0 && metrics != null) {
Shape shape=g.getClip();
g.setClip(null);
int sw = metrics.stringWidth(label);
String[] lines = label.split("\n");
boolean multiline=false;
if (label.contains("\n")){
multiline=true;
int maxWidth=-1;
for (String line:lines)
maxWidth=Math.max(maxWidth, metrics.stringWidth(line));
sw=maxWidth;
}
int sh = metrics.getHeight();
Graphics2D g2 = (Graphics2D) g;
boolean applyTransform = isLabelTransform(label);
double angle = 0;
int dx = -sw / 3;
int dy = +sh / 4;
int offset = isMoveBelowZero || applyTransform ? 0 : Math
.min(0, (int) (dx + p.getX()));
g2.translate(p.getX() - offset, p.getY());
if (applyTransform) {
angle = getLabelAngle(label);
g2.rotate(angle);
}
if (GraphConstants.isOpaque(view.getAllAttributes())){
g.setColor(GraphConstants.getBackground(view.getAllAttributes()));
g.fillRect(dx-2 , -10, sw + 4,
dy+sh*lines.length+2);
} else
if (isOpaque() && mainLabel) {
g.setColor(getBackground());
g.fillRect(-sw / 2 - 1, -sh / 2 - 1, sw + 2,
sh + 2);
}
if (GraphConstants.getBorderColor(view.getAllAttributes())!=null){
Stroke os = g2.getStroke();
BasicStroke bs= new BasicStroke(2.0f, // Width
BasicStroke.CAP_ROUND, // End cap
BasicStroke.JOIN_ROUND, // Join style
10.0f, // Miter limit
new float[] {5,3}, // Dash pattern
0.0f); // Dash phase
g2.setStroke(bs);
g.setColor(GraphConstants.getBorderColor(view.getAllAttributes()));
g.drawRect(dx -2, -10, sw + 4,
dy+sh*lines.length+2 );
g2.setStroke(os);
} else
if (borderColor != null && mainLabel) {
g.setColor(borderColor);
g.drawRect(-sw / 2 - 1, -sh / 2 - 1, sw + 2,
sh + 2);
}
g.setColor(fontColor);
if (applyTransform && borderColor == null && !isOpaque()) {
// Shift label perpendicularly by the descent so it
// doesn't cross the line.
dy = -metrics.getDescent();
}
for (int k=0;k 1) {
// Following block may modify static vars as side effect (Flyweight
// Design)
EdgeView tmp = view;
Point2D[] p = null;
p = new Point2D[n];
for (int i = 0; i < n; i++) {
Point2D pt = tmp.getPoint(i);
if (pt == null)
return null; // exit
p[i] = new Point2D.Double(pt.getX(), pt.getY());
}
// End of Side-Effect Block
// Undo Possible MT-Side Effects
if (view != tmp) {
view = tmp;
installAttributes(view);
}
GeneralPath sharedPath = getCachedViewSharedPath();
// End of Undo
if (sharedPath == null) {
sharedPath=new GeneralPath(GeneralPath.WIND_NON_ZERO, n);
} else {
sharedPath.reset();
}
view.beginShape = view.lineShape = view.endShape = null;
Point2D p0 = p[0];
Point2D pe = p[n - 1];
Point2D p1 = p[1];
Point2D p2 = p[n - 2];
// if (p0!=null && pe!=null){
if (lineStyle == GraphConstants.STYLE_BEZIER && n > 2) {
bezier = new Bezier(p);
p2 = bezier.getPoint(bezier.getPointCount() - 1);
} else if (lineStyle == GraphConstants.STYLE_SPLINE && n > 2) {
spline = new Spline2D(p);
double[] point = spline.getPoint(0.9875);
// Extrapolate p2 away from the end point, pe, to avoid integer
// rounding errors becoming too large when creating the line end
double scaledX = pe.getX() - ((pe.getX() - point[0]) * 128);
double scaledY = pe.getY() - ((pe.getY() - point[1]) * 128);
p2.setLocation(scaledX, scaledY);
}
if (beginDeco != GraphConstants.ARROW_NONE) {
view.beginShape = createLineEnd(beginSize, beginDeco, p1, p0);
}
if (endDeco != GraphConstants.ARROW_NONE) {
view.endShape = createLineEnd(endSize, endDeco, p2, pe);
}
//if ( view!=null && view.sharedPath!=null && p0!=null)
boolean viewnull=view==null;
boolean sharedpnull=getCachedViewSharedPath()==null;
boolean p0null=p0==null;
sharedPath.moveTo((float) p0.getX(), (float) p0.getY());
//else
// return null;
/* THIS CODE WAS ADDED BY MARTIN KRUEGER 10/20/2003 */
if (lineStyle == GraphConstants.STYLE_BEZIER && n > 2) {
Point2D[] b = bezier.getPoints();
sharedPath.quadTo((float) b[0].getX(),
(float) b[0].getY(), (float) p1.getX(), (float) p1
.getY());
for (int i = 2; i < n - 1; i++) {
Point2D b0 = b[2 * i - 3];
Point2D b1 = b[2 * i - 2];
sharedPath.curveTo((float) b0.getX(), (float) b0
.getY(), (float) b1.getX(), (float) b1.getY(),
(float) p[i].getX(), (float) p[i].getY());
}
sharedPath.quadTo((float) b[b.length - 1].getX(),
(float) b[b.length - 1].getY(),
(float) p[n - 1].getX(), (float) p[n - 1].getY());
} else if (lineStyle == GraphConstants.STYLE_SPLINE && n > 2) {
for (double t = 0; t <= 1; t += 0.0125) {
double[] xy = spline.getPoint(t);
sharedPath.lineTo((float) xy[0], (float) xy[1]);
}
}
/* END */
else {
for (int i = 1; i < n - 1; i++)
sharedPath.lineTo((float) p[i].getX(), (float) p[i]
.getY());
boolean penull=pe==null;
boolean sharedpathnull=getCachedViewSharedPath()==null;
//if ( view!=null && view.sharedPath!=null && pe!=null)
sharedPath.lineTo((float) pe.getX(), (float) pe.getY());
}
// if ( view!=null && view.sharedPath!=null && pe!=null)
sharedPath.moveTo((float) pe.getX(), (float) pe.getY());
if (view.endShape == null && view.beginShape == null) {
// With no end decorations the line shape is the same as the
// shared path and memory
view.lineShape = sharedPath;
} else {
// if ( view!=null && view.lineShape!=null && view.sharedPath!=null)
view.lineShape = (GeneralPath) sharedPath.clone();
Shape beginShape = view.beginShape;
Shape endShape = view.endShape;// there must be some race condition that changes the
// view values before they are actually used. The other thread must set endShape attribute
// to null, since after checking view.endShape!=null, the sharedPath.append can trigger a nullpointer
// when trying to use view.endShape. To avoid nulls, a copy is made before the use
if (endShape != null)
// if ( view!=null && view.sharedPath!=null && view.endShape!=null)
sharedPath.append(endShape, true);
if (beginShape != null)
sharedPath.append(beginShape, true);
}
setCachedViewSharedPath(sharedPath);
this.view=view;
return sharedPath;
// }
}
} catch (Throwable t){
t.printStackTrace();
}
}
return null;
}
private synchronized void setCachedViewSharedPath(GeneralPath generalPath) {
view.sharedPath=generalPath;
}
private synchronized GeneralPath getCachedViewSharedPath() {
return view.sharedPath;
}
/**
* Paint the current view's direction. Sets tmpPoint as a side-effect such
* that the invoking method can use it to determine the connection point to
* this decoration.
*/
protected Shape createLineEnd(int size, int style, Point2D src, Point2D dst) {
if (src == null || dst == null)
return null;
int d = (int) Math.max(1, dst.distance(src));
int ax = (int) -(size * (dst.getX() - src.getX()) / d);
int ay = (int) -(size * (dst.getY() - src.getY()) / d);
if (style == GraphConstants.ARROW_DIAMOND) {
Polygon poly = new Polygon();
poly.addPoint((int) dst.getX(), (int) dst.getY());
poly.addPoint((int) (dst.getX() + ax / 2 + ay / 3), (int) (dst
.getY()
+ ay / 2 - ax / 3));
Point2D last = (Point2D) dst.clone();
dst.setLocation(dst.getX() + ax, dst.getY() + ay);
poly.addPoint((int) dst.getX(), (int) dst.getY());
poly.addPoint((int) (last.getX() + ax / 2 - ay / 3), (int) (last
.getY()
+ ay / 2 + ax / 3));
return poly;
} else if (style == GraphConstants.ARROW_TECHNICAL
|| style == GraphConstants.ARROW_CLASSIC) {
Polygon poly = new Polygon();
poly.addPoint((int) dst.getX(), (int) dst.getY());
poly.addPoint((int) (dst.getX() + ax + ay / 2), (int) (dst.getY()
+ ay - ax / 2));
Point2D last = (Point2D) dst.clone();
if (style == GraphConstants.ARROW_CLASSIC) {
dst.setLocation((int) (dst.getX() + ax * 2 / 3), (int) (dst
.getY() + ay * 2 / 3));
poly.addPoint((int) dst.getX(), (int) dst.getY());
} else if (style == GraphConstants.ARROW_DIAMOND) {
dst.setLocation(dst.getX() + 2 * ax, dst.getY() + 2 * ay);
poly.addPoint((int) dst.getX(), (int) dst.getY());
} else
dst.setLocation((int) (dst.getX() + ax),
(int) (dst.getY() + ay));
poly.addPoint((int) (last.getX() + ax - ay / 2), (int) (last.getY()
+ ay + ax / 2));
return poly;
} else if (style == GraphConstants.ARROW_SIMPLE) {
GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO, 4);
path.moveTo((float) (dst.getX() + ax + ay / 2), (float) (dst.getY()
+ ay - ax / 2));
path.lineTo((float) dst.getX(), (float) dst.getY());
path.lineTo((float) (dst.getX() + ax - ay / 2), (float) (dst.getY()
+ ay + ax / 2));
return path;
} else if (style == GraphConstants.ARROW_CIRCLE) {
Ellipse2D ellipse = new Ellipse2D.Float((float) (dst.getX() + ax
/ 2 - size / 2), (float) (dst.getY() + ay / 2 - size / 2),
size, size);
dst.setLocation(dst.getX() + ax, dst.getY() + ay);
return ellipse;
} else if (style == GraphConstants.ARROW_LINE
|| style == GraphConstants.ARROW_DOUBLELINE) {
GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO, 4);
path.moveTo((float) (dst.getX() + ax / 2 + ay / 2), (float) (dst
.getY()
+ ay / 2 - ax / 2));
path.lineTo((float) (dst.getX() + ax / 2 - ay / 2), (float) (dst
.getY()
+ ay / 2 + ax / 2));
if (style == GraphConstants.ARROW_DOUBLELINE) {
path.moveTo((float) (dst.getX() + ax / 3 + ay / 2),
(float) (dst.getY() + ay / 3 - ax / 2));
path.lineTo((float) (dst.getX() + ax / 3 - ay / 2),
(float) (dst.getY() + ay / 3 + ax / 2));
}
return path;
}
return null;
}
/**
* @return Returns the gradientColor.
*/
public Color getGradientColor() {
return gradientColor;
}
/**
* @param gradientColor
* The gradientColor to set.
*/
public void setGradientColor(Color gradientColor) {
this.gradientColor = gradientColor;
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void validate() {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void revalidate() {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void repaint(long tm, int x, int y, int width, int height) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void repaint(Rectangle r) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
protected void firePropertyChange(String propertyName, Object oldValue,
Object newValue) {
// Strings get interned...
if (propertyName == "text")
super.firePropertyChange(propertyName, oldValue, newValue);
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, byte oldValue,
byte newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, char oldValue,
char newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, short oldValue,
short newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, int oldValue,
int newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, long oldValue,
long newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, float oldValue,
float newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, double oldValue,
double newValue) {
}
/**
* Overridden for performance reasons. See the Implementation Note for more information.
*/
public void firePropertyChange(String propertyName, boolean oldValue,
boolean newValue) {
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy