Package org.jgraph.graph

Source Code of org.jgraph.graph.EdgeView$EdgeHandle

/*
* @(#)EdgeView.java  1.0 03-JUL-04
*
* Copyright (c) 2001-2004 Gaudenz Alder
*/
package org.jgraph.graph;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;

import javax.swing.SwingUtilities;

import org.jgraph.JGraph;
import org.jgraph.plaf.GraphUI;
import org.jgraph.plaf.basic.BasicGraphUI;

/**
* The default implementation of an edge view. The getEdgeRenderer method
* assumes a renderer of type EdgeRenderer. If you provide a custom renderer to
* a subclass, you must also override the methods that call this method, namely:
* getShape, getLabelBounds, getExtraLabelBounds, intersects and getBounds.
*
* @version 1.0 1/1/02
* @author Gaudenz Alder
*/

public class EdgeView extends AbstractCellView {

  /** Renderer for the class. */
  public static transient EdgeRenderer renderer = new EdgeRenderer();

  /** List of points of the edge. May contain ports. */
  protected transient java.util.List points;

  /** Cached source and target portview of the edge. */
  protected transient CellView source, target;

  /** Cached label position of the edge. */
  protected transient Point labelPosition;

  protected transient Point[] extraLabelPositions;

  /** Drawing attributes that are created on the fly */
  public Shape beginShape, endShape, lineShape;

  /** Shared-path tune-up. */
  public transient GeneralPath sharedPath = null;

  protected transient Rectangle2D cachedLabelBounds = null;

  protected transient Rectangle2D[] cachedExtraLabelBounds = null;

  protected transient Rectangle2D cachedBounds = null;

  protected transient Point2D labelVector = null;

  /**
   * Constructs an empty edge view.
   */
  public EdgeView() {
    super();
  }

  /**
   * Constructs an edge view for the specified model object.
   *
   * @param cell
   *            reference to the model object
   */
  public EdgeView(Object cell) {
    super(cell);
  }

  //
  // Data Source
  //

  /**
   * Overrides the parent method to udpate the cached points, source and
   * target port. If the source or target is removed, a point is inserted into
   * the array of points.
   */
  public void refresh(GraphModel model, CellMapper mapper,
      boolean createDependentViews) {
    super.refresh(model, mapper, createDependentViews);
    // Re-sync source- and targetportviews
    Object modelSource = model.getSource(cell);
    Object modelTarget = model.getTarget(cell);
    setSource(mapper.getMapping(modelSource, createDependentViews));
    setTarget(mapper.getMapping(modelTarget, createDependentViews));
  }

  /**
   * Update attributes and recurse children.
   */
  public void update() {
    super.update();
    // Save the reference to the points so they can be changed
    // in-place by use of setPoint, setSource, setTarget methods.
    points = GraphConstants.getPoints(allAttributes);
    if (points == null) {
      points = new ArrayList(4);
      points.add(getAllAttributes().createPoint(10, 10));
      points.add(getAllAttributes().createPoint(20, 20));
      GraphConstants.setPoints(allAttributes, points);
    }
    checkDefaultLabelPosition();
    Point[] positions = GraphConstants
        .getExtraLabelPositions(allAttributes);
    if (positions != null) {
      extraLabelPositions = new Point[positions.length];
      for (int i = 0; i < positions.length; i++)
        extraLabelPositions[i] = positions[i];
    } else
      extraLabelPositions = null;
    Edge.Routing routing = GraphConstants.getRouting(allAttributes);
    if (routing != null)
      routing.route(this, points);
    // Clear cached shapes
    beginShape = null;
    endShape = null;
    lineShape = null;
    invalidate();
  }

  /**
   * Hook for subclassers to avoid default label positions.
   */
  protected void checkDefaultLabelPosition() {
    labelPosition = GraphConstants.getLabelPosition(allAttributes);
    String label = String.valueOf(getCell());
    if (labelPosition == null && label != null && label.length() > 0) {
      int center = GraphConstants.PERMILLE / 2;
      labelPosition = new Point(center, 0);
      GraphConstants.setLabelPosition(allAttributes, labelPosition);
    }
  }

  void invalidate() {
    labelVector = null;
    sharedPath = null;
    cachedBounds = null;
    cachedLabelBounds = null;
    cachedExtraLabelBounds = null;
  }

