Source Code Cross Referenced for EdgeView.java in  » Graphic-Library » jgraph » org » jgraph » graph » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Graphic Library » jgraph » org.jgraph.graph 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)EdgeView.java	1.0 03-JUL-04
0003:         * 
0004:         * Copyright (c) 2001-2004 Gaudenz Alder
0005:         *  
0006:         */
0007:        package org.jgraph.graph;
0008:
0009:        import java.awt.Cursor;
0010:        import java.awt.Dimension;
0011:        import java.awt.Graphics;
0012:        import java.awt.Graphics2D;
0013:        import java.awt.Point;
0014:        import java.awt.Rectangle;
0015:        import java.awt.Shape;
0016:        import java.awt.event.MouseEvent;
0017:        import java.awt.geom.AffineTransform;
0018:        import java.awt.geom.GeneralPath;
0019:        import java.awt.geom.Line2D;
0020:        import java.awt.geom.Point2D;
0021:        import java.awt.geom.Rectangle2D;
0022:        import java.io.Serializable;
0023:        import java.util.ArrayList;
0024:        import java.util.List;
0025:        import java.util.Map;
0026:
0027:        import javax.swing.SwingUtilities;
0028:
0029:        import org.jgraph.JGraph;
0030:        import org.jgraph.plaf.GraphUI;
0031:        import org.jgraph.plaf.basic.BasicGraphUI;
0032:
0033:        /**
0034:         * The default implementation of an edge view. The getEdgeRenderer method
0035:         * assumes a renderer of type EdgeRenderer. If you provide a custom renderer to
0036:         * a subclass, you must also override the methods that call this method, namely:
0037:         * getShape, getLabelBounds, getExtraLabelBounds, intersects and getBounds.
0038:         * 
0039:         * @version 1.0 1/1/02
0040:         * @author Gaudenz Alder
0041:         */
0042:
0043:        public class EdgeView extends AbstractCellView {
0044:
0045:            /** Renderer for the class. */
0046:            public static transient EdgeRenderer renderer = new EdgeRenderer();
0047:
0048:            /** List of points of the edge. May contain ports. */
0049:            protected List points;
0050:
0051:            /** Cached source and target portview of the edge. */
0052:            protected CellView source, target;
0053:
0054:            protected CellView sourceParentView, targetParentView;
0055:
0056:            /** Cached label position of the edge. */
0057:            protected Point2D labelPosition;
0058:
0059:            protected Point2D[] extraLabelPositions;
0060:
0061:            protected transient Point2D labelVector = null;
0062:
0063:            /** Drawing attributes that are created on the fly */
0064:            public transient Shape beginShape, endShape, lineShape;
0065:
0066:            /** Shared-path tune-up. */
0067:            public transient GeneralPath sharedPath = null;
0068:
0069:            protected transient Rectangle2D cachedBounds = null;
0070:
0071:            /**
0072:             * Constructs an empty edge view.
0073:             */
0074:            public EdgeView() {
0075:                super ();
0076:            }
0077:
0078:            /**
0079:             * Constructs an edge view for the specified model object.
0080:             * 
0081:             * @param cell
0082:             *            reference to the model object
0083:             */
0084:            public EdgeView(Object cell) {
0085:                super (cell);
0086:            }
0087:
0088:            //
0089:            // Data Source
0090:            //
0091:
0092:            /**
0093:             * Overrides the parent method to udpate the cached points, source and
0094:             * target port. If the source or target is removed, a point is inserted into
0095:             * the array of points.
0096:             */
0097:            public void refresh(GraphLayoutCache cache, CellMapper mapper,
0098:                    boolean createDependentViews) {
0099:                // Makes sure the manual control points are passed to
0100:                // the router instead of the cached control points after
0101:                // changes to the edge (normally manual point changes).
0102:                points = null;
0103:                super .refresh(cache, mapper, createDependentViews);
0104:                // Re-sync source- and targetportviews
0105:                GraphModel model = cache.getModel();
0106:                Object modelSource = model.getSource(cell);
0107:                Object modelTarget = model.getTarget(cell);
0108:                setSource(mapper.getMapping(modelSource, createDependentViews));
0109:                setTarget(mapper.getMapping(modelTarget, createDependentViews));
0110:                if (modelSource != null && getSource() == null)
0111:                    sourceParentView = getVisibleParent(model, mapper,
0112:                            modelSource);
0113:                else
0114:                    sourceParentView = null;
0115:                if (modelTarget != null && getTarget() == null)
0116:                    targetParentView = getVisibleParent(model, mapper,
0117:                            modelTarget);
0118:                else
0119:                    targetParentView = null;
0120:            }
0121:
0122:            protected CellView getVisibleParent(GraphModel model,
0123:                    CellMapper mapper, Object port) {
0124:                CellView view = null;
0125:                do {
0126:                    view = mapper.getMapping(port, false);
0127:                    port = model.getParent(port);
0128:                } while (view == null && port != null);
0129:                return view;
0130:            }
0131:
0132:            /**
0133:             * Update attributes and recurse children.
0134:             */
0135:            public void update(GraphLayoutCache cache) {
0136:                super .update(cache);
0137:                // Save the reference to the points so they can be changed
0138:                // in-place by use of setPoint, setSource, setTarget methods.
0139:                List controlPoints = GraphConstants.getPoints(allAttributes);
0140:                if (controlPoints == null) {
0141:                    controlPoints = new ArrayList(4);
0142:                    controlPoints.add(allAttributes.createPoint(10, 10));
0143:                    controlPoints.add(allAttributes.createPoint(20, 20));
0144:                    GraphConstants.setPoints(allAttributes, controlPoints);
0145:                }
0146:
0147:                // Uses the manual control points while the edge is being routed.
0148:                // Otherwise uses the cached points (eg. for preview).
0149:                if (points == null)
0150:                    points = controlPoints;
0151:
0152:                Edge.Routing routing = GraphConstants.getRouting(allAttributes);
0153:                List routedPoints = null;
0154:                // Passes the current cached points to the router
0155:                if (routing != null)
0156:                    routedPoints = routing.route(cache, this );
0157:
0158:                // Shadows the manual control points with the
0159:                // routed control points
0160:                points = (routedPoints != null && !routedPoints.isEmpty()) ? routedPoints
0161:                        : controlPoints;
0162:
0163:                // Overrides manual point locations with the real port views
0164:                if (points == controlPoints) {
0165:                    if (source != null)
0166:                        setSource(source);
0167:                    if (target != null)
0168:                        setTarget(target);
0169:                }
0170:
0171:                // Checks and caches label positions
0172:                checkDefaultLabelPosition();
0173:                Point2D[] positions = GraphConstants
0174:                        .getExtraLabelPositions(allAttributes);
0175:                if (positions != null) {
0176:                    extraLabelPositions = new Point2D[positions.length];
0177:                    for (int i = 0; i < positions.length; i++)
0178:                        extraLabelPositions[i] = positions[i];
0179:                } else
0180:                    extraLabelPositions = null;
0181:
0182:                // Clear cached shapes
0183:                beginShape = null;
0184:                endShape = null;
0185:                lineShape = null;
0186:                invalidate();
0187:            }
0188:
0189:            /**
0190:             * Hook for subclassers to avoid default label positions.
0191:             */
0192:            protected void checkDefaultLabelPosition() {
0193:                labelPosition = GraphConstants.getLabelPosition(allAttributes);
0194:                String label = String.valueOf(getCell());
0195:                if (labelPosition == null && label != null
0196:                        && label.length() > 0) {
0197:                    int center = GraphConstants.PERMILLE / 2;
0198:                    labelPosition = new Point(center, 0);
0199:                    GraphConstants.setLabelPosition(allAttributes,
0200:                            labelPosition);
0201:                }
0202:            }
0203:
0204:            /**
0205:             * Resets the cached values of the edge view
0206:             */
0207:            protected void invalidate() {
0208:                labelVector = null;
0209:                sharedPath = null;
0210:                cachedBounds = null;
0211:            }
0212:
0213:            /**
0214:             * Returns the shape of the view according to the last rendering state
0215:             */
0216:            public Shape getShape() {
0217:                if (sharedPath != null)
0218:                    return sharedPath;
0219:                else {
0220:                    return sharedPath = (GeneralPath) getEdgeRenderer()
0221:                            .createShape();
0222:                }
0223:            }
0224:
0225:            //
0226:            // View Methods
0227:            //
0228:
0229:            /**
0230:             * Returns true if this view intersects the given rectangle.
0231:             */
0232:            public boolean intersects(JGraph graph, Rectangle2D rect) {
0233:                boolean intersects = super .intersects(graph, rect);
0234:                if (!isLeaf()) {
0235:                    return intersects;
0236:                } else if (intersects) {
0237:                    Rectangle r = new Rectangle((int) rect.getX(), (int) rect
0238:                            .getY(), (int) rect.getWidth(), (int) rect
0239:                            .getHeight());
0240:                    return getEdgeRenderer().intersects(graph, this , r);
0241:                }
0242:                return false;
0243:            }
0244:
0245:            /**
0246:             * Returns the location for this edgeview.
0247:             */
0248:            public Rectangle2D getBounds() {
0249:                Rectangle2D rect = super .getBounds();
0250:                if (rect == null) {
0251:                    if (cachedBounds == null) {
0252:                        cachedBounds = getEdgeRenderer().getBounds(this );
0253:                    }
0254:                    rect = cachedBounds;
0255:                }
0256:                return rect;
0257:            }
0258:
0259:            /**
0260:             * Returns the local renderer. Do not access the renderer field directly.
0261:             * Use this method instead. Note: This method is package private.
0262:             */
0263:            EdgeRenderer getEdgeRenderer() {
0264:                return (EdgeRenderer) getRenderer();
0265:            }
0266:
0267:            /**
0268:             * Returns a renderer for the class.
0269:             */
0270:            public CellViewRenderer getRenderer() {
0271:                return renderer;
0272:            }
0273:
0274:            /**
0275:             * Returns a cell handle for the view.
0276:             */
0277:            public CellHandle getHandle(GraphContext context) {
0278:                return new EdgeHandle(this , context);
0279:            }
0280:
0281:            //
0282:            // Cached Values
0283:            //
0284:
0285:            /**
0286:             * Returns the CellView that represents the source of the edge.
0287:             */
0288:            public CellView getSource() {
0289:                return source;
0290:            }
0291:
0292:            public CellView getSourceParentView() {
0293:                return sourceParentView;
0294:            }
0295:
0296:            /**
0297:             * Sets the <code>sourceView</code> of the edge.
0298:             */
0299:            public void setSource(CellView sourceView) {
0300:                sourceParentView = null;
0301:                source = sourceView;
0302:                if (source != null)
0303:                    points.set(0, source);
0304:                else
0305:                    points.set(0, getPoint(0));
0306:                invalidate();
0307:            }
0308:
0309:            /**
0310:             * Returns the CellView that represents the target of the edge.
0311:             */
0312:            public CellView getTarget() {
0313:                return target;
0314:            }
0315:
0316:            public CellView getTargetParentView() {
0317:                return targetParentView;
0318:            }
0319:
0320:            /**
0321:             * Sets the <code>targetView</code> of the edge.
0322:             */
0323:            public void setTarget(CellView targetView) {
0324:                target = targetView;
0325:                targetParentView = null;
0326:                int n = points.size() - 1;
0327:                if (target != null)
0328:                    points.set(n, target);
0329:                else
0330:                    points.set(n, getPoint(n));
0331:                invalidate();
0332:            }
0333:
0334:            /**
0335:             * Returns a point that describes the position of the label.
0336:             */
0337:            public Point2D getExtraLabelPosition(int index) {
0338:                return extraLabelPositions[index];
0339:            }
0340:
0341:            /**
0342:             * Returns a point that describes the position of the label.
0343:             */
0344:            public Point2D getLabelPosition() {
0345:                return labelPosition;
0346:            }
0347:
0348:            /**
0349:             * Sets the description of the label position.
0350:             */
0351:            public void setLabelPosition(Point2D pos) {
0352:                labelPosition.setLocation(pos);
0353:                invalidate();
0354:            }
0355:
0356:            /**
0357:             * Sets the description of the label position.
0358:             */
0359:            public void setExtraLabelPosition(int index, Point2D pos) {
0360:                extraLabelPositions[index].setLocation(pos);
0361:                invalidate();
0362:            }
0363:
0364:            //
0365:            // Points
0366:            //
0367:
0368:            /**
0369:             * Returns true if the edge is a loop.
0370:             */
0371:            public boolean isLoop() {
0372:                return (getSource() != null && getSource() == getTarget())
0373:                        || (sourceParentView != null && sourceParentView == targetParentView)
0374:                        || (sourceParentView != null && getTarget() != null && getTarget()
0375:                                .getParentView() == sourceParentView)
0376:                        || (targetParentView != null && getSource() != null && getSource()
0377:                                .getParentView() == targetParentView);
0378:            }
0379:
0380:            /**
0381:             * Returns the points.
0382:             * 
0383:             * @return List
0384:             */
0385:            public List getPoints() {
0386:                return points;
0387:            }
0388:
0389:            /**
0390:             * Returns the number of point for this edge.
0391:             */
0392:            public int getPointCount() {
0393:                if (points != null) {
0394:                    return points.size();
0395:                } else {
0396:                    return 0;
0397:                }
0398:            }
0399:
0400:            /**
0401:             * Returns the cached points for this edge.
0402:             */
0403:            public Point2D getPoint(int index) {
0404:                Object obj = points.get(index);
0405:                if (index == 0 && sourceParentView != null) {
0406:                    return sourceParentView.getPerimeterPoint(this ,
0407:                            getCenterPoint(sourceParentView),
0408:                            getNearestPoint(index == 0));
0409:                } else if (index == getPointCount() - 1
0410:                        && targetParentView != null) {
0411:                    return targetParentView.getPerimeterPoint(this ,
0412:                            getCenterPoint(targetParentView),
0413:                            getNearestPoint(index == 0));
0414:                } else if (obj instanceof  PortView)
0415:                    // Port Location Seen From This Edge
0416:                    return ((PortView) obj).getLocation(this ,
0417:                            getNearestPoint(index == 0));
0418:                else if (obj instanceof  CellView) {
0419:                    // Should not happen
0420:                    Rectangle2D r = ((CellView) obj).getBounds();
0421:                    return new Point2D.Double(r.getX(), r.getY());
0422:                } else if (obj instanceof  Point2D)
0423:                    // Regular Point
0424:                    return (Point2D) obj;
0425:                return null;
0426:            }
0427:
0428:            /**
0429:             * Returns the nearest point wrt to the source or target. This method
0430:             * returns the next or previous point or port in the points list, eg. if
0431:             * source is true it returns the location of the point or port at index 1
0432:             * without calling the getLocation method on any ports.<br>
0433:             * Likewise, the method returns the location at index getPointCount()-2 if
0434:             * source is false.
0435:             */
0436:            protected Point2D getNearestPoint(boolean source) {
0437:                if (getPointCount() == 2) {
0438:                    if (source
0439:                            && target instanceof  PortView
0440:                            && GraphConstants.getOffset(target
0441:                                    .getAllAttributes()) != null) {
0442:                        return ((PortView) target).getLocation(this );
0443:                    }
0444:                    if (!source
0445:                            && this .source instanceof  PortView
0446:                            && GraphConstants.getOffset(this .source
0447:                                    .getAllAttributes()) != null) {
0448:                        return ((PortView) this .source).getLocation(this );
0449:                    }
0450:                    if (source && targetParentView != null
0451:                            && targetParentView.isLeaf())
0452:                        return getCenterPoint(targetParentView);
0453:                    else if (!source && sourceParentView != null
0454:                            && sourceParentView.isLeaf())
0455:                        return getCenterPoint(sourceParentView);
0456:                }
0457:                return getPointLocation((source) ? 1 : getPointCount() - 2);
0458:            }
0459:
0460:            /**
0461:             * Returns the point of <code>edge</code> at <code>index</code>. Avoids
0462:             * calling <code>getLocation</code> on any ports of <code>edge</code>.
0463:             * <br>
0464:             * This is used from within getPoint to pass the nearest point to the
0465:             * portview to find it's location. This uses the center point of the parent
0466:             * view to determine the port view's location to avoid infinite recursion.
0467:             */
0468:            protected Point2D getPointLocation(int index) {
0469:                Object obj = points.get(index);
0470:                if (obj instanceof  Point2D)
0471:                    return (Point2D) obj;
0472:                else if (obj instanceof  PortView) {
0473:                    CellView vertex = ((CellView) obj).getParentView();
0474:                    if (vertex != null)
0475:                        return getCenterPoint(vertex);
0476:                }
0477:                return null;
0478:            }
0479:
0480:            /**
0481:             * Sets the point at <code>index</code> to <code>p</code>.
0482:             */
0483:            public void setPoint(int index, Point2D p) {
0484:                points.set(index, p);
0485:                invalidate();
0486:            }
0487:
0488:            /**
0489:             * Adds <code>p</code> at position <code>index</code>.
0490:             */
0491:            public void addPoint(int index, Point2D p) {
0492:                points.add(index, p);
0493:                invalidate();
0494:            }
0495:
0496:            /**
0497:             * Removes the point at position <code>index</code>.
0498:             */
0499:            public void removePoint(int index) {
0500:                points.remove(index);
0501:                invalidate();
0502:            }
0503:
0504:            /**
0505:             * Adds an extra label.
0506:             */
0507:            public void addExtraLabel(Point2D location, Object label) {
0508:                Object[] extraLabels = GraphConstants
0509:                        .getExtraLabels(getAllAttributes());
0510:                Point2D[] positions = GraphConstants
0511:                        .getExtraLabelPositions(getAllAttributes());
0512:
0513:                // Inserts a new extra label
0514:                if (extraLabels == null) {
0515:                    extraLabels = new Object[1];
0516:                    positions = new Point2D[1];
0517:                } else {
0518:                    Object[] tmp = new Object[extraLabels.length + 1];
0519:                    System
0520:                            .arraycopy(extraLabels, 0, tmp, 0,
0521:                                    extraLabels.length);
0522:                    extraLabels = tmp;
0523:                    Point2D[] pts = new Point2D[positions.length + 1];
0524:                    System.arraycopy(positions, 0, pts, 0, positions.length);
0525:                    positions = pts;
0526:                }
0527:                int newIndex = extraLabels.length - 1;
0528:                extraLabels[newIndex] = label;
0529:                positions[newIndex] = location;
0530:                GraphConstants.setExtraLabels(getAllAttributes(), extraLabels);
0531:                GraphConstants.setExtraLabelPositions(getAllAttributes(),
0532:                        positions);
0533:            }
0534:
0535:            /**
0536:             * Removes the point at position <code>index</code>.
0537:             */
0538:            public void removeExtraLabel(int index) {
0539:                Object[] labels = GraphConstants
0540:                        .getExtraLabels(getAllAttributes());
0541:                Point2D[] pts = GraphConstants
0542:                        .getExtraLabelPositions(getAllAttributes());
0543:                if (labels == null || labels.length > 1) {
0544:                    Object[] newLabels = new Object[labels.length - 1];
0545:                    Point2D[] newPts = new Point2D[pts.length - 1];
0546:                    System.arraycopy(labels, 0, newLabels, 0, index);
0547:                    if (index < newLabels.length)
0548:                        System.arraycopy(labels, index + 1, newLabels, index,
0549:                                newLabels.length - index);
0550:                    System.arraycopy(pts, 0, newPts, 0, index);
0551:                    if (index < newPts.length)
0552:                        System.arraycopy(pts, index + 1, newPts, index,
0553:                                newPts.length - index);
0554:                    GraphConstants
0555:                            .setExtraLabels(getAllAttributes(), newLabels);
0556:                    GraphConstants.setExtraLabelPositions(getAllAttributes(),
0557:                            newPts);
0558:                } else {
0559:                    // TODO: Remove via REMOVEATTRIBUTES
0560:                    GraphConstants.setExtraLabels(getAllAttributes(),
0561:                            new Object[0]);
0562:                    GraphConstants.setExtraLabelPositions(getAllAttributes(),
0563:                            new Point2D[0]);
0564:                }
0565:            }
0566:
0567:            /**
0568:             * Hook to return the vector that is taken as the base vector to compute
0569:             * relative label positions. Normally, the vector goes from the first to the
0570:             * last point on the edge, unless these points are equal, in which case the
0571:             * average distance of all points to the source point is used.
0572:             */
0573:            public Point2D getLabelVector() {
0574:                if (labelVector == null) {
0575:                    Point2D p0 = getPoint(0);
0576:                    double dx = 0;
0577:                    double dy = 0;
0578:                    // Finds an average distance
0579:                    dx = 0;
0580:                    dy = 0;
0581:                    int n = getPointCount();
0582:                    if (isLoop()) {
0583:                        for (int i = 1; i < n; i++) {
0584:                            Point2D point = getPoint(i);
0585:                            dx += point.getX() - p0.getX();
0586:                            dy += point.getY() - p0.getY();
0587:                        }
0588:                        n /= 2;
0589:                        dx /= n;
0590:                        dy /= n;
0591:                        labelVector = new Point2D.Double(dx, dy);
0592:                    } else {
0593:                        Point2D point = getPoint(n - 1);
0594:                        dx += point.getX() - p0.getX();
0595:                        dy += point.getY() - p0.getY();
0596:                        labelVector = new Point2D.Double(dx, dy);
0597:                    }
0598:                }
0599:                return labelVector;
0600:            }
0601:
0602:            //
0603:            // Routing
0604:            //
0605:
0606:            public static double getLength(CellView view) {
0607:                double cost = 1;
0608:                if (view instanceof  EdgeView) {
0609:                    EdgeView edge = (EdgeView) view;
0610:                    Point2D last = null, current = null;
0611:                    for (int i = 0; i < edge.getPointCount(); i++) {
0612:                        current = edge.getPoint(i);
0613:                        if (last != null)
0614:                            cost += last.distance(current);
0615:                        last = current;
0616:                    }
0617:                }
0618:                return cost;
0619:            }
0620:
0621:            //
0622:            // Handle
0623:            //
0624:
0625:            // This implementation uses the point instance to make the change. No index
0626:            // is used for the current point because routing could change the index
0627:            // during
0628:            // the move operation.
0629:            public static class EdgeHandle implements  CellHandle, Serializable {
0630:
0631:                protected JGraph graph;
0632:
0633:                /* Pointer to the edge and its clone. */
0634:                protected EdgeView edge, orig;
0635:
0636:                /*
0637:                 * Boolean indicating whether the source, target or label is being
0638:                 * edited.
0639:                 */
0640:                protected boolean label = false, source = false,
0641:                        target = false;
0642:
0643:                /**
0644:                 * Holds the index of the current (editing) label or point.
0645:                 */
0646:                protected int currentLabel = -1, currentIndex = -1;
0647:
0648:                /* Pointer to the currently selected point. */
0649:                protected Point2D currentPoint;
0650:
0651:                /* Array of control points represented as rectangles. */
0652:                protected transient Rectangle2D[] r;
0653:
0654:                /* A control point for the label position. */
0655:                protected transient Rectangle2D loc;
0656:
0657:                protected transient Rectangle2D[] extraLabelLocations;
0658:
0659:                protected boolean firstOverlayCall = true;
0660:
0661:                protected boolean isEdgeConnectable = true;
0662:
0663:                protected EdgeView relevantEdge = null;
0664:
0665:                /**
0666:                 * True if the cell is being edited.
0667:                 */
0668:                protected boolean editing = false;
0669:
0670:                /**
0671:                 * Holds the initial location of the label.
0672:                 */
0673:                protected Point2D initialLabelLocation = null;
0674:
0675:                /**
0676:                 * Indicates whether the edge has been modified during the last mouse
0677:                 * pressed and dragged operations.
0678:                 */
0679:                protected boolean edgeModified = false;
0680:
0681:                public EdgeHandle(EdgeView edge, GraphContext ctx) {
0682:                    this .graph = ctx.getGraph();
0683:                    this .edge = edge;
0684:                    editing = graph.getEditingCell() == edge.getCell();
0685:                    loc = new Rectangle();
0686:                    Object[] labels = GraphConstants.getExtraLabels(edge
0687:                            .getAllAttributes());
0688:                    if (labels != null) {
0689:                        extraLabelLocations = new Rectangle[labels.length];
0690:                        for (int i = 0; i < extraLabelLocations.length; i++)
0691:                            extraLabelLocations[i] = new Rectangle();
0692:                    }
0693:                    orig = (EdgeView) graph.getGraphLayoutCache().getMapping(
0694:                            edge.getCell(), false);
0695:                    reloadPoints(orig);
0696:                    isEdgeConnectable = GraphConstants.isConnectable(edge
0697:                            .getAllAttributes());
0698:                }
0699:
0700:                protected void reloadPoints(EdgeView edge) {
0701:                    relevantEdge = edge;
0702:                    r = new Rectangle[edge.getPointCount()];
0703:                    for (int i = 0; i < r.length; i++)
0704:                        r[i] = new Rectangle();
0705:                    invalidate();
0706:                }
0707:
0708:                // Update and paint control points
0709:                public void paint(Graphics g) {
0710:                    invalidate();
0711:                    if (!edge.isLeaf())
0712:                        return;
0713:                    for (int i = 0; i < r.length; i++) {
0714:                        if (isEdgeConnectable && !editing)
0715:                            g.setColor(graph.getHandleColor());
0716:                        else
0717:                            g.setColor(graph.getLockedHandleColor());
0718:                        g.fill3DRect((int) r[i].getX(), (int) r[i].getY(),
0719:                                (int) r[i].getWidth(), (int) r[i].getHeight(),
0720:                                true);
0721:                        CellView port = null;
0722:                        if (i == 0 && edge.getSource() != null)
0723:                            port = edge.getSource();
0724:                        else if (i == r.length - 1 && edge.getTarget() != null)
0725:                            port = edge.getTarget();
0726:                        if (port != null
0727:                                || (i == 0 && edge.getSourceParentView() != null)
0728:                                || (i == r.length - 1 && edge
0729:                                        .getTargetParentView() != null)) {
0730:                            g.setColor(graph.getLockedHandleColor());
0731:                            Point2D tmp = (port != null) ? GraphConstants
0732:                                    .getOffset(port.getAllAttributes()) : null;
0733:                            if (tmp != null) {
0734:                                g
0735:                                        .drawLine((int) r[i].getX() + 1,
0736:                                                (int) r[i].getY() + 1,
0737:                                                (int) (r[i].getX() + r[i]
0738:                                                        .getWidth()) - 3,
0739:                                                (int) (r[i].getY() + r[i]
0740:                                                        .getHeight()) - 3);
0741:                                g
0742:                                        .drawLine((int) r[i].getX() + 1,
0743:                                                (int) (r[i].getY() + r[i]
0744:                                                        .getHeight()) - 3,
0745:                                                (int) (r[i].getX() + r[i]
0746:                                                        .getWidth()) - 3,
0747:                                                (int) r[i].getY() + 1);
0748:                            } else
0749:                                g.drawRect((int) r[i].getX() + 2, (int) r[i]
0750:                                        .getY() + 2, (int) r[i].getWidth() - 5,
0751:                                        (int) r[i].getHeight() - 5);
0752:                        }
0753:                    }
0754:                    if (!graph.isXorEnabled()) {
0755:                        firstOverlayCall = false;
0756:                        overlay(g);
0757:                    }
0758:                }
0759:
0760:                public void overlay(Graphics g) {
0761:                    if (edge != null && !firstOverlayCall && edge.isLeaf()) {
0762:                        // g.setColor(graph.getBackground()); // JDK 1.3
0763:                        g.setColor(graph.getForeground());
0764:                        if (graph.isXorEnabled()) {
0765:                            g.setXORMode(graph.getBackground().darker());
0766:                        }
0767:                        Graphics2D g2 = (Graphics2D) g;
0768:                        AffineTransform oldTransform = g2.getTransform();
0769:                        g2.scale(graph.getScale(), graph.getScale());
0770:                        graph.getUI()
0771:                                .paintCell(g, edge, edge.getBounds(), true);
0772:                        g2.setTransform(oldTransform);
0773:                        if (isSourceEditing() && edge.getSource() != null)
0774:                            paintPort(g, edge.getSource());
0775:                        else if (isTargetEditing() && edge.getTarget() != null)
0776:                            paintPort(g, edge.getTarget());
0777:                    }
0778:                    firstOverlayCall = false;
0779:                }
0780:
0781:                protected void paintPort(Graphics g, CellView p) {
0782:                    boolean offset = (GraphConstants.getOffset(p
0783:                            .getAllAttributes()) != null);
0784:                    Rectangle2D r = (offset) ? p.getBounds() : p
0785:                            .getParentView().getBounds();
0786:                    r = graph.toScreen((Rectangle2D) r.clone());
0787:                    int s = 3;
0788:                    r.setFrame(r.getX() - s, r.getY() - s,
0789:                            r.getWidth() + 2 * s, r.getHeight() + 2 * s);
0790:                    graph.getUI().paintCell(g, p, r, true);
0791:                }
0792:
0793:                protected boolean snap(boolean source, Point2D point) {
0794:                    boolean connect = graph.isConnectable()
0795:                            && isEdgeConnectable;
0796:                    Object port = graph.getPortForLocation(point.getX(), point
0797:                            .getY());
0798:                    if (port != null
0799:                            && graph.getModel().getParent(port) == edge
0800:                                    .getCell())
0801:                        port = null;
0802:                    if (port != null && connect) {
0803:                        CellView portView = graph.getGraphLayoutCache()
0804:                                .getMapping(port, false);
0805:                        Rectangle2D dirty = edge.getBounds();
0806:                        dirty.add(portView.getParentView().getBounds());
0807:                        if (GraphConstants.isConnectable(portView
0808:                                .getParentView().getAllAttributes())) {
0809:                            Object cell = edge.getCell();
0810:                            if (source
0811:                                    && graph.getModel().acceptsSource(cell,
0812:                                            port)) {
0813:                                if (edge.getSource() != portView) {
0814:                                    edgeModified = true;
0815:                                    if (graph.isXorEnabled()) {
0816:                                        overlay(graph.getGraphics());
0817:                                    }
0818:                                    edge.setSource(portView);
0819:                                    edge.update(graph.getGraphLayoutCache());
0820:                                    if (graph.isXorEnabled()) {
0821:                                        overlay(graph.getGraphics());
0822:                                    } else {
0823:                                        dirty.add(edge.getBounds());
0824:                                        graph.repaint((int) dirty.getX(),
0825:                                                (int) dirty.getY(), (int) dirty
0826:                                                        .getWidth(),
0827:                                                (int) dirty.getHeight());
0828:                                    }
0829:                                }
0830:                                return true;
0831:                            } else if (!source
0832:                                    && graph.getModel().acceptsTarget(cell,
0833:                                            port)) {
0834:                                if (edge.getTarget() != portView) {
0835:                                    edgeModified = true;
0836:                                    if (graph.isXorEnabled()) {
0837:                                        overlay(graph.getGraphics());
0838:                                    }
0839:                                    edge.setTarget(portView);
0840:                                    edge.update(graph.getGraphLayoutCache());
0841:                                    if (graph.isXorEnabled()) {
0842:                                        overlay(graph.getGraphics());
0843:                                    } else {
0844:                                        dirty.add(edge.getBounds());
0845:                                        graph.repaint((int) dirty.getX(),
0846:                                                (int) dirty.getY(), (int) dirty
0847:                                                        .getWidth(),
0848:                                                (int) dirty.getHeight());
0849:                                    }
0850:                                }
0851:                                return true;
0852:                            }
0853:                        }
0854:                    }
0855:                    return false;
0856:                }
0857:
0858:                public boolean isConstrainedMoveEvent(MouseEvent e) {
0859:                    GraphUI ui = graph.getUI();
0860:                    if (ui instanceof  BasicGraphUI)
0861:                        return ((BasicGraphUI) ui).isConstrainedMoveEvent(e);
0862:                    return false;
0863:                }
0864:
0865:                /**
0866:                 * Returning true signifies a mouse event adds a new point to an edge.
0867:                 */
0868:                public boolean isAddPointEvent(MouseEvent event) {
0869:                    return event.isPopupTrigger()
0870:                            || SwingUtilities.isRightMouseButton(event);
0871:                }
0872:
0873:                /**
0874:                 * Returning true signifies a mouse event removes a given point.
0875:                 */
0876:                public boolean isRemovePointEvent(MouseEvent event) {
0877:                    return event.isPopupTrigger()
0878:                            || SwingUtilities.isRightMouseButton(event);
0879:                }
0880:
0881:                protected boolean isSourceEditing() {
0882:                    return source;
0883:                }
0884:
0885:                protected boolean isTargetEditing() {
0886:                    return target;
0887:                }
0888:
0889:                /*
0890:                 * Returns true if either the source, target, label or a point is being
0891:                 * edited.
0892:                 */
0893:                protected boolean isEditing() {
0894:                    return source || target || label || currentLabel >= 0
0895:                            || currentPoint != null;
0896:                }
0897:
0898:                /**
0899:                 * Invoked when the mouse pointer has been moved on a component (with no
0900:                 * buttons down).
0901:                 */
0902:                public void mouseMoved(MouseEvent event) {
0903:                    for (int i = 0; i < r.length; i++)
0904:                        if (r[i].contains(event.getPoint())) {
0905:                            graph
0906:                                    .setCursor(new Cursor(
0907:                                            Cursor.CROSSHAIR_CURSOR));
0908:                            event.consume();
0909:                            return;
0910:                        }
0911:                    if (loc.contains(event.getPoint())
0912:                            && graph.isMoveable()
0913:                            && GraphConstants.isMoveable(edge
0914:                                    .getAllAttributes())) {
0915:                        graph.setCursor(new Cursor(Cursor.HAND_CURSOR));
0916:                        event.consume();
0917:                    }
0918:                    if (extraLabelLocations != null
0919:                            && graph.isMoveable()
0920:                            && GraphConstants.isMoveable(edge
0921:                                    .getAllAttributes())) {
0922:                        for (int i = 0; i < extraLabelLocations.length; i++) {
0923:                            if (extraLabelLocations[i].contains(event
0924:                                    .getPoint())) {
0925:                                graph.setCursor(new Cursor(Cursor.HAND_CURSOR));
0926:                                event.consume();
0927:                            }
0928:                        }
0929:                    }
0930:                }
0931:
0932:                // Handle mouse pressed event.
0933:                public void mousePressed(MouseEvent event) {
0934:                    /* INV: currentPoint = null; source = target = label = false; */
0935:                    if (!edge.isLeaf())
0936:                        return;
0937:                    boolean bendable = graph.isBendable()
0938:                            && GraphConstants.isBendable(edge
0939:                                    .getAllAttributes());
0940:                    int x = event.getX();
0941:                    int y = event.getY();
0942:                    // Detect hit on control point
0943:                    int index = 0;
0944:                    for (index = 0; index < r.length; index++) {
0945:                        if (r[index].contains(x, y)) {
0946:                            currentPoint = edge.getPoint(index);
0947:                            currentIndex = index;
0948:                            source = index == 0;
0949:                            target = index == r.length - 1;
0950:                            break;
0951:                        }
0952:                    }
0953:                    // Detect hit on label
0954:                    if (!isEditing()
0955:                            && graph.isMoveable()
0956:                            && GraphConstants.isMoveable(edge
0957:                                    .getAllAttributes()) && loc != null
0958:                            && loc.contains(x, y) && !isAddPointEvent(event)
0959:                            && !isRemovePointEvent(event)
0960:                            && graph.getEdgeLabelsMovable()) {
0961:                        initialLabelLocation = (Point2D) edge
0962:                                .getLabelPosition().clone();
0963:                        label = true;
0964:                    }
0965:                    // Detect hit on extra labels
0966:                    else if (extraLabelLocations != null
0967:                            && !isEditing()
0968:                            && graph.isMoveable()
0969:                            && graph.getEdgeLabelsMovable()
0970:                            && GraphConstants.isMoveable(edge
0971:                                    .getAllAttributes())) {
0972:                        for (int i = 0; i < extraLabelLocations.length; i++) {
0973:                            if (extraLabelLocations[i] != null
0974:                                    && extraLabelLocations[i].contains(x, y)) {
0975:                                currentLabel = i;
0976:                                initialLabelLocation = (Point2D) edge
0977:                                        .getExtraLabelPosition(currentLabel)
0978:                                        .clone();
0979:                                if (isRemovePointEvent(event)) {
0980:                                    edge.removeExtraLabel(i);
0981:                                    edgeModified = true;
0982:                                    mouseReleased(event);
0983:                                }
0984:                                break;
0985:                            }
0986:                        }
0987:                    }
0988:                    // Remove Point
0989:                    if (isRemovePointEvent(event)
0990:                            && currentPoint != null
0991:                            && !source
0992:                            && !target
0993:                            && bendable
0994:                            && (edge.getSource() == null || currentIndex > 0)
0995:                            && (edge.getTarget() == null || currentIndex < edge
0996:                                    .getPointCount() - 1)) {
0997:                        edge.removePoint(index);
0998:                        edgeModified = true;
0999:                        mouseReleased(event);
1000:                        // Add Point
1001:                    } else if (isAddPointEvent(event) && !isEditing()
1002:                            && bendable) {
1003:                        int s = graph.getHandleSize();
1004:                        Rectangle2D rect = graph.fromScreen(new Rectangle(
1005:                                x - s, y - s, 2 * s, 2 * s));
1006:                        if (edge.intersects(graph, rect)) {
1007:                            Point2D point = graph.fromScreen(graph
1008:                                    .snap(new Point(event.getPoint())));
1009:                            double min = Double.MAX_VALUE, dist = 0;
1010:                            for (int i = 0; i < edge.getPointCount() - 1; i++) {
1011:                                Point2D p = edge.getPoint(i);
1012:                                Point2D p1 = edge.getPoint(i + 1);
1013:                                dist = new Line2D.Double(p, p1)
1014:                                        .ptSegDistSq(point);
1015:                                if (dist < min) {
1016:                                    min = dist;
1017:                                    index = i + 1;
1018:                                }
1019:                            }
1020:                            edge.addPoint(index, point);
1021:                            edgeModified = true;
1022:                            currentPoint = point;
1023:                            reloadPoints(edge);
1024:                            paint(graph.getGraphics());
1025:                        }
1026:                    }
1027:                    if (isEditing())
1028:                        event.consume();
1029:                }
1030:
1031:                public void mouseDragged(MouseEvent event) {
1032:                    Point2D p = graph.fromScreen(new Point(event.getPoint()));
1033:                    // Move Label
1034:                    if (label || currentLabel >= 0) {
1035:                        Rectangle2D r = edge.getBounds();
1036:                        if (r != null) {
1037:                            edgeModified = true;
1038:                            if (graph.isXorEnabled()) {
1039:                                overlay(graph.getGraphics());
1040:                            }
1041:                            if (!GraphConstants.isLabelAlongEdge(edge
1042:                                    .getAllAttributes())) {
1043:                                p = getRelativeLabelPosition(edge, p);
1044:                            } else {
1045:                                double x = p.getX();
1046:                                double y = p.getY();
1047:
1048:                                Point2D p0 = edge.getPoint(0);
1049:
1050:                                double p0x = p0.getX();
1051:                                double p0y = p0.getY();
1052:
1053:                                Point2D vector = edge.getLabelVector();
1054:                                double dx = vector.getX();
1055:                                double dy = vector.getY();
1056:
1057:                                double pex = p0.getX() + dx;
1058:                                double pey = p0.getY() + dy;
1059:
1060:                                double len = Math.sqrt(dx * dx + dy * dy);
1061:                                if (len > 0) {
1062:                                    double u = GraphConstants.PERMILLE;
1063:                                    double posy = len
1064:                                            * (-y * dx + p0y * dx + x * dy - p0x
1065:                                                    * dy)
1066:                                            / (-pey * dy + p0y * dy - dx * pex + dx
1067:                                                    * p0x);
1068:                                    double posx = u
1069:                                            * (-y * pey + y * p0y + p0y * pey
1070:                                                    - p0y * p0y - pex * x + pex
1071:                                                    * p0x + p0x * x - p0x * p0x)
1072:                                            / (-pey * dy + p0y * dy - dx * pex + dx
1073:                                                    * p0x);
1074:                                    p = new Point2D.Double(posx, posy);
1075:                                } else {
1076:                                    p = new Point2D.Double(x - p0.getX(), y
1077:                                            - p0.getY());
1078:                                }
1079:                            }
1080:                            Rectangle2D dirty = edge.getBounds();
1081:                            if (label)
1082:                                edge.setLabelPosition(p);
1083:                            else
1084:                                edge.setExtraLabelPosition(currentLabel, p);
1085:                            edge.update(graph.getGraphLayoutCache());
1086:                            if (graph.isXorEnabled()) {
1087:                                overlay(graph.getGraphics());
1088:                            } else {
1089:                                graph.repaint((int) dirty.getX(), (int) dirty
1090:                                        .getY(), (int) dirty.getWidth(),
1091:                                        (int) dirty.getHeight());
1092:                            }
1093:                        }
1094:                    } else if (isEditing() && currentPoint != null) {
1095:                        boolean disconnectable = (!source && !target)
1096:                                || (graph.isDisconnectable() && GraphConstants
1097:                                        .isDisconnectable(orig
1098:                                                .getAllAttributes()));
1099:                        if (source)
1100:                            disconnectable = disconnectable
1101:                                    && ((orig.getSource() == null && orig
1102:                                            .getSourceParentView() == null)
1103:                                            || (orig.getSource() != null && GraphConstants
1104:                                                    .isDisconnectable(orig
1105:                                                            .getSource()
1106:                                                            .getParentView()
1107:                                                            .getAllAttributes())) || (orig
1108:                                            .getSourceParentView() != null && GraphConstants
1109:                                            .isDisconnectable(orig
1110:                                                    .getSourceParentView()
1111:                                                    .getAllAttributes())));
1112:                        if (target)
1113:                            disconnectable = disconnectable
1114:                                    && ((orig.getTarget() == null && orig
1115:                                            .getTargetParentView() == null)
1116:                                            || (orig.getTarget() != null && GraphConstants
1117:                                                    .isDisconnectable(orig
1118:                                                            .getTarget()
1119:                                                            .getParentView()
1120:                                                            .getAllAttributes())) || (orig
1121:                                            .getTargetParentView() != null && GraphConstants
1122:                                            .isDisconnectable(orig
1123:                                                    .getTargetParentView()
1124:                                                    .getAllAttributes())));
1125:                        // Find Source/Target Port
1126:                        if (!((source && snap(true, event.getPoint())) || (target && snap(
1127:                                false, event.getPoint())))
1128:                                && disconnectable) {
1129:                            // Else Use Point
1130:                            boolean acceptSource = source
1131:                                    && (graph.getModel().acceptsSource(
1132:                                            edge.getCell(), null) || graph
1133:                                            .isPreviewInvalidNullPorts());
1134:                            boolean acceptTarget = target
1135:                                    && (graph.getModel().acceptsTarget(
1136:                                            edge.getCell(), null) || graph
1137:                                            .isPreviewInvalidNullPorts());
1138:                            if (acceptSource || acceptTarget
1139:                                    || !(source || target)) {
1140:                                edgeModified = true;
1141:                                Rectangle2D dirty = edge.getBounds();
1142:                                if (edge.getSource() != null) {
1143:                                    dirty.add(edge.getSource().getParentView()
1144:                                            .getBounds());
1145:                                }
1146:                                if (edge.getTarget() != null) {
1147:                                    dirty.add(edge.getTarget().getParentView()
1148:                                            .getBounds());
1149:                                }
1150:                                if (graph.isXorEnabled()) {
1151:                                    overlay(graph.getGraphics());
1152:                                }
1153:                                p = graph.fromScreen(graph.snap(new Point(event
1154:                                        .getPoint())));
1155:                                // Constrained movement
1156:                                if (isConstrainedMoveEvent(event)
1157:                                        && currentIndex >= 0) {
1158:                                    // Reset Initial Positions
1159:                                    EdgeView orig = (EdgeView) graph
1160:                                            .getGraphLayoutCache().getMapping(
1161:                                                    edge.getCell(), false);
1162:                                    Point2D origPoint = orig
1163:                                            .getPoint(currentIndex);
1164:                                    double totDx = p.getX() - origPoint.getX();
1165:                                    double totDy = p.getY() - origPoint.getY();
1166:                                    if (Math.abs(totDx) < Math.abs(totDy))
1167:                                        p.setLocation(origPoint.getX(), p
1168:                                                .getY());
1169:                                    else
1170:                                        p.setLocation(p.getX(), origPoint
1171:                                                .getY());
1172:                                }
1173:                                // Do not move into negative space
1174:                                p.setLocation(Math.max(0, p.getX()), Math.max(
1175:                                        0, p.getY()));
1176:                                currentPoint.setLocation(p);
1177:                                if (source) {
1178:                                    edge.setPoint(0, p);
1179:                                    edge.setSource(null);
1180:                                } else if (target) {
1181:                                    edge.setPoint(edge.getPointCount() - 1, p);
1182:                                    edge.setTarget(null);
1183:                                }
1184:                                edge.update(graph.getGraphLayoutCache());
1185:                                dirty.add(edge.getBounds());
1186:                                if (graph.isXorEnabled()) {
1187:                                    overlay(graph.getGraphics());
1188:                                } else {
1189:                                    if (edge.getSource() != null) {
1190:                                        dirty.add(edge.getSource()
1191:                                                .getParentView().getBounds());
1192:                                    }
1193:                                    if (edge.getTarget() != null) {
1194:                                        dirty.add(edge.getTarget()
1195:                                                .getParentView().getBounds());
1196:                                    }
1197:                                    graph.repaint((int) dirty.getX(),
1198:                                            (int) dirty.getY(), (int) dirty
1199:                                                    .getWidth(), (int) dirty
1200:                                                    .getHeight());
1201:                                }
1202:                            }
1203:                        }
1204:                    }
1205:                }
1206:
1207:                protected Point2D getRelativeLabelPosition(EdgeView edge,
1208:                        Point2D p) {
1209:                    int pointCount = edge.getPointCount();
1210:
1211:                    double totalLength = 0;
1212:                    double[] segments = new double[pointCount];
1213:
1214:                    Point2D p0 = edge.getPoint(0);
1215:                    Point2D pt = p0;
1216:
1217:                    for (int i = 1; i < pointCount; i++) {
1218:                        Point2D tmp = edge.getPoint(i);
1219:
1220:                        if (tmp != null) {
1221:                            double dx = pt.getX() - tmp.getX();
1222:                            double dy = pt.getY() - tmp.getY();
1223:
1224:                            double segment = Math.sqrt(dx * dx + dy * dy);
1225:
1226:                            segments[i - 1] = segment;
1227:                            totalLength += segment;
1228:                            pt = tmp;
1229:                        }
1230:                    }
1231:
1232:                    Point2D last = edge.getPoint(1);
1233:                    Line2D line = new Line2D.Double(p0, last);
1234:                    double minDist = line.ptSegDistSq(p);
1235:
1236:                    int index = 0;
1237:                    double tmp = 0;
1238:                    double length = 0;
1239:
1240:                    for (int i = 2; i < pointCount; i++) {
1241:                        tmp += segments[i - 2];
1242:
1243:                        line = new Line2D.Double(edge.getPoint(i), last);
1244:                        double dist = line.ptLineDistSq(p);
1245:
1246:                        if (dist < minDist) {
1247:                            minDist = dist;
1248:                            index = i - 1;
1249:                            length = tmp;
1250:                        }
1251:
1252:                        last = edge.getPoint(i);
1253:                    }
1254:
1255:                    double seg = segments[index];
1256:
1257:                    pt = edge.getPoint(index);
1258:
1259:                    double x2 = pt.getX();
1260:                    double y2 = pt.getY();
1261:
1262:                    pt = edge.getPoint(index + 1);
1263:
1264:                    double x1 = pt.getX();
1265:                    double y1 = pt.getY();
1266:
1267:                    double px = p.getX();
1268:                    double py = p.getY();
1269:
1270:                    x2 -= x1;
1271:                    y2 -= y1;
1272:
1273:                    px -= x1;
1274:                    py -= y1;
1275:
1276:                    double dotprod = px * x2 + py * y2;
1277:                    double projlenSq = 0;
1278:
1279:                    px = x2 - px;
1280:                    py = y2 - py;
1281:                    dotprod = px * x2 + py * y2;
1282:
1283:                    if (dotprod <= 0.0) {
1284:                        projlenSq = 0;
1285:                    } else {
1286:                        projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
1287:                    }
1288:
1289:                    tmp = Math.sqrt(projlenSq);
1290:                    if (tmp > seg) {
1291:                        tmp = seg;
1292:                    }
1293:
1294:                    p0 = edge.getPoint(index);
1295:                    Point2D pe = edge.getPoint(index + 1);
1296:
1297:                    double offsetX = 0;
1298:                    double offsetY = 0;
1299:
1300:                    if (p0 != null && pe != null) {
1301:                        double factor = tmp / seg;
1302:
1303:                        double dx = pe.getX() - p0.getX();
1304:                        double dy = pe.getY() - p0.getY();
1305:
1306:                        double tx = p0.getX() + dx * factor;
1307:                        double ty = p0.getY() + dy * factor;
1308:
1309:                        offsetX = p.getX() - tx;
1310:                        offsetY = p.getY() - ty;
1311:                    }
1312:
1313:                    // Uses the offset constant to align the label to the point
1314:                    // from the relative location on the edge shape
1315:                    Point2D off = new Point2D.Double(offsetX, offsetY);
1316:                    GraphConstants.setOffset(edge.getAllAttributes(), off);
1317:
1318:                    // Contructs the relative point for the label
1319:                    Point2D result = new Point2D.Double(((((totalLength / 2
1320:                            - length - tmp) / totalLength) * -2) + 1)
1321:                            * GraphConstants.PERMILLE / 2, 0);
1322:
1323:                    return result;
1324:                }
1325:
1326:                // Handle mouse released event
1327:                public void mouseReleased(MouseEvent e) {
1328:                    boolean clone = e.isControlDown() && graph.isCloneable();
1329:                    GraphModel model = graph.getModel();
1330:                    Object source = (edge.getSource() != null) ? edge
1331:                            .getSource().getCell() : null;
1332:                    Object target = (edge.getTarget() != null) ? edge
1333:                            .getTarget().getCell() : null;
1334:                    if (edgeModified
1335:                            && model.acceptsSource(edge.getCell(), source)
1336:                            && model.acceptsTarget(edge.getCell(), target)) {
1337:
1338:                        // Creates an extra label if the label was cloned
1339:                        if (clone && initialLabelLocation != null) {
1340:
1341:                            // Resets the dragging label position and adds a new label
1342:                            // instead. Note: label locations are modified in-place
1343:                            // which is why we need to clone at beginning.
1344:                            Object value = null;
1345:                            Point2D location = null;
1346:                            Object[] extraLabels = GraphConstants
1347:                                    .getExtraLabels(edge.getAllAttributes());
1348:                            if (label) {
1349:                                location = (Point2D) edge.getLabelPosition()
1350:                                        .clone();
1351:                                value = graph.convertValueToString(orig);
1352:                                edge.setLabelPosition(initialLabelLocation);
1353:                            } else {
1354:                                location = (Point2D) edge
1355:                                        .getExtraLabelPosition(currentLabel)
1356:                                        .clone();
1357:                                value = extraLabels[currentLabel];
1358:                                edge.setExtraLabelPosition(currentLabel,
1359:                                        initialLabelLocation);
1360:                            }
1361:                            edge.addExtraLabel(location, value);
1362:                            edge.update(graph.getGraphLayoutCache());
1363:                            clone = false;
1364:                        }
1365:
1366:                        // Creates the data required for the edit/insert call
1367:                        ConnectionSet cs = createConnectionSet(edge, clone);
1368:                        Map nested = GraphConstants.createAttributes(
1369:                                new CellView[] { edge }, null);
1370:
1371:                        // The cached points may be different from what's
1372:                        // in the attribute map if the edge is routed.
1373:                        Map tmp = (Map) nested.get(edge.getCell());
1374:                        List controlPoints = GraphConstants.getPoints(tmp);
1375:                        List currentPoints = edge.getPoints();
1376:
1377:                        // Checks if we're dealing with a routing algorithm
1378:                        // and if we are, replaces only the source and target
1379:                        // in the control point list.
1380:                        if (controlPoints != currentPoints) {
1381:                            controlPoints.set(0, edge.getPoint(0));
1382:                            controlPoints.set(controlPoints.size() - 1, edge
1383:                                    .getPoint(edge.getPointCount() - 1));
1384:                        }
1385:
1386:                        if (clone) {
1387:                            Map cellMap = graph.cloneCells(graph
1388:                                    .getDescendants(new Object[] { edge
1389:                                            .getCell() }));
1390:                            processNestedMap(nested, true);
1391:                            nested = GraphConstants
1392:                                    .replaceKeys(cellMap, nested);
1393:                            cs = cs.clone(cellMap);
1394:                            Object[] cells = cellMap.values().toArray();
1395:                            graph.getGraphLayoutCache().insert(cells, nested,
1396:                                    cs, null, null);
1397:                        } else {
1398:                            processNestedMap(nested, false);
1399:                            graph.getGraphLayoutCache().edit(nested, cs, null,
1400:                                    null);
1401:                        }
1402:                    } else {
1403:                        if (graph.isXorEnabled()) {
1404:                            overlay(graph.getGraphics());
1405:                        } else {
1406:                            Rectangle2D dirty = edge.getBounds();
1407:                            graph.repaint((int) dirty.getX(), (int) dirty
1408:                                    .getY(), (int) dirty.getWidth(),
1409:                                    (int) dirty.getHeight());
1410:                        }
1411:                        edge.refresh(graph.getGraphLayoutCache(), graph
1412:                                .getGraphLayoutCache(), false);
1413:                    }
1414:                    initialLabelLocation = null;
1415:                    currentPoint = null;
1416:                    this .edgeModified = false;
1417:                    this .label = false;
1418:                    this .source = false;
1419:                    this .target = false;
1420:                    currentLabel = -1;
1421:                    currentIndex = -1;
1422:                    firstOverlayCall = true;
1423:                    e.consume();
1424:                }
1425:
1426:                protected void processNestedMap(Map nested, boolean clone) {
1427:                    // subclassers can override this to modify the attributes
1428:                }
1429:
1430:                protected ConnectionSet createConnectionSet(EdgeView view,
1431:                        boolean verbose) {
1432:                    Object edge = view.getCell();
1433:                    GraphModel model = graph.getModel();
1434:                    ConnectionSet cs = new ConnectionSet();
1435:                    Object sourcePort = null, targetPort = null;
1436:                    if (view.getSource() != null)
1437:                        sourcePort = view.getSource().getCell();
1438:                    else if (view.getSourceParentView() != null)
1439:                        sourcePort = model.getSource(edge);
1440:                    if (view.getTarget() != null)
1441:                        targetPort = view.getTarget().getCell();
1442:                    else if (view.getTargetParentView() != null)
1443:                        targetPort = model.getTarget(edge);
1444:                    if (view.getTarget() != null)
1445:                        targetPort = view.getTarget().getCell();
1446:                    if (verbose
1447:                            || (sourcePort != model.getSource(edge) && source))
1448:                        cs.connect(edge, sourcePort, true);
1449:                    if (verbose
1450:                            || (targetPort != model.getTarget(edge) && target))
1451:                        cs.connect(edge, targetPort, false);
1452:                    return cs;
1453:                }
1454:
1455:                // Update control points
1456:                protected void invalidate() {
1457:                    EdgeView e = relevantEdge;
1458:                    int handlesize = graph.getHandleSize();
1459:                    EdgeRenderer er = (EdgeRenderer) edge.getRenderer();
1460:                    for (int i = 0; i < r.length; i++) {
1461:                        Point2D p = e.getPoint(i);
1462:                        p = graph.toScreen(new Point2D.Double(p.getX(), p
1463:                                .getY()));
1464:                        r[i].setFrame(p.getX() - handlesize, p.getY()
1465:                                - handlesize, 2 * handlesize, 2 * handlesize);
1466:                        p = graph.toScreen(er.getLabelPosition(e));
1467:                        Dimension d = er.getLabelSize(e, graph
1468:                                .convertValueToString(e));
1469:                        if (p != null && d != null) {
1470:                            Point2D s = graph.toScreen(new Point2D.Double(
1471:                                    d.width, d.height));
1472:                            loc.setFrame(p.getX() - s.getX() / 2, p.getY()
1473:                                    - s.getY() / 2, s.getX(), s.getY());
1474:                        }
1475:                    }
1476:                    if (extraLabelLocations != null) {
1477:                        for (int i = 0; i < extraLabelLocations.length; i++) {
1478:                            Point2D p = er.getExtraLabelPosition(e, i);
1479:                            if (p != null) {
1480:                                p = graph.toScreen((Point2D) p.clone());
1481:                                Dimension d = er.getExtraLabelSize(graph, e, i);
1482:                                if (d != null) {
1483:                                    Point2D s = graph
1484:                                            .toScreen(new Point2D.Double(
1485:                                                    d.width, d.height));
1486:                                    extraLabelLocations[i].setFrame(p.getX()
1487:                                            - s.getX() / 2, p.getY() - s.getY()
1488:                                            / 2, s.getX(), s.getY());
1489:                                }
1490:                            }
1491:                        }
1492:                    }
1493:                }
1494:
1495:            }
1496:
1497:            public Point2D getPerimeterPoint(EdgeView edge, Point2D source,
1498:                    Point2D p) {
1499:                if (getPointCount() > 2)
1500:                    return getPoint(getPointCount() / 2);
1501:                Point2D p0 = getPoint(0);
1502:                Point2D pe = getPoint(getPointCount() - 1);
1503:                return new Point2D.Double((pe.getX() + p0.getX()) / 2, (pe
1504:                        .getY() + p0.getY()) / 2);
1505:            }
1506:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.