Package org.eclipse.zest.layouts.exampleUses

Source Code of org.eclipse.zest.layouts.exampleUses.SimpleSwingExample$MainPanel

/*******************************************************************************
* Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     The Chisel Group, University of Victoria
*******************************************************************************/
package org.eclipse.zest.layouts.exampleUses;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;

import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
import org.eclipse.zest.layouts.LayoutAlgorithm;
import org.eclipse.zest.layouts.LayoutBendPoint;
import org.eclipse.zest.layouts.LayoutEntity;
import org.eclipse.zest.layouts.LayoutRelationship;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.HorizontalLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.VerticalLayoutAlgorithm;
import org.eclipse.zest.layouts.exampleStructures.SimpleNode;
import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship;
import org.eclipse.zest.layouts.progress.ProgressEvent;
import org.eclipse.zest.layouts.progress.ProgressListener;

/**
* @author Rob Lintern
* @author Chris Bennett
*
* A simple example of using layout algorithms with a Swing application.
*/
public class SimpleSwingExample {
  private static final Color NODE_NORMAL_COLOR = new Color(225, 225, 255);
  private static final Color NODE_SELECTED_COLOR = new Color(255, 125, 125);
  //private static final Color NODE_ADJACENT_COLOR = new Color (255, 200, 125);
  private static final Color BORDER_NORMAL_COLOR = new Color(0, 0, 0);
  private static final Color BORDER_SELECTED_COLOR = new Color(255, 0, 0);
  //private static final Color BORDER_ADJACENT_COLOR = new Color (255, 128, 0);  
  private static final Stroke BORDER_NORMAL_STROKE = new BasicStroke(1.0f);
  private static final Stroke BORDER_SELECTED_STROKE = new BasicStroke(2.0f);
  private static final Color RELATIONSHIP_NORMAL_COLOR = Color.BLUE;
  //private static final Color RELATIONSHIP_HIGHLIGHT_COLOR = new Color (255, 200, 125);

  public static SpringLayoutAlgorithm SPRING = new SpringLayoutAlgorithm(LayoutStyles.NONE);
  public static TreeLayoutAlgorithm TREE_VERT = new TreeLayoutAlgorithm(LayoutStyles.NONE);
  public static HorizontalTreeLayoutAlgorithm TREE_HORIZ = new HorizontalTreeLayoutAlgorithm(LayoutStyles.NONE);
  public static RadialLayoutAlgorithm RADIAL = new RadialLayoutAlgorithm(LayoutStyles.NONE);
  public static GridLayoutAlgorithm GRID = new GridLayoutAlgorithm(LayoutStyles.NONE);
  public static HorizontalLayoutAlgorithm HORIZ = new HorizontalLayoutAlgorithm(LayoutStyles.NONE);
  public static VerticalLayoutAlgorithm VERT = new VerticalLayoutAlgorithm(LayoutStyles.NONE);

  private List algorithms = new ArrayList();
  private List algorithmNames = new ArrayList();

  private static final int INITIAL_PANEL_WIDTH = 700;
  private static final int INITIAL_PANEL_HEIGHT = 500;

  private static final boolean RENDER_HIGH_QUALITY = true;

  private static final double INITIAL_NODE_WIDTH = 20;
  private static final double INITIAL_NODE_HEIGHT = 20;
  private static final int ARROW_HALF_WIDTH = 4;
  private static final int ARROW_HALF_HEIGHT = 6;
  private static final Shape ARROW_SHAPE = new Polygon(new int[] { -ARROW_HALF_HEIGHT, ARROW_HALF_HEIGHT, -ARROW_HALF_HEIGHT }, new int[] { -ARROW_HALF_WIDTH, 0, ARROW_HALF_WIDTH }, 3);
  private static final Stroke ARROW_BORDER_STROKE = new BasicStroke(0.5f);
  private static final Color ARROW_HEAD_FILL_COLOR = new Color(125, 255, 125);
  private static final Color ARROW_HEAD_BORDER_COLOR = Color.BLACK;