  /**
   * Returns the shape of the view according to the last rendering state
   */
  public Shape getShape() {
    if (sharedPath != null)
      return sharedPath;
    else
      return sharedPath = (GeneralPath) getEdgeRenderer().createShape();
  }

  /**
   * Returns the bounds of label according to the last rendering state
   */
  public Rectangle2D getLabelBounds() {
    if (cachedLabelBounds != null) {
      return cachedLabelBounds;
    } else {
      return cachedLabelBounds = getEdgeRenderer().getLabelBounds(null,
          this);
    }
  }

  /**
   * Returns the bounds of label according to the last rendering state
   */
  public Rectangle2D getExtraLabelBounds(int index) {
    if (cachedLabelBounds != null && index < cachedExtraLabelBounds.length
        && cachedExtraLabelBounds[index] != null) {
      return cachedExtraLabelBounds[index];
    } else {
      return cachedExtraLabelBounds[index] = getEdgeRenderer()
          .getExtraLabelBounds(null, this, index);
    }
  }

  //
  // View Methods
  //

  /**
   * Returns true if this view intersects the given rectangle.
   */
  public boolean intersects(JGraph graph, Rectangle2D rect) {
    boolean intersects = super.intersects(graph, rect);
    if (!isLeaf()) {
      return intersects;
    } else if (intersects) {
      Rectangle r = new Rectangle((int) rect.getX(), (int) rect.getY(),
          (int) rect.getWidth(), (int) rect.getHeight());
      return getEdgeRenderer().intersects(graph, this, r);
    }
    return false;
  }

  /**
   * Returns the location for this portview.
   */
  public Rectangle2D getBounds() {
    Rectangle2D rect = super.getBounds();
    if (rect == null) {
      if (cachedBounds == null) {
        cachedBounds = getEdgeRenderer().getBounds(this);
      }
      rect = cachedBounds;
    }
    return rect;
  }

  /**
   * Returns the local renderer. Do not access the renderer field directly.
   * Use this method instead. Note: This method is package private.
   */
  EdgeRenderer getEdgeRenderer() {
    return (EdgeRenderer) getRenderer();
  }

  /**
   * Returns a renderer for the class.
   */
  public CellViewRenderer getRenderer() {
    return renderer;
  }

  /**
   * Returns a cell handle for the view.
   */
  public CellHandle getHandle(GraphContext context) {
    return new EdgeHandle(this, context);
  }

  //
  // Cached Values
  //

  /**
   * Returns the CellView that represents the source of the edge.
   */
  public CellView getSource() {
    return source;
  }

  /**
   * Sets the <code>sourceView</code> of the edge.
   */
  public void setSource(CellView sourceView) {
    source = sourceView;
    if (source != null)
      points.set(0, source);
    else
      points.set(0, getPoint(0));
    invalidate();
  }

  /**
   * Returns the CellView that represents the target of the edge.
   */
  public CellView getTarget() {
    return target;
  }

  /**
   * Sets the <code>targetView</code> of the edge.
   */
  public void setTarget(CellView targetView) {
    target = targetView;
    int n = points.size() - 1;
    if (target != null)
      points.set(n, target);
    else
      points.set(n, getPoint(n));
    invalidate();
  }

  /**
   * Returns a point that describes the position of the label.
   */
  public Point2D getExtraLabelPosition(int index) {
    return extraLabelPositions[index];
  }

  /**
   * Returns a point that describes the position of the label.
   */
  public Point2D getLabelPosition() {
    return labelPosition;
  }

  /**
   * Sets the description of the label position.
   */
  public void setLabelPosition(Point2D pos) {
    labelPosition.setLocation(pos);
    invalidate();
  }

  /**
   * Sets the description of the label position.
   */
  public void setExtraLabelPosition(int index, Point2D pos) {
    extraLabelPositions[index].setLocation(pos);
    invalidate();
  }

  //
  // Points
  //

  /**
   * Returns the points.
   *
   * @return java.util.List
   */
  public java.util.List getPoints() {
    return points;
  }

  /**
   * Returns the number of point for this edge.
   */
  public int getPointCount() {
    return points.size();
  }

