Source of SegmentedLineEdge.java


  1: import java.awt.Color;
  2: import java.awt.Dimension;
  3: import java.awt.Graphics2D;
  4: import java.awt.Shape;
  5: import java.awt.Stroke;
  6: import java.awt.geom.GeneralPath;
  7: import java.awt.geom.Line2D;
  8: import java.awt.geom.Point2D;
  9: import java.awt.geom.Rectangle2D;
 10: import java.util.ArrayList;

 12: import javax.swing.JLabel;

 14: /**
 15:    An edge that is composed of multiple line segments
 16: */
 17: public abstract class SegmentedLineEdge extends ShapeEdge
 18: {
 19:    /**
 20:       Costructs an edge with no adornments.
 21:    */
 22:    public SegmentedLineEdge()
 23:    {
 24:       lineStyle = LineStyle.SOLID;
 25:       startArrowHead = ArrowHead.NONE;
 26:       endArrowHead = ArrowHead.NONE;
 27:       startLabel = "";
 28:       middleLabel = "";
 29:       endLabel = "";
 30:    }

 32:    /**
 33:       Sets the line style property.
 34:       @param newValue the new value
 35:    */
 36:    public void setLineStyle(LineStyle newValue) { lineStyle = newValue; }

 38:    /**
 39:       Gets the line style property.
 40:       @return the line style
 41:    */
 42:    public LineStyle getLineStyle() { return lineStyle; }

 44:    /**
 45:       Sets the start arrow head property
 46:       @param newValue the new value
 47:    */
 48:    public void setStartArrowHead(ArrowHead newValue) { startArrowHead = newValue; }

 50:    /**
 51:       Gets the start arrow head property
 52:       @return the start arrow head style
 53:    */
 54:    public ArrowHead getStartArrowHead() { return startArrowHead; }

 56:    /**
 57:       Sets the end arrow head property
 58:       @param newValue the new value
 59:    */
 60:    public void setEndArrowHead(ArrowHead newValue) { endArrowHead = newValue; }

 62:    /**
 63:       Gets the end arrow head property
 64:       @return the end arrow head style
 65:    */
 66:    public ArrowHead getEndArrowHead() { return endArrowHead; }

 68:    /**
 69:       Sets the start label property
 70:       @param newValue the new value
 71:    */
 72:    public void setStartLabel(String newValue) { startLabel = newValue; }

 74:    /**
 75:       Gets the start label property
 76:       @return the label at the start of the edge
 77:    */
 78:    public String getStartLabel() { return startLabel; }

 80:    /**
 81:       Sets the middle label property
 82:       @param newValue the new value
 83:    */
 84:    public void setMiddleLabel(String newValue) { middleLabel = newValue; }

 86:    /**
 87:       Gets the middle label property
 88:       @return the label at the middle of the edge
 89:    */
 90:    public String getMiddleLabel() { return middleLabel; }

 92:    /**
 93:       Sets the end label property
 94:       @param newValue the new value
 95:    */
 96:    public void setEndLabel(String newValue) { endLabel = newValue; }

 98:    /**
 99:       Gets the end label property
100:       @return the label at the end of the edge
101:    */
102:    public String getEndLabel() { return endLabel; }

104:    /**
105:       Draws the edge.
106:       @param g2 the graphics context
107:    */
108:    public void draw(Graphics2D g2)
109:    {
110:       ArrayList points = getPoints();
111:       
112:       Stroke oldStroke = g2.getStroke();
113:       g2.setStroke(lineStyle.getStroke());
114:       g2.draw(getSegmentPath());
115:       g2.setStroke(oldStroke);
116:       startArrowHead.draw(g2, (Point2D)points.get(1),
117:          (Point2D)points.get(0));
118:       endArrowHead.draw(g2, (Point2D)points.get(points.size() - 2),
119:          (Point2D)points.get(points.size() - 1));

121:       drawString(g2, (Point2D)points.get(1), (Point2D)points.get(0), 
122:             startArrowHead, startLabel, false);
123:       drawString(g2, (Point2D)points.get(points.size() / 2 - 1),
124:             (Point2D)points.get(points.size() / 2),
125:             null, middleLabel, true);
126:       drawString(g2, (Point2D)points.get(points.size() - 2),
127:             (Point2D)points.get(points.size() - 1), 
128:             endArrowHead, endLabel, false);
129:    }

131:    /**
132:       Draws a string.
133:       @param g2 the graphics context
134:       @param p an endpoint of the segment along which to
135:       draw the string
136:       @param q the other endpoint of the segment along which to
137:       draw the string
138:       @param s the string to draw
139:       @param center true if the string should be centered
140:       along the segment
141:    */
142:    private static void drawString(Graphics2D g2, 
143:       Point2D p, Point2D q, ArrowHead arrow, String s, boolean center)
144:    {
145:       if (s == null || s.length() == 0) return;
146:       label.setText("<html>" + s + "</html>");
147:       label.setFont(g2.getFont());
148:       Dimension d = label.getPreferredSize();      
149:       label.setBounds(0, 0, d.width, d.height);

151:       Rectangle2D b = getStringBounds(g2, p, q, arrow, s, center);
152:       
153:       Color oldColor = g2.getColor();
154:       g2.setColor(g2.getBackground());
155:       g2.fill(b);
156:       g2.setColor(oldColor);
157:       
158:       g2.translate(b.getX(), b.getY());
159:       label.paint(g2);
160:       g2.translate(-b.getX(), -b.getY());        
161:    }

163:    /**
164:       Computes the attachment point for drawing a string.
165:       @param g2 the graphics context
166:       @param p an endpoint of the segment along which to
167:       draw the string
168:       @param q the other endpoint of the segment along which to
169:       draw the string
170:       @param b the bounds of the string to draw
171:       @param center true if the string should be centered
172:       along the segment
173:       @return the point at which to draw the string
174:    */
175:    private static Point2D getAttachmentPoint(Graphics2D g2, 
176:       Point2D p, Point2D q, ArrowHead arrow, Dimension d, boolean center)
177:    {    
178:       final int GAP = 3;
179:       double xoff = GAP;
180:       double yoff = -GAP - d.getHeight();
181:       Point2D attach = q;
182:       if (center)
183:       {
184:          if (p.getX() > q.getX()) 
185:          { 
186:             return getAttachmentPoint(g2, q, p, arrow, d, center); 
187:          }
188:          attach = new Point2D.Double((p.getX() + q.getX()) / 2, 
189:             (p.getY() + q.getY()) / 2);
190:          if (p.getY() < q.getY())
191:             yoff =  - GAP - d.getHeight();
192:          else if (p.getY() == q.getY())
193:             xoff = -d.getWidth() / 2;
194:          else
195:             yoff = GAP;
196:       }
197:       else 
198:       {
199:          if (p.getX() < q.getX())
200:          {
201:             xoff = -GAP - d.getWidth();
202:          }
203:          if (p.getY() > q.getY())
204:          {
205:             yoff = GAP;
206:          }
207:          if (arrow != null)
208:          {
209:             Rectangle2D arrowBounds = arrow.getPath(p, q).getBounds2D();
210:             if (p.getX() < q.getX())
211:             {
212:                xoff -= arrowBounds.getWidth();
213:             }
214:             else
215:             {
216:                xoff += arrowBounds.getWidth();
217:             }
218:          }
219:       }
220:       return new Point2D.Double(attach.getX() + xoff, attach.getY() + yoff);
221:    }

223:    /**
224:       Computes the extent of a string that is drawn along a line segment.
225:       @param g2 the graphics context
226:       @param p an endpoint of the segment along which to
227:       draw the string
228:       @param q the other endpoint of the segment along which to
229:       draw the string
230:       @param s the string to draw
231:       @param center true if the string should be centered
232:       along the segment
233:       @return the rectangle enclosing the string
234:    */
235:    private static Rectangle2D getStringBounds(Graphics2D g2, 
236:       Point2D p, Point2D q, ArrowHead arrow, String s, boolean center)
237:    {
238:       if (g2 == null) return new Rectangle2D.Double();
239:       if (s == null || s.equals("")) return new Rectangle2D.Double(q.getX(), q.getY(), 0, 0);
240:       label.setText("<html>" + s + "</html>");
241:       label.setFont(g2.getFont());
242:       Dimension d = label.getPreferredSize();
243:       Point2D a = getAttachmentPoint(g2, p, q, arrow, d, center);
244:       return new Rectangle2D.Double(a.getX(), a.getY(), d.getWidth(), d.getHeight());
245:    }

247:    public Rectangle2D getBounds(Graphics2D g2)
248:    {
249:       ArrayList points = getPoints();
250:       Rectangle2D r = super.getBounds(g2);
251:       r.add(getStringBounds(g2, 
252:                (Point2D)points.get(1), (Point2D)points.get(0), 
253:                startArrowHead, startLabel, false));
254:       r.add(getStringBounds(g2, 
255:                (Point2D)points.get(points.size() / 2 - 1),
256:                (Point2D)points.get(points.size() / 2), 
257:                null, middleLabel, true));
258:       r.add(getStringBounds(g2, 
259:                (Point2D)points.get(points.size() - 2),
260:                (Point2D)points.get(points.size() - 1), 
261:                endArrowHead, endLabel, false));
262:       return r;
263:    }

265:    public Shape getShape()
266:    {
267:       GeneralPath path = getSegmentPath();
268:       ArrayList points = getPoints();
269:       path.append(startArrowHead.getPath((Point2D)points.get(1),
270:             (Point2D)points.get(0)), false);
271:       path.append(endArrowHead.getPath((Point2D)points.get(points.size() - 2),
272:             (Point2D)points.get(points.size() - 1)), false);
273:       return path;
274:    }

276:    private GeneralPath getSegmentPath()
277:    {
278:       ArrayList points = getPoints();
279:       
280:       GeneralPath path = new GeneralPath();
281:       Point2D p = (Point2D) points.get(points.size() - 1);
282:       path.moveTo((float) p.getX(), (float) p.getY());
283:       for (int i = points.size() - 2; i >= 0; i--)
284:       {
285:          p = (Point2D) points.get(i);
286:          path.lineTo((float) p.getX(), (float) p.getY());
287:       }
288:       return path;
289:    }
290:    
291:    public Line2D getConnectionPoints()
292:    {
293:       ArrayList points = getPoints();
294:       return new Line2D.Double((Point2D) points.get(0),
295:          (Point2D) points.get(points.size() - 1));
296:    }

298:    /**
299:       Gets the corner points of this segmented line edge
300:       @return an array list of Point2D objects, containing
301:       the corner points
302:    */
303:    public abstract ArrayList getPoints();

305:    private LineStyle lineStyle;
306:    private ArrowHead startArrowHead;
307:    private ArrowHead endArrowHead;
308:    private String startLabel;
309:    private String middleLabel;
310:    private String endLabel;
311:    
312:    private static JLabel label = new JLabel();
313: }