  public static final String DEFAULT_NODE_SHAPE = "oval";

  private long updateGUICount = 0;

  private JFrame mainFrame;
  private JPanel mainPanel;
  private List entities;
  private List relationships;
  private JToolBar toolBar;
  private JLabel lblProgress;
  private JToggleButton btnContinuous;
  private JToggleButton btnAsynchronous;
  private JButton btnStop;

  private LayoutAlgorithm currentLayoutAlgorithm;
  protected String currentLayoutAlgorithmName;
  protected SimpleNode selectedEntity;
  protected Point mouseDownPoint;
  protected Point selectedEntityPositionAtMouseDown;
  private long idCount;
  protected String currentNodeShape = DEFAULT_NODE_SHAPE; // e.g., oval, rectangle

  public SimpleSwingExample() {

  }

  protected void addAlgorithm(LayoutAlgorithm algorithm, String name, boolean animate) {
    algorithms.add(algorithm);
    algorithmNames.add(name);
  }

  public void start() {

    mainFrame = new JFrame("Simple Swing Layout Example");
    toolBar = new JToolBar();
    mainFrame.getContentPane().setLayout(new BorderLayout());
    mainFrame.getContentPane().add(toolBar, BorderLayout.NORTH);
    lblProgress = new JLabel("Progress: ");
    mainFrame.getContentPane().add(lblProgress, BorderLayout.SOUTH);

    createMainPanel();
    mainFrame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        stop();
        mainFrame.dispose();

      }
    });

    btnContinuous = new JToggleButton("continuous", false);
    btnAsynchronous = new JToggleButton("asynchronous", false);

    toolBar.add(btnContinuous);
    toolBar.add(btnAsynchronous);

    btnStop = new JButton("Stop");
    btnStop.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        stop();
      }
    });
    toolBar.add(btnStop);

    JButton btnCreateGraph = new JButton("New graph");
    btnCreateGraph.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        stop();
        createGraph(true);
      }
    });
    toolBar.add(btnCreateGraph);
    JButton btnCreateTree = new JButton("New tree");
    btnCreateTree.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        stop();
        createGraph(false);
      }
    });
    toolBar.add(btnCreateTree);

    createGraph(false);

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    mainFrame.setLocation((int) (screenSize.getWidth() - INITIAL_PANEL_WIDTH) / 2, (int) (screenSize.getHeight() - INITIAL_PANEL_HEIGHT) / 2);
    mainFrame.pack();
    mainFrame.setVisible(true);
    mainFrame.repaint();

    try {
      SwingUtilities.invokeAndWait(new Runnable() {

        public void run() {
          SPRING = new SpringLayoutAlgorithm(LayoutStyles.NONE);
          TREE_VERT = new TreeLayoutAlgorithm(LayoutStyles.NONE);
          TREE_HORIZ = new HorizontalTreeLayoutAlgorithm(LayoutStyles.NONE);
          RADIAL = new RadialLayoutAlgorithm(LayoutStyles.NONE);
          GRID = new GridLayoutAlgorithm(LayoutStyles.NONE);
          HORIZ = new HorizontalLayoutAlgorithm(LayoutStyles.NONE);
          VERT = new VerticalLayoutAlgorithm(LayoutStyles.NONE);

          SPRING.setIterations(1000);
          // initialize layouts
          TREE_VERT.setComparator(new Comparator() {
            public int compare(Object o1, Object o2) {
              if (o1 instanceof Comparable && o2 instanceof Comparable) {
                return ((Comparable) o1).compareTo(o2);
              }
              return 0;
            }

          });
          GRID.setRowPadding(20);
          addAlgorithm(SPRING, "Spring", false);
          addAlgorithm(TREE_VERT, "Tree-V", false);
          addAlgorithm(TREE_HORIZ, "Tree-H", false);
          addAlgorithm(RADIAL, "Radial", false);
          addAlgorithm(GRID, "Grid", false);
          addAlgorithm(HORIZ, "Horiz", false);
          addAlgorithm(VERT, "Vert", false);

          for (int i = 0; i < algorithms.size(); i++) {
            final LayoutAlgorithm algorithm = (LayoutAlgorithm) algorithms.get(i);
            final String algorithmName = (String) algorithmNames.get(i);
            //final boolean algorithmAnimate = ((Boolean)algorithmAnimates.get(i)).booleanValue();
            JButton algorithmButton = new JButton(algorithmName);
            algorithmButton.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
                currentLayoutAlgorithm = algorithm;
                currentLayoutAlgorithmName = algorithmName;
                algorithm.setEntityAspectRatio((double) mainPanel.getWidth() / (double) mainPanel.getHeight());
                //animate = algorithmAnimate;
                performLayout();
              }
            });
            toolBar.add(algorithmButton);
          }
        }
      });
    } catch (InterruptedException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    } catch (InvocationTargetException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    }

  }

  private void stop() {
    if (currentLayoutAlgorithm != null && currentLayoutAlgorithm.isRunning()) {
      currentLayoutAlgorithm.stop();
    }
  }

  protected void performLayout() {
    stop();
    final Cursor cursor = mainFrame.getCursor();
    updateGUICount = 0;
    placeRandomly();
    final boolean continuous = btnContinuous.isSelected();
    final boolean asynchronous = btnAsynchronous.isSelected();
    ProgressListener progressListener = new ProgressListener() {
      public void progressUpdated(final ProgressEvent e) {
        //if (asynchronous) {
        updateGUI();
        //}
        lblProgress.setText("Progress: " + e.getStepsCompleted() + " of " + e.getTotalNumberOfSteps() + " completed ...");
        lblProgress.paintImmediately(0, 0, lblProgress.getWidth(), lblProgress.getHeight());
      }

      public void progressStarted(ProgressEvent e) {
        if (!asynchronous) {
          mainFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        }
        lblProgress.setText("Layout started ...");
        lblProgress.paintImmediately(0, 0, lblProgress.getWidth(), lblProgress.getHeight());
      }

      public void progressEnded(ProgressEvent e) {
        lblProgress.setText("Layout completed ...");
        lblProgress.paintImmediately(0, 0, lblProgress.getWidth(), lblProgress.getHeight());
        currentLayoutAlgorithm.removeProgressListener(this);
        if (!asynchronous) {
          mainFrame.setCursor(cursor);
        }
      }
    };

    currentLayoutAlgorithm.addProgressListener(progressListener);

    try {
      final LayoutEntity[] layoutEntities = new LayoutEntity[entities.size()];
      entities.toArray(layoutEntities);
      final LayoutRelationship[] layoutRelationships = new LayoutRelationship[relationships.size()];
      relationships.toArray(layoutRelationships);
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          try {
            currentLayoutAlgorithm.applyLayout(layoutEntities, layoutRelationships, 0, 0, mainPanel.getWidth(), mainPanel.getHeight(), asynchronous, continuous);
          } catch (InvalidLayoutConfiguration e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }

        }

      });
      //if (!animate) {
      updateGUI();
      //}
      // reset
      currentNodeShape = DEFAULT_NODE_SHAPE;
    } catch (StackOverflowError e) {
      e.printStackTrace();
    } finally {
    }
  }

  private void createMainPanel() {

    mainPanel = new MainPanel(); // see below for class definition
    mainPanel.setPreferredSize(new Dimension(INITIAL_PANEL_WIDTH, INITIAL_PANEL_HEIGHT));
    mainPanel.setBackground(Color.WHITE);
    mainPanel.setLayout(null);
    mainFrame.getContentPane().add(new JScrollPane(mainPanel), BorderLayout.CENTER);

    mainPanel.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        selectedEntity = null;
        for (Iterator iter = entities.iterator(); iter.hasNext() && selectedEntity == null;) {
          SimpleNode entity = (SimpleNode) iter.next();
          double x = entity.getX();
          double y = entity.getY();
          double w = entity.getWidth();
          double h = entity.getHeight();
          Rectangle2D.Double rect = new Rectangle2D.Double(x, y, w, h);
          if (rect.contains(e.getX(), e.getY())) {
            selectedEntity = entity;
          }
        }
        if (selectedEntity != null) {
          mouseDownPoint = e.getPoint();
          selectedEntityPositionAtMouseDown = new Point((int) selectedEntity.getX(), (int) selectedEntity.getY());
        } else {
          mouseDownPoint = null;
          selectedEntityPositionAtMouseDown = null;
        }
        updateGUI();
      }

      public void mouseReleased(MouseEvent e) {
        selectedEntity = null;
        mouseDownPoint = null;
        selectedEntityPositionAtMouseDown = null;
        updateGUI();
      }
    });

    mainPanel.addMouseMotionListener(new MouseMotionListener() {
      public void mouseDragged(MouseEvent e) {
        //                if (selectedEntity != null) {
        //          //TODO: Add mouse moving
        //                    //selectedEntity.setLocationInLayout(selectedEntityPositionAtMouseDown.x + dx, selectedEntityPositionAtMouseDown.y + dy);
        //                    updateGUI();
        //                }
      }

      public void mouseMoved(MouseEvent e) {
      }
    });
  }

  private void createGraph(boolean addNonTreeRels) {
    entities = new ArrayList();
    relationships = new ArrayList();
    selectedEntity = null;

    createTreeGraph(2, 4, 2, 5, true, true, addNonTreeRels);
    //        createCustomGraph();

    placeRandomly();
    mainPanel.repaint();
  }

  /**
   *
   * @param maxLevels Max number of levels wanted in tree 
   * @param maxChildren Max number of children for each node in the tree
   * @param randomNumChildren Whether or not to pick random number of levels (from 1 to maxLevels) and
   * random number of children (from 1 to maxChildren)
   */
  private void createTreeGraph(int minChildren, int maxChildren, int minLevels, int maxLevels, boolean randomNumChildren, boolean randomLevels, boolean addNonTreeRels) {
    LayoutEntity currentParent = createSimpleNode(getNextID());
    entities.add(currentParent);
    createTreeGraphRecursive(currentParent, minChildren, maxChildren, minLevels, maxLevels, 1, randomNumChildren, randomLevels, addNonTreeRels);
  }

  private void createTreeGraphRecursive(LayoutEntity currentParentNode, int minChildren, int maxChildren, int minLevel, int maxLevel, int level, boolean randomNumChildren, boolean randomLevels, boolean addNonTreeRels) {
    if (level > maxLevel) {
      return;
    }
    if (randomLevels) {
      if (level > minLevel) {
        double zeroToOne = Math.random();
        if (zeroToOne < 0.75) {
          return;
        }
      }
    }
    int numChildren = randomNumChildren ? Math.max(minChildren, (int) (Math.random() * maxChildren + 1)) : maxChildren;
    for (int i = 0; i < numChildren; i++) {
      LayoutEntity newNode = createSimpleNode(getNextID());
      entities.add(newNode);
      if (addNonTreeRels && entities.size() % 5 == 0) {
        int index = (int) (Math.random() * entities.size());
        LayoutRelationship rel = new SimpleRelationship((LayoutEntity) entities.get(index), newNode, false);
        relationships.add(rel);
      }
      LayoutRelationship rel = new SimpleRelationship(currentParentNode, newNode, false);
      relationships.add(rel);
      createTreeGraphRecursive(newNode, minChildren, maxChildren, minLevel, maxLevel, level + 1, randomNumChildren, randomLevels, addNonTreeRels);
    }
  }

  /**
   * Call this from createGraph in place of createTreeGraph
   * this for debugging and testing.
   */
  /*    private void createCustomGraph() {
   LayoutEntity A = createSimpleNode("1");
   LayoutEntity B = createSimpleNode("10");
   LayoutEntity _1 = createSimpleNode("100");
   entities.add(A);
   entities.add(B);
   entities.add(_1);
   relationships.add(new SimpleRelationship (A, B, false));
   relationships.add(new SimpleRelationship (A, _1, false));
   relationships.add(new SimpleRelationship (_1, A, false));
   }
   */
  private String getNextID() {
    String id = "" + idCount;
    idCount++;
    return id;
  }

  /** Places nodes randomly on the screen **/
  private void placeRandomly() {
    for (Iterator iter = entities.iterator(); iter.hasNext();) {
      SimpleNode simpleNode = (SimpleNode) iter.next();
      double x = Math.random() * INITIAL_PANEL_WIDTH - INITIAL_NODE_WIDTH;
      double y = Math.random() * INITIAL_PANEL_HEIGHT - INITIAL_NODE_HEIGHT;
      simpleNode.setLocationInLayout(x, y);
      simpleNode.setSizeInLayout(INITIAL_NODE_WIDTH, INITIAL_NODE_HEIGHT);
    }
  }

  /**
   * Creates a SimpleNode
   * @param name
   * @return
   */
  private SimpleNode createSimpleNode(String name) {
    SimpleNode simpleNode = new SimpleNode(name);
    return simpleNode;
  }

  private void updateGUI() {
    updateGUICount++;
    if (updateGUICount > 0) {
      mainPanel.paintImmediately(0, 0, mainPanel.getWidth(), mainPanel.getHeight());
    }
  }

  private static Point2D.Double getEllipseIntersectionPoint(double theta, double ellipseWidth, double ellipseHeight) {
    double nhalfw = ellipseWidth / 2.0; // half elllipse width
    double nhalfh = ellipseHeight / 2.0; // half ellipse height
    double tanTheta = Math.tan(theta);

    double a = nhalfw;
    double b = nhalfh;
    double x = (a * b) / Math.sqrt(Math.pow(b, 2) + Math.pow(a, 2) * Math.pow(tanTheta, 2));
    if ((theta > Math.PI / 2.0 && theta < 1.5 * Math.PI) || (theta < -Math.PI / 2.0 && theta > -1.5 * Math.PI)) {
      x = -x;
    }
    double y = tanTheta * x;
    Point2D.Double p = new Point2D.Double(x, y);
    return p;
  }

  public static void main(String[] args) {
    (new SimpleSwingExample()).start();
  }

  /**
   * A JPanel that provides entity and relationship rendering
   * Instead of letting Swing paint all the JPanels for us, we will just do our own painting here
   */
  private class MainPanel extends JPanel {

    private static final long serialVersionUID = 1;

    protected void paintChildren(Graphics g) {
      if (g instanceof Graphics2D && RENDER_HIGH_QUALITY) {
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
      }

      // paint the nodes
      for (Iterator iter = entities.iterator(); iter.hasNext();) {
        paintEntity((SimpleNode) iter.next(), g);
      }

      // paint the relationships
      for (Iterator iter = relationships.iterator(); iter.hasNext();) {
        paintRelationship((LayoutRelationship) iter.next(), g);
      }
    }

    private void paintEntity(SimpleNode entity, Graphics g) {
      boolean isSelected = selectedEntity != null && selectedEntity.equals(entity);
      g.setColor(isSelected ? NODE_SELECTED_COLOR : NODE_NORMAL_COLOR);
      if (currentNodeShape.equals("rectangle")) {
        g.fillRect((int) entity.getX(), (int) entity.getY(), (int) entity.getWidth(), (int) entity.getHeight());
      } else { // default
        g.fillOval((int) entity.getX(), (int) entity.getY(), (int) entity.getWidth(), (int) entity.getHeight());
      }
      g.setColor(isSelected ? BORDER_SELECTED_COLOR : BORDER_NORMAL_COLOR);
      String name = entity.toString();
      Rectangle2D nameBounds = g.getFontMetrics().getStringBounds(name, g);
      g.drawString(name, (int) (entity.getX() + entity.getWidth() / 2.0 - nameBounds.getWidth() / 2.0), (int) (entity.getY() + entity.getHeight() / 2.0 + nameBounds.getHeight() / 2.0));//- nameBounds.getHeight() - nameBounds.getY()));
      if (g instanceof Graphics2D) {
        ((Graphics2D) g).setStroke(isSelected ? BORDER_SELECTED_STROKE : BORDER_NORMAL_STROKE);
      }
      if (currentNodeShape.equals("rectangle")) {
        g.drawRect((int) entity.getX(), (int) entity.getY(), (int) entity.getWidth(), (int) entity.getHeight());
      } else { // default
        g.drawOval((int) entity.getX(), (int) entity.getY(), (int) entity.getWidth(), (int) entity.getHeight());
      }
    }

    private void paintRelationship(LayoutRelationship rel, Graphics g) {

      SimpleNode src = (SimpleNode) rel.getSourceInLayout();
      SimpleNode dest = (SimpleNode) rel.getDestinationInLayout();

      // Add bend points if required
      if (((SimpleRelationship) rel).getBendPoints() != null && ((SimpleRelationship) rel).getBendPoints().length > 0) {
        drawBendPoints(rel, g);
      } else {
        double srcX = src.getX() + src.getWidth() / 2.0;
        double srcY = src.getY() + src.getHeight() / 2.0;
        double destX = dest.getX() + dest.getWidth() / 2.0;
        double destY = dest.getY() + dest.getHeight() / 2.0;
        double dx = getLength(srcX, destX);
        double dy = getLength(srcY, destY);
        double theta = Math.atan2(dy, dx);
        drawRelationship(src, dest, theta, srcX, srcY, destX, destY, g);

        // draw an arrow in the middle of the line
        drawArrow(theta, srcX, srcY, dx, dy, g);
      }
    }

    /**
     * Draw a line from the edge of the src node to the edge of the destination node
     */
    private void drawRelationship(SimpleNode src, SimpleNode dest, double theta, double srcX, double srcY, double destX, double destY, Graphics g) {

      double reverseTheta = theta > 0.0d ? theta - Math.PI : theta + Math.PI;

      Point2D.Double srcIntersectionP = getEllipseIntersectionPoint(theta, src.getWidth(), src.getHeight());

      Point2D.Double destIntersectionP = getEllipseIntersectionPoint(reverseTheta, dest.getWidth(), dest.getHeight());

      drawRelationship(srcX + srcIntersectionP.getX(), srcY + srcIntersectionP.getY(), destX + destIntersectionP.getX(), destY + destIntersectionP.getY(), g);
    }

    /**
     * Draw a line from specified source to specified destination
     */
    private void drawRelationship(double srcX, double srcY, double destX, double destY, Graphics g) {
      g.setColor(RELATIONSHIP_NORMAL_COLOR);
      g.drawLine((int) srcX, (int) srcY, (int) destX, (int) destY);
    }

    private void drawArrow(double theta, double srcX, double srcY, double dx, double dy, Graphics g) {
      AffineTransform tx = new AffineTransform();
      double arrX = srcX + (dx) / 2.0;
      double arrY = srcY + (dy) / 2.0;
      tx.translate(arrX, arrY);
      tx.rotate(theta);
      Shape arrowTx = tx.createTransformedShape(ARROW_SHAPE);
      if (g instanceof Graphics2D) {
        g.setColor(ARROW_HEAD_FILL_COLOR);
        ((Graphics2D) g).fill(arrowTx);
        ((Graphics2D) g).setStroke(ARROW_BORDER_STROKE);
        g.setColor(ARROW_HEAD_BORDER_COLOR);
        ((Graphics2D) g).draw(arrowTx);
      }
    }

    /**
     * Get the length of a line ensuring it is not too small to render
     * @param start
     * @param end
     * @return
     */
    private double getLength(double start, double end) {
      double length = end - start;
      // make sure dx is not zero or too small
      if (length < 0.01 && length > -0.01) {
        if (length > 0) {
          length = 0.01;
        } else if (length < 0) {
          length = -0.01;
        }
      }
      return length;
    }

    /**
     * Draw a line from specified source to specified destination
     */
    private void drawCurvedRelationship(double srcX, double srcY, double control1X, double control1Y, double control2X, double control2Y, double destX, double destY, Graphics g) {
      GeneralPath shape = new GeneralPath();
      shape.moveTo((float) srcX, (float) srcY);
      shape.curveTo((float) control1X, (float) control1Y, (float) control2X, (float) control2Y, (float) destX, (float) destY);
      g.setColor(RELATIONSHIP_NORMAL_COLOR);
      ((Graphics2D) g).draw(shape);
    }

    /**
     * Draws a set of lines between bendpoints, returning the last bendpoint
     * drawn. Note that this assumes the first and last bendpoints are actually
     * the source node and destination node centre points.
     * @param relationship
     * @param bendNodes
     * @param bendEdges
     * @return the last bendpoint entity or null if there are no bendpoints
     */
    private void drawBendPoints(LayoutRelationship rel, Graphics g) {
      final String DUMMY_TITLE = "dummy";
      LayoutBendPoint bp;

      SimpleNode startEntity = (SimpleNode) rel.getSourceInLayout();
      SimpleNode destEntity = (SimpleNode) rel.getDestinationInLayout();
      double srcX = startEntity.getX();
      double srcY = startEntity.getY();

      // Transform the bendpoints to this coordinate system
      LayoutBendPoint[] bendPoints = ((SimpleRelationship) rel).getBendPoints();

      srcX = bendPoints[1].getX();
      srcY = bendPoints[1].getY();
      int bpNum = 2;
      while (bpNum < bendPoints.length - 1) { // ignore first and last bendpoints (src and dest)
        int currentBpNum = bpNum;
        bp = bendPoints[bpNum];
        if (bp.getIsControlPoint()) {
          if (bendPoints[bpNum + 1].getIsControlPoint()) {
            destEntity = new SimpleNode(DUMMY_TITLE, bendPoints[bpNum + 2].getX(), bendPoints[bpNum + 2].getY(), 0.01, 0.01);
            drawCurvedRelationship(srcX, srcY, bp.getX(), bp.getY(), bendPoints[bpNum + 1].getX(), bendPoints[bpNum + 1].getY(), bendPoints[bpNum + 2].getX(), bendPoints[bpNum + 2].getY(), g);
            bpNum += 4;
          } else {
            destEntity = new SimpleNode(DUMMY_TITLE, bp.getX(), bp.getY(), 0.01, 0.01);
          }
        } else {
          drawRelationship(srcX, srcY, bp.getX(), bp.getY(), g);
          bpNum++;
          destEntity = new SimpleNode(DUMMY_TITLE, bp.getX(), bp.getY(), 0.01, 0.01);
        }
        startEntity = destEntity;
        if (currentBpNum == bendPoints.length - 2) { // last point
          // draw an arrow in the middle of the line
          double dx = getLength(srcX, destEntity.getX());
          double dy = getLength(srcY, destEntity.getY());
          double theta = Math.atan2(dy, dx);
          drawArrow(theta, srcX, srcY, dx, dy, g);
        } else {
          srcX = startEntity.getX();
          srcY = startEntity.getY();
        }
      }

    }
  }
}
TOP

Related Classes of org.eclipse.zest.layouts.exampleUses.SimpleSwingExample$MainPanel

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.