  /**
   * Returns the cached points for this edge.
   */
  public Point2D getPoint(int index) {
    Object obj = points.get(index);
    if (obj instanceof PortView)
      // Port Location Seen From This Edge
      return ((PortView) obj).getLocation(this,
          getPointLocation((index == 0) ? 1 : points.size() - 2));
    else if (obj instanceof CellView) {
      // Should not happen
      Rectangle2D r = ((CellView) obj).getBounds();
      return new Point2D.Double(r.getX(), r.getY());
    } else if (obj instanceof Point2D)
      // Regular Point
      return (Point2D) obj;
    return null;
  }

  /**
   * Returns the point of <code>edge</code> at <code>index</code>. Avoids
   * calling <code>getLocation</code> on any ports of <code>edge</code>.
   * <br>
   * This is used from within getPoint to pass the nearest point to the
   * portview to find it's location. This uses the center point of the parent
   * view to determine the port view's location to avoid infinite recursion.
   */
  protected Point2D getPointLocation(int index) {
    Object obj = points.get(index);
    if (obj instanceof Point2D)
      return (Point2D) obj;
    else if (obj instanceof PortView) {
      VertexView vertex = (VertexView) ((CellView) obj).getParentView();
      if (vertex != null)
        return vertex.getCenterPoint();
    }
    return null;
  }

  /**
   * Sets the point at <code>index</code> to <code>p</code>.
   */
  public void setPoint(int index, Point2D p) {
    points.set(index, p);
    invalidate();
  }

  /**
   * Adds <code>p</code> at position <code>index</code>.
   */
  public void addPoint(int index, Point2D p) {
    points.add(index, p);
    invalidate();
  }

  /**
   * Removes the point at position <code>index</code>.
   */
  public void removePoint(int index) {
    points.remove(index);
    invalidate();
  }

  /**
   * Hook to return the vector that is taken as the base vector to compute
   * relative label positions. Normally, the vector goes from the first to the
   * last point on the edge, unless these points are equal, in which case the
   * average distance of all points to the source point is used.
   */
  public Point2D getLabelVector() {
    if (labelVector == null) {
      Point2D p0 = getPoint(0);
      Point2D pe = getPoint(getPointCount() - 1);
      double dx = 0;
      double dy = 0;
      // Finds an average distance
      dx = 0;
      dy = 0;
      int n = getPointCount();
      for (int i = 1; i < n; i++) {
        Point2D point = getPoint(i);
        dx += point.getX() - p0.getX();
        dy += point.getY() - p0.getY();
      }
      n--;
      dx /= (double) n;
      dy /= (double) n;
      labelVector = new Point2D.Double(dx, dy);
    }
    return labelVector;
  }

  //
  // Routing
  //

  public static double getLength(CellView view) {
    double cost = 1;
    if (view instanceof EdgeView) {
      EdgeView edge = (EdgeView) view;
      Point2D last = null, current = null;
      for (int i = 0; i < edge.getPointCount(); i++) {
        current = edge.getPoint(i);
        if (last != null)
          cost += last.distance(current);
        last = current;
      }
    }
    return cost;
  }

  //
  // Handle
  //

  // This implementation uses the point instance to make the change. No index
  // is used for the current point because routing could change the index
  // during
  // the move operation.
  public static class EdgeHandle implements CellHandle, Serializable {

    protected JGraph graph;

    /* Pointer to the edge and its clone. */
    protected EdgeView edge, orig;

    /*
     * Boolean indicating whether the source, target or label is being
     * edited.
     */
    protected boolean label = false, source = false, target = false;

    /**
     * Holds the index of the current (editing) label or point.
     */
    protected int currentLabel = -1, currentIndex = -1;

    /* Pointer to the currently selected point. */
    protected Point2D currentPoint;

    /* Array of control points represented as rectangles. */
    protected transient Rectangle2D[] r;

    /* A control point for the label position. */
    protected transient Rectangle2D loc;

    protected transient Rectangle2D[] extraLabelLocations;

    protected boolean firstOverlayCall = true;

    protected boolean isEdgeConnectable = true;

    protected EdgeView relevantEdge = null;

    /**
     * Indicates whether the edge has been modified during the last mouse
     * pressed and dragged operations.
     */
    protected boolean edgeModified = false;

