    001: import java.awt.Font;
    002: import java.awt.Graphics2D;
    003: import java.awt.Stroke;
    004: import java.awt.font.FontRenderContext;
    005: import java.awt.geom.GeneralPath;
    006: import java.awt.geom.Line2D;
    007: import java.awt.geom.Point2D;
    008: import java.awt.geom.Rectangle2D;
    009: import java.util.ArrayList;
    010:
    011: /**
    012:    An edge that is composed of multiple line segments
    013: */
    014: public abstract class SegmentedLineEdge extends GeneralPathEdge
    015: {
    016:    /**
    017:       Costructs an edge with no adornments.
    018:    */
    019:    public SegmentedLineEdge()
    020:    {
    021:       lineStyle = LineStyle.SOLID;
    022:       startArrowHead = ArrowHead.NONE;
    023:       endArrowHead = ArrowHead.NONE;
    024:       startLabel = "";
    025:       middleLabel = "";
    026:       endLabel = "";
    027:    }
    028:
    029:    /**
    030:       Sets the line style property.
    031:       @param newValue the new value
    032:    */
    033:    public void setLineStyle(LineStyle newValue) { lineStyle = newValue; }
    034:
    035:    /**
    036:       Gets the line style property.
    037:       @return the line style
    038:    */
    039:    public LineStyle getLineStyle() { return lineStyle; }
    040:
    041:    /**
    042:       Sets the start arrow head property
    043:       @param newValue the new value
    044:    */
    045:    public void setStartArrowHead(ArrowHead newValue) { startArrowHead = newValue; }
    046:
    047:    /**
    048:       Gets the start arrow head property
    049:       @return the start arrow head style
    050:    */
    051:    public ArrowHead getStartArrowHead() { return startArrowHead; }
    052:
    053:    /**
    054:       Sets the end arrow head property
    055:       @param newValue the new value
    056:    */
    057:    public void setEndArrowHead(ArrowHead newValue) { endArrowHead = newValue; }
    058:
    059:    /**
    060:       Gets the end arrow head property
    061:       @return the end arrow head style
    062:    */
    063:    public ArrowHead getEndArrowHead() { return endArrowHead; }
    064:
    065:    /**
    066:       Sets the start label property
    067:       @param newValue the new value
    068:    */
    069:    public void setStartLabel(String newValue) { startLabel = newValue; }
    070:
    071:    /**
    072:       Gets the start label property
    073:       @return the label at the start of the edge
    074:    */
    075:    public String getStartLabel() { return startLabel; }
    076:
    077:    /**
    078:       Sets the middle label property
    079:       @param newValue the new value
    080:    */
    081:    public void setMiddleLabel(String newValue) { middleLabel = newValue; }
    082:
    083:    /**
    084:       Gets the middle label property
    085:       @return the label at the middle of the edge
    086:    */
    087:    public String getMiddleLabel() { return middleLabel; }
    088:
    089:    /**
    090:       Sets the end label property
    091:       @param newValue the new value
    092:    */
    093:    public void setEndLabel(String newValue) { endLabel = newValue; }
    094:
    095:    /**
    096:       Gets the end label property
    097:       @return the label at the end of the edge
    098:    */
    099:    public String getEndLabel() { return endLabel; }
    100:
    101:    /**
    102:       Draws the edge.
    103:       @param g2 the graphics context
    104:    */
    105:    public void draw(Graphics2D g2)
    106:    {
    107:       Stroke oldStroke = g2.getStroke();
    108:       g2.setStroke(lineStyle.getStroke());
    109:       g2.draw(getPath());
    110:       g2.setStroke(oldStroke);
    111:       ArrayList points = getPoints();
    112:       startArrowHead.draw(g2, (Point2D) points.get(1),
    113:          (Point2D) points.get(0));
    114:       endArrowHead.draw(g2, (Point2D) points.get(points.size() - 2),
    115:          (Point2D) points.get(points.size() - 1));
    116:
    117:       drawString(g2, (Point2D) points.get(1), (Point2D) points.get(0),
    118:          startLabel, false);
    119:       drawString(g2, (Point2D) points.get(points.size() / 2 - 1),
    120:          (Point2D) points.get(points.size() / 2),
    121:          middleLabel, true);
    122:       drawString(g2, (Point2D) points.get(points.size() - 2),
    123:          (Point2D) points.get(points.size() - 1),
    124:          endLabel, false);
    125:    }
    126:
    127:    /**
    128:       Draws a string.
    129:       @param g2 the graphics context
    130:       @param p an endpoint of the segment along which to
    131:       draw the string
    132:       @param q the other endpoint of the segment along which to
    133:       draw the string
    134:       @param s the string to draw
    135:       @param center true if the string should be centered
    136:       along the segment
    137:    */
    138:
    139:    public static void drawString(Graphics2D g2,
    140:       Point2D p, Point2D q, String s, boolean center)
    141:    {
    142:       Point2D a = getAttachmentPoint(g2, p, q, s, center);
    143:       g2.drawString(s, (float) a.getX(), (float) a.getY());
    144:    }
    145:
    146:    /**
    147:       Computes the attachment point for drawing a string.
    148:       @param g2 the graphics context
    149:       @param p an endpoint of the segment along which to
    150:       draw the string
    151:       @param q the other endpoint of the segment along which to
    152:       draw the string
    153:       @param s the string to draw
    154:       @param center true if the string should be centered
    155:       along the segment
    156:       @return the point at which to draw the string
    157:    */
    158:    private static Point2D getAttachmentPoint(Graphics2D g2,
    159:       Point2D p, Point2D q, String s, boolean center)
    160:    {
    161:       if (s == null) s = "";
    162:       Font font = g2.getFont();
    163:       FontRenderContext frc = g2.getFontRenderContext();
    164:       Rectangle2D b = font.getStringBounds(s, frc);
    165:       final int GAP = 3;
    166:       double xoff = GAP;
    167:       double yoff = -GAP;
    168:       Point2D attach = q;
    169:       if (center)
    170:       {
    171:          if (p.getX() > q.getX())
    172:          {
    173:             return getAttachmentPoint(g2, q, p, s, center);
    174:          }
    175:          attach = new Point2D.Double((p.getX() + q.getX()) / 2,
    176:             (p.getY() + q.getY()) / 2);
    177:          if (p.getY() < q.getY())
    178:             yoff = b.getY() + b.getHeight() - GAP;
    179:          else if (p.getY() == q.getY())
    180:             xoff = -b.getWidth() / 2;
    181:          else
    182:             yoff = -b.getY() + GAP;
    183:       }
    184:       else
    185:       {
    186:          if (p.getX() < q.getX())
    187:          {
    188:             xoff = -GAP - b.getWidth();
    189:          }
    190:          if (p.getY() > q.getY())
    191:          {
    192:             yoff = -b.getY() + GAP;
    193:          }
    194:       }
    195:       return new Point2D.Double(attach.getX() + xoff, attach.getY() + yoff);
    196:    }
    197:
    198:    /**
    199:       Computes the extent of a string that is drawn along a line segment.
    200:       @param g2 the graphics context
    201:       @param p an endpoint of the segment along which to
    202:       draw the string
    203:       @param q the other endpoint of the segment along which to
    204:       draw the string
    205:       @param s the string to draw
    206:       @param center true if the string should be centered
    207:       along the segment
    208:       @return the rectangle enclosing the string
    209:    */
    210:    public static Rectangle2D getStringBounds(Graphics2D g2,
    211:       Point2D p, Point2D q, String s, boolean center)
    212:    {
    213:       if (g2 == null) return new Rectangle2D.Double();
    214:       Font font = g2.getFont();
    215:       FontRenderContext frc = g2.getFontRenderContext();
    216:       Rectangle2D b = font.getStringBounds(s, frc);
    217:       Point2D a = getAttachmentPoint(g2, p, q, s, center);
    218:       return new Rectangle2D.Double(b.getX() + a.getX(),
    219:          b.getY() + a.getY(), b.getWidth(), b.getHeight());
    220:    }
    221:
    222:    public Rectangle2D getBounds(Graphics2D g2)
    223:    {
    224:       ArrayList points = getPoints();
    225:       Rectangle2D r = super.getBounds(g2);
    226:       r.add(getStringBounds(g2,
    227:                (Point2D) points.get(1), (Point2D) points.get(0),
    228:                startLabel, false));
    229:       r.add(getStringBounds(g2,
    230:                (Point2D) points.get(points.size() / 2 - 1),
    231:                (Point2D) points.get(points.size() / 2),
    232:                middleLabel, true));
    233:       r.add(getStringBounds(g2,
    234:                (Point2D) points.get(points.size() - 2),
    235:                (Point2D) points.get(points.size() - 1),
    236:                endLabel, false));
    237:       return r;
    238:    }
    239:
    240:    public GeneralPath getPath()
    241:    {
    242:       ArrayList points = getPoints();
    243:       GeneralPath path = new GeneralPath();
    244:       Point2D p = (Point2D) points.get(points.size() - 1);
    245:       path.moveTo((float) p.getX(), (float) p.getY());
    246:       for (int i = points.size() - 2; i >= 0; i--)
    247:       {
    248:          p = (Point2D) points.get(i);
    249:          path.lineTo((float) p.getX(), (float) p.getY());
    250:       }
    251:       return path;
    252:    }
    253:
    254:    public Line2D getConnectionPoints()
    255:    {
    256:       ArrayList points = getPoints();
    257:       return new Line2D.Double((Point2D) points.get(0),
    258:          (Point2D) points.get(points.size() - 1));
    259:    }
    260:
    261:    /**
    262:       Gets the corner points of this segmented line edge
    263:       @return an array list of Point2D objects, containing
    264:       the corner points
    265:    */
    266:    public abstract ArrayList getPoints();
    267:
    268:    private LineStyle lineStyle;
    269:    private ArrowHead startArrowHead;
    270:    private ArrowHead endArrowHead;
    271:    private String startLabel;
    272:    private String middleLabel;
    273:    private String endLabel;
    274: }