    public EdgeHandle(EdgeView edge, GraphContext ctx) {
      this.graph = ctx.getGraph();
      this.edge = edge;
      loc = new Rectangle();
      Object[] labels = GraphConstants.getExtraLabels(edge
          .getAllAttributes());
      if (labels != null) {
        extraLabelLocations = new Rectangle[labels.length];
        for (int i = 0; i < extraLabelLocations.length; i++)
          extraLabelLocations[i] = new Rectangle();
      }
      orig = (EdgeView) graph.getGraphLayoutCache().getMapping(
          edge.getCell(), false);
      reloadPoints(orig);
      isEdgeConnectable = GraphConstants.isConnectable(edge
          .getAllAttributes());
    }

    protected void reloadPoints(EdgeView edge) {
      relevantEdge = edge;
      r = new Rectangle[edge.getPointCount()];
      for (int i = 0; i < r.length; i++)
        r[i] = new Rectangle();
      invalidate();
    }

    // Update and paint control points
    public void paint(Graphics g) {
      invalidate();
      if (!edge.isLeaf())
        return;
      for (int i = 0; i < r.length; i++) {
        if (isEdgeConnectable)
          g.setColor(graph.getHandleColor());
        else
          g.setColor(graph.getLockedHandleColor());
        g.fill3DRect((int) r[i].getX(), (int) r[i].getY(), (int) r[i]
            .getWidth(), (int) r[i].getHeight(), true);
        CellView port = null;
        if (i == 0 && edge.getSource() != null)
          port = edge.getSource();
        else if (i == r.length - 1 && edge.getTarget() != null)
          port = edge.getTarget();
        if (port != null) {
          g.setColor(graph.getLockedHandleColor());
          Point2D tmp = GraphConstants.getOffset(port
              .getAllAttributes());
          if (tmp != null) {
            g.drawLine((int) r[i].getX() + 1,
                (int) r[i].getY() + 1,
                (int) (r[i].getX() + r[i].getWidth()) - 3,
                (int) (r[i].getY() + r[i].getHeight()) - 3);
            g.drawLine((int) r[i].getX() + 1,
                (int) (r[i].getY() + r[i].getHeight()) - 3,
                (int) (r[i].getX() + r[i].getWidth()) - 3,
                (int) r[i].getY() + 1);
          } else
            g.drawRect((int) r[i].getX() + 2,
                (int) r[i].getY() + 2,
                (int) r[i].getWidth() - 5, (int) r[i]
                    .getHeight() - 5);
        }
      }
    }

    public void overlay(Graphics g) {
      if (edge != null && !firstOverlayCall && edge.isLeaf()) {
        // g.setColor(graph.getBackground()); // JDK 1.3
        g.setColor(graph.getForeground());
        g.setXORMode(graph.getBackground().darker());
        Graphics2D g2 = (Graphics2D) g;
        AffineTransform oldTransform = g2.getTransform();
        g2.scale(graph.getScale(), graph.getScale());
        graph.getUI().paintCell(g, edge, edge.getBounds(), true);
        g2.setTransform(oldTransform);
        if (isSourceEditing() && edge.getSource() != null)
          paintPort(g, edge.getSource());
        else if (isTargetEditing() && edge.getTarget() != null)
          paintPort(g, edge.getTarget());
      }
      firstOverlayCall = false;
    }

    protected void paintPort(Graphics g, CellView p) {
      boolean offset = (GraphConstants.getOffset(p.getAllAttributes()) != null);
      Rectangle2D r = (offset) ? p.getBounds() : p.getParentView()
          .getBounds();
      r = graph.toScreen((Rectangle2D) r.clone());
      int s = 3;
      r.setFrame(r.getX() - s, r.getY() - s, r.getWidth() + 2 * s, r
          .getHeight()
          + 2 * s);
      graph.getUI().paintCell(g, p, r, true);
    }

    protected boolean snap(boolean source, Point2D point) {
      boolean connect = graph.isConnectable() && isEdgeConnectable;
      Object port = graph.getPortForLocation(point.getX(), point.getY());
      if (port != null && connect) {
        CellView portView = graph.getGraphLayoutCache().getMapping(
            port, false);
        if (GraphConstants.isConnectable(portView.getParentView()
            .getAllAttributes())) {
          Object cell = edge.getCell();
          if (source && graph.getModel().acceptsSource(cell, port)) {
            if (edge.getSource() != portView) {
              overlay(graph.getGraphics());
              edge.setSource(portView);
              edge.update();
              overlay(graph.getGraphics());
            }
            return true;
          } else if (!source
              && graph.getModel().acceptsTarget(cell, port)) {
            if (edge.getTarget() != portView) {
              overlay(graph.getGraphics());
              edge.setTarget(portView);
              edge.update();
              overlay(graph.getGraphics());
            }
            return true;
          }
        }
      }
      return false;
    }

    public boolean isConstrainedMoveEvent(MouseEvent e) {
      GraphUI ui = graph.getUI();
      if (ui instanceof BasicGraphUI)
        return ((BasicGraphUI) ui).isConstrainedMoveEvent(e);
      return false;
    }

    /**
     * Returning true signifies a mouse event adds a new point to an edge.
     */
    public boolean isAddPointEvent(MouseEvent event) {
      return SwingUtilities.isRightMouseButton(event);
    }

    /**
     * Returning true signifies a mouse event removes a given point.
     */
    public boolean isRemovePointEvent(MouseEvent event) {
      return SwingUtilities.isRightMouseButton(event);
    }

    protected boolean isSourceEditing() {
      return source;
    }

    protected boolean isTargetEditing() {
      return target;
    }

    /*
     * Returns true if either the source, target, label or a point is being
     * edited.
     */
    protected boolean isEditing() {
      return source || target || label || currentLabel >= 0
          || currentPoint != null;
    }

    /**
     * Invoked when the mouse pointer has been moved on a component (with no
     * buttons down).
     */
    public void mouseMoved(MouseEvent event) {
      for (int i = 0; i < r.length; i++)
        if (r[i].contains(event.getPoint())) {
          graph.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
          event.consume();
          return;
        }
      if (loc.contains(event.getPoint()) && graph.isMoveable()
          && GraphConstants.isMoveable(edge.getAllAttributes())) {
        graph.setCursor(new Cursor(Cursor.HAND_CURSOR));
        event.consume();
      }
      if (extraLabelLocations != null && graph.isMoveable()
          && GraphConstants.isMoveable(edge.getAllAttributes())) {
        for (int i = 0; i < extraLabelLocations.length; i++) {
          if (extraLabelLocations[i].contains(event.getPoint())) {
            graph.setCursor(new Cursor(Cursor.HAND_CURSOR));
            event.consume();
          }
        }
      }
    }

    // Handle mouse pressed event.
    public void mousePressed(MouseEvent event) {
      /* INV: currentPoint = null; source = target = label = false; */
      if (!edge.isLeaf())
        return;
      boolean bendable = graph.isBendable()
          && GraphConstants.isBendable(edge.getAllAttributes());
      boolean disconnectable = graph.isDisconnectable()
          && GraphConstants.isDisconnectable(orig.getAllAttributes());
      int x = event.getX();
      int y = event.getY();
      // Detect hit on control point
      int index = 0;
      for (index = 0; index < r.length; index++) {
        if (r[index].contains(x, y)) {
          currentPoint = edge.getPoint(index);
          currentIndex = index;
          source = index == 0
              && (edge.getSource() == null || (disconnectable && GraphConstants
                  .isDisconnectable(edge.getSource()
                      .getParentView().getAllAttributes())));
          target = index == r.length - 1
              && (edge.getTarget() == null || (disconnectable && GraphConstants
                  .isDisconnectable(edge.getTarget()
                      .getParentView().getAllAttributes())));
          break;
        }
      }
      // Detect hit on label
      if (!isEditing() && graph.isMoveable()
          && GraphConstants.isMoveable(edge.getAllAttributes())
          && loc != null && loc.contains(x, y)
          && !isAddPointEvent(event) && !isRemovePointEvent(event)) {
        label = true;
      }
      // Detect hit on extra labels
      else if (extraLabelLocations != null && !isEditing()
          && graph.isMoveable()
          && GraphConstants.isMoveable(edge.getAllAttributes())
          && !isAddPointEvent(event) && !isRemovePointEvent(event)) {
        for (int i = 0; i < extraLabelLocations.length; i++) {
          if (extraLabelLocations[i] != null
              && extraLabelLocations[i].contains(x, y)) {
            currentLabel = i;
            break;
          }
        }
      }
      // Remove Point
      if (isRemovePointEvent(event)
          && currentPoint != null
          && !source
          && !target
          && bendable
          && (edge.getSource() == null || currentIndex > 0)
          && (edge.getTarget() == null || currentIndex < edge
              .getPointCount() - 1)) {
        edge.removePoint(index);
        edgeModified = true;
        mouseReleased(event);
        // Add Point
      } else if (isAddPointEvent(event) && !isEditing() && bendable) {
        int s = graph.getHandleSize();
        Rectangle2D rect = graph.fromScreen(new Rectangle(x - s, y - s,
            2 * s, 2 * s));
        if (edge.intersects(graph, rect)) {
          Point2D point = graph.fromScreen(graph.snap(new Point(event
              .getPoint())));
          double min = Double.MAX_VALUE, dist = 0;
          for (int i = 0; i < edge.getPointCount() - 1; i++) {
            Point2D p = edge.getPoint(i);
            Point2D p1 = edge.getPoint(i + 1);
            dist = new Line2D.Double(p, p1).ptLineDistSq(point);
            if (dist < min) {
              min = dist;
              index = i + 1;
            }
          }
          edge.addPoint(index, point);
          edgeModified = true;
          currentPoint = point;
          reloadPoints(edge);
          paint(graph.getGraphics());
        }
      }
      if (isEditing())
        event.consume();
    }

    public void mouseDragged(MouseEvent event) {
      edgeModified = true;
      Point2D p = graph.fromScreen(new Point(event.getPoint()));
      // Move Label
      if (label || currentLabel >= 0) {
        Rectangle2D r = edge.getBounds();
        if (r != null) {

          double x = p.getX();
          double y = p.getY();

          Point2D p0 = edge.getPoint(0);
          Point2D pe = edge.getPoint(edge.getPointCount() - 1);

          double p0x = p0.getX();
          double p0y = p0.getY();

          Point2D vector = edge.getLabelVector();
          double dx = vector.getX();
          double dy = vector.getY();

          double pex = p0.getX() + dx;
          double pey = p0.getY() + dy;

          double len = Math.sqrt(dx * dx + dy * dy);
          if (len > 0) {
            double u = GraphConstants.PERMILLE;
            double posy = len
                * (-y * dx + p0y * dx + x * dy - p0x * dy)
                / (-pey * dy + p0y * dy - dx * pex + dx * p0x);
            double posx = u
                * (-y * pey + y * p0y + p0y * pey - p0y * p0y
                    - pex * x + pex * p0x + p0x * x - p0x
                    * p0x)
                / (-pey * dy + p0y * dy - dx * pex + dx * p0x);
            p = new Point2D.Double(posx, posy);
          } else {
            p = new Point2D.Double(x - p0.getX(), y - p0.getY());
          }
          overlay(graph.getGraphics());
          if (label)
            edge.setLabelPosition(p);
          else
            edge.setExtraLabelPosition(currentLabel, p);
          edge.update();
          overlay(graph.getGraphics());
        }
      } else if (isEditing() && currentPoint != null) {
        // Find Source/Target Port
        if (!((source && snap(true, event.getPoint())) || (target && snap(
            false, event.getPoint())))) {
          // Else Use Point
          boolean acceptSource = source
              && (graph.getModel().acceptsSource(edge.getCell(),
                  null) || graph.isPreviewInvalidNullPorts());
          boolean acceptTarget = target
              && (graph.getModel().acceptsTarget(edge.getCell(),
                  null) || graph.isPreviewInvalidNullPorts());
          if (acceptSource || acceptTarget || !(source || target)) {
            overlay(graph.getGraphics());
            p = graph.fromScreen(graph.snap(new Point(event
                .getPoint())));
            // Constrained movement
            if (isConstrainedMoveEvent(event) && currentIndex >= 0) {
              // Reset Initial Positions
              EdgeView orig = (EdgeView) graph
                  .getGraphLayoutCache().getMapping(
                      edge.getCell(), false);
              Point2D origPoint = orig.getPoint(currentIndex);
              double totDx = p.getX() - origPoint.getX();
              double totDy = p.getY() - origPoint.getY();
              if (Math.abs(totDx) < Math.abs(totDy))
                p.setLocation(origPoint.getX(), p.getY());
              else
                p.setLocation(p.getX(), origPoint.getY());
            }
            // Do not move into negative space
            p.setLocation(Math.max(0, p.getX()), Math.max(0, p
                .getY()));
            currentPoint.setLocation(p);
            if (source) {
              edge.setPoint(0, p);
              edge.setSource(null);
            } else if (target) {
              edge.setPoint(edge.getPointCount() - 1, p);
              edge.setTarget(null);
            }
            edge.update();
            overlay(graph.getGraphics());
          }
        }
      }
    } // Handle mouse released event

    public void mouseReleased(MouseEvent e) {
      boolean clone = e.isControlDown() && graph.isCloneable();
      GraphModel model = graph.getModel();
      Object source = (edge.getSource() != null) ? edge.getSource()
          .getCell() : null;
      Object target = (edge.getTarget() != null) ? edge.getTarget()
          .getCell() : null;
      if (edgeModified && model.acceptsSource(edge.getCell(), source)
          && model.acceptsTarget(edge.getCell(), target)) {
        ConnectionSet cs = createConnectionSet(edge, edge.getCell(),
            clone);
        Map nested = GraphConstants.createAttributes(
            new CellView[] { edge }, null);
        if (clone) {
          Map cellMap = graph.cloneCells(graph
              .getDescendants(new Object[] { edge.getCell() }));
          nested = GraphConstants.replaceKeys(cellMap, nested);
          cs = cs.clone(cellMap);
          Object[] cells = cellMap.values().toArray();
          graph.getGraphLayoutCache().insert(cells, nested, cs, null,
              null);
        } else {
          graph.getGraphLayoutCache().edit(nested, cs, null, null);
        }
      } else {
        overlay(graph.getGraphics());
        edge.refresh(graph.getModel(), graph.getGraphLayoutCache(),
            false);
      }
      currentPoint = null;
      this.edgeModified = false;
      this.label = false;
      this.source = false;
      this.target = false;
      currentLabel = -1;
      currentIndex = -1;
      firstOverlayCall = true;
      e.consume();
    }

    protected ConnectionSet createConnectionSet(EdgeView view, Object edge,
        boolean verbose) {
      ConnectionSet cs = new ConnectionSet();
      Object sourcePort = null, targetPort = null;
      if (view.getSource() != null)
        sourcePort = view.getSource().getCell();
      if (view.getTarget() != null)
        targetPort = view.getTarget().getCell();
      if (verbose || sourcePort != graph.getModel().getSource(edge))
        cs.connect(edge, sourcePort, true);
      if (verbose || targetPort != graph.getModel().getTarget(edge))
        cs.connect(edge, targetPort, false);
      return cs;
    }

    // Update control points
    protected void invalidate() {
      EdgeView e = relevantEdge;
      int handlesize = graph.getHandleSize();
      EdgeRenderer er = (EdgeRenderer) edge.getRenderer();
      for (int i = 0; i < r.length; i++) {
        Point2D p = e.getPoint(i);
        p = graph.toScreen(new Point2D.Double(p.getX(), p.getY()));
        r[i].setFrame(p.getX() - handlesize, p.getY() - handlesize,
            2 * handlesize, 2 * handlesize);
        p = graph.toScreen(er.getLabelPosition(e));
        Dimension d = er.getLabelSize(graph, e, graph
            .convertValueToString(e));
        if (p != null && d != null) {
          Point2D s = graph.toScreen(new Point2D.Double(d.width,
              d.height));
          loc.setFrame(p.getX() - s.getX() / 2, p.getY() - s.getY()
              / 2, s.getX(), s.getY());
        }
      }
      if (extraLabelLocations != null) {
        for (int i = 0; i < extraLabelLocations.length; i++) {
          Point2D p = er.getExtraLabelPosition(e, i);
          if (p != null) {
            p = graph.toScreen((Point2D) p.clone());
            Dimension d = er.getExtraLabelSize(graph, e, i);
            if (d != null) {
              Point2D s = graph.toScreen(new Point2D.Double(
                  d.width, d.height));
              extraLabelLocations[i].setFrame(p.getX() - s.getX()
                  / 2, p.getY() - s.getY() / 2, s.getX(), s
                  .getY());
            }
          }
        }
      }
    }

  }

}
TOP

Related Classes of org.jgraph.graph.EdgeView$EdgeHandle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.