SugiyamaLayoutAlgorithm.java :  » Workflow-Engines » OSWorkflow » com » opensymphony » workflow » designer » layout » Java Open Source

Java Open Source » Workflow Engines » OSWorkflow 
OSWorkflow » com » opensymphony » workflow » designer » layout » SugiyamaLayoutAlgorithm.java
// This file is part of the Echidna project
// (C) 2002 Forschungszentrum Informatik (FZI) Karlsruhe
// Please visit our website at http://echidna.sf.net
package com.opensymphony.workflow.designer.layout;

import javax.swing.*;

import org.jgraph.JGraph;
import org.jgraph.graph.*;

import java.awt.Point;
import java.awt.Rectangle;
import java.text.NumberFormat;
import java.util.*;

/**
 * Arranges the nodes with the Sugiyama Layout Algorithm.<br>
 *
 * <a href="http://plg.uwaterloo.ca/~itbowman/CS746G/Notes/Sugiyama1981_MVU/">
 *  Link to the algorithm</a>
 *
 *<br>
 *<br>
 * @author Sven Luzar<br>
 * @version 1.0 init
 */
public class SugiyamaLayoutAlgorithm implements LayoutAlgorithm
{

  /** Field for debug output
   */
  protected final boolean verbose = false;

  /** Const to add Attributes at the Nodes
   *
   */
  public static final String SUGIYAMA_VISITED = "SugiyamaVisited"/*#Frozen*/;

  /** Const to add the Cell Wrapper to the Nodes
   */
  public static final String SUGIYAMA_CELL_WRAPPER = "SugiyamaCellWrapper"/*#Frozen*/;

  /** represents the size of the grid in horizontal grid elements
   *
   */
  protected int gridAreaSize = Integer.MIN_VALUE;

  /** A List with Integer Objects. The List contains the
   *  history of movements per loop
   *  It was needed for the progress dialog
   */
  List movements = null;
  /** Represents the movements in the current loop.
   *  It was needed for the progress dialog
   */
  int movementsCurrentLoop = -1;
  /** Represents the maximum of movements in the current loop.
   *  It was needed for the progress dialog
   */
  int movementsMax = Integer.MIN_VALUE;
  /** Represents the current loop number
   *  It was needed for the progress dialog
   */
  int iteration = 0;
  public static final String KEY_HORIZONTAL_SPACING = "HorizontalSpacing";
  public static final String KEY_VERTICAL_SPACING = "VerticalSpacing";

  /**
   * Implementation.
   *
   * First of all the Algorithm searches the roots from the
   * Graph. Starting from this roots the Algorithm creates
   * levels and stores them in the member <code>levels</code>.
   * The Member levels contains List Objects and the List per level
   * contains Cell Wrapper Objects. After that the Algorithm
   * tries to solve the edge crosses from level to level and
   * goes top down and bottom up. After minimization of the
   * edge crosses the algorithm moves each node to its
   * bary center. Last but not Least the method draws the Graph.
   *
   * @see LayoutAlgorithm
   *
   */
  public void perform(JGraph jgraph, boolean applyToAll, Properties configuration)
  {

    Object[] selectedCells = (applyToAll ? jgraph.getRoots() : jgraph.getSelectionCells());
    CellView[] selectedCellViews = jgraph.getGraphLayoutCache().getMapping(selectedCells);

    Point spacing = new Point();
    /*  The Algorithm distributes the nodes on a grid.
     *  For this grid you can configure the horizontal spacing.
     *  This field specifies the configured value
     *
     */
    spacing.x = Integer.parseInt(configuration.getProperty(KEY_HORIZONTAL_SPACING));

    /*  The Algorithm distributes the nodes on a grid.
     *  For this grid you can configure the vertical spacing.
     *  This field specifies the configured value
     *
     */

    spacing.y = Integer.parseInt(configuration.getProperty(KEY_VERTICAL_SPACING));

    // search all roots
    List roots = searchRoots(jgraph, selectedCellViews);

    // return if no root found
    if(roots.size() == 0)
      return;

    // create levels
    List levels = fillLevels(jgraph, selectedCellViews, roots);

    // solves the edge crosses
    solveEdgeCrosses(jgraph, levels);

    // move all nodes into the barycenter
    moveToBarycenter(jgraph, selectedCellViews, levels);

    Point min = findMinimumAndSpacing(selectedCellViews, spacing);

    // draw the graph in the window
    drawGraph(jgraph, levels, min, spacing);

    // clean temp values from the nodes / cells
    // the clean up was made in drawGraph
    //cleanUp(selectedCellViews);

  }

  /** Debugdisplay for the edge crosses indicators on the System out
   */
  protected void displayEdgeCrossesValues(List levels)
  {
    System.out.println("----------------Edge Crosses Indicator Values"/*#Frozen*/);

    for(int i = 0; i < levels.size() - 1; i++)
    {
      // Get the current level
      List currentLevel = (List)levels.get(i);
      System.out.print("Level (" + i + "):"/*#Frozen*/);
      for(int j = 0; j < currentLevel.size(); j++)
      {
        CellWrapper sourceWrapper = (CellWrapper)currentLevel.get(j);

        System.out.print(NumberFormat.getNumberInstance().format(sourceWrapper.getEdgeCrossesIndicator()) + " - "/*#Frozen*/);
      }
      System.out.println();
    }
  }

  /** Debugdisplay for the grid positions on the System out
   */
  protected void displayGridPositions(List levels)
  {

    System.out.println("----------------GridPositions"/*#Frozen*/);

    for(int i = 0; i < levels.size() - 1; i++)
    {
      // Get the current level
      List currentLevel = (List)levels.get(i);
      System.out.print("Level (" + i + "):"/*#Frozen*/);
      for(int j = 0; j < currentLevel.size(); j++)
      {
        CellWrapper sourceWrapper = (CellWrapper)currentLevel.get(j);
        System.out.print(NumberFormat.getNumberInstance().format(sourceWrapper.getGridPosition()) + " - "/*#Frozen*/);
      }
      System.out.println();
    }
  }

  /** Debugdisplay for the priorities on the System out
   */
  protected void displayPriorities(List levels)
  {

    System.out.println("----------------down Priorities"/*#Frozen*/);

    for(int i = 0; i < levels.size() - 1; i++)
    {
      // Get the current level
      List currentLevel = (List)levels.get(i);
      System.out.print("Level (" + i + "):"/*#Frozen*/);
      for(int j = 0; j < currentLevel.size(); j++)
      {
        CellWrapper sourceWrapper = (CellWrapper)currentLevel.get(j);
        System.out.print(sourceWrapper.getPriority() + /*" (" +
                           sourceWrapper.nearestDownNeighborLevel + ") " +*/
                         " - "/*#Frozen*/);
      }
      System.out.println();
    }
  }

  /** Searches all Roots for the current Graph
   *  First the method marks any Node as not visited.
   *  Than calls searchRoots(MyGraphCell) for each
   *  not visited Cell.
   *  The Roots are stored in the List named roots
   *
   *   @return returns a List with the roots
   *  @see #searchRoots(JGraph, CellView[])
   */
  protected List searchRoots(JGraph jgraph, CellView[] selectedCellViews)
  {

    // get all cells and relations
    List vertexViews = new ArrayList(selectedCellViews.length);
    List roots = new ArrayList();

    // first: mark all as not visited
    // O(allCells&Edges)
    for(int i = 0; i < selectedCellViews.length; i++)
    {
      if(selectedCellViews[i] instanceof VertexView)
      {
        VertexView vertexView = (VertexView)selectedCellViews[i];
        vertexView.getAttributes().remove(SUGIYAMA_VISITED);
        vertexViews.add(selectedCellViews[i]);
      }
    }

    // O(graphCells)
    for(int i = 0; i < vertexViews.size(); i++)
    {
      VertexView vertexView = (VertexView)vertexViews.get(i);
      if(vertexView.getAttributes().get(SUGIYAMA_VISITED) == null)
      {
        searchRoots(jgraph, vertexView, roots);
      }
    }

    // Error Msg if the graph has no roots
    if(roots.size() == 0)
    {
      JOptionPane.showMessageDialog(null, "The Graph is not a DAG. Can't use Sugiyama Algorithm!"/*#Finished:Original="The Graph is not a DAG. Can't use Sugiyama Algorithm!"*/, null, JOptionPane.ERROR_MESSAGE);
    }
    return roots;
  }

  /** Searches Roots for the current Cell.
   *
   *  Therefore he looks at all Ports from the Cell.
   *  At the Ports he looks for Edges.
   *  At the Edges he looks for the Target.
   *  If the Ports of the current Cell contains the target ReViewNodePort
   *  he follows the edge to the source and looks at the
   *  Cell for this source.
   *
   */
  protected void searchRoots(JGraph jgraph, VertexView vertexViewToInspect, List roots)
  {
    // the node already visited
    if(vertexViewToInspect.getAttributes().get(SUGIYAMA_VISITED) != null)
    {
      return;
    }

    // mark as visited for cycle tests
    vertexViewToInspect.getAttributes().put(SUGIYAMA_VISITED, new Boolean(true));

    GraphModel model = jgraph.getModel();

    // get all Ports and search the relations at the ports
    //List vertexPortViewList = new ArrayList() ;

    Object vertex = vertexViewToInspect.getCell();

    int portCount = model.getChildCount(vertex);
    for(int j = 0; j < portCount; j++)
    {
      Object port = model.getChild(vertex, j);

      // Test all relations for where
      // the current node is a target node
      // for roots

      boolean isRoot = true;
      Iterator itrEdges = model.edges(port);
      while(itrEdges.hasNext())
      {
        Object edge = itrEdges.next();

        // if the current node is a target node
        // get the source node and test
        // the source node for roots

        if(model.getTarget(edge) == port)
        {
          Object sourcePort = model.getSource(edge);

          Object sourceVertex = model.getParent(sourcePort);

          CellView sourceVertexView = jgraph.getGraphLayoutCache().getMapping(sourceVertex, false);
          if(sourceVertexView instanceof VertexView)
          {
            searchRoots(jgraph, (VertexView)sourceVertexView, roots);
            isRoot = false;
          }
        }
      }
      // The current node is never a Target Node
      // -> The current node is a root node
      if(isRoot)
      {
        roots.add(vertexViewToInspect);
      }
    }
  }

  /** Method fills the levels and stores them in the member levels.

   *  Each level was represended by a List with Cell Wrapper objects.
   *  These Lists are the elements in the <code>levels</code> List.
   *
   */
  protected List fillLevels(JGraph jgraph, CellView[] selectedCellViews, List rootVertexViews)
  {
    List levels = new ArrayList();

    // mark as not visited
    // O(allCells)
    for(int i = 0; i < selectedCellViews.length; i++)
    {
      CellView cellView = selectedCellViews[i];
      cellView.getAttributes().remove(SUGIYAMA_VISITED);
    }

    Iterator roots = rootVertexViews.iterator();
    while(roots.hasNext())
    {
      VertexView vertexView = (VertexView)roots.next();
      fillLevels(jgraph, levels, 0, vertexView);
    }

    return levels;

  }

  /** Fills the List for the specified level with a wrapper
   *  for the MyGraphCell. After that the method called for
   *  each neighbor graph cell.
   *
   *  @param level        The level for the graphCell
   */
  protected void fillLevels(JGraph jgraph, List levels, int level, VertexView vertexView)
  {
    // be sure that a List container exists for the current level
    if(levels.size() == level)
      levels.add(level, new ArrayList());

    // if the cell already visited return
    if(vertexView.getAttributes().get(SUGIYAMA_VISITED) != null)
    {
      return;
    }

    // mark as visited for cycle tests
    vertexView.getAttributes().put(SUGIYAMA_VISITED, new Boolean(true));

    // put the current node into the current level
    // get the Level List
    List vecForTheCurrentLevel = (List)levels.get(level);

    // Create a wrapper for the node
    int numberForTheEntry = vecForTheCurrentLevel.size();

    CellWrapper wrapper = new CellWrapper(level, numberForTheEntry, vertexView);

    // put the Wrapper in the LevelList
    vecForTheCurrentLevel.add(wrapper);

    // concat the wrapper to the cell for an easy access
    vertexView.getAttributes().put(SUGIYAMA_CELL_WRAPPER, wrapper);

    // if the Cell has no Ports we can return, there are no relations
    Object vertex = vertexView.getCell();
    GraphModel model = jgraph.getModel();
    int portCount = model.getChildCount(vertex);

    // iterate any NodePort
    for(int i = 0; i < portCount; i++)
    {

      Object port = model.getChild(vertex, i);

      // iterate any Edge in the port
      Iterator itrEdges = model.edges(port);

      while(itrEdges.hasNext())
      {
        Object edge = itrEdges.next();

        // if the Edge is a forward edge we should follow this edge
        if(port == model.getSource(edge))
        {
          Object targetPort = model.getTarget(edge);
          Object targetVertex = model.getParent(targetPort);
          VertexView targetVertexView = (VertexView)jgraph.getGraphLayoutCache().getMapping(targetVertex, false);
          fillLevels(jgraph, levels, (level + 1), targetVertexView);
        }
      }
    }

    if(vecForTheCurrentLevel.size() > gridAreaSize)
    {
      gridAreaSize = vecForTheCurrentLevel.size();
    }

  }

  /** calculates the minimum for the paint area.
   *
   */
  protected Point findMinimumAndSpacing(CellView[] graphCellViews, Point spacing)
  {
    try
    {

      // variables
      /* represents the minimum x value for the paint area
       */
      int min_x = 1000000;

      /* represents the minimum y value for the paint area
       */
      int min_y = 1000000;

      // find the maximum & minimum coordinates

      for(int i = 0; i < graphCellViews.length; i++)
      {

        // the cellView and their bounds
        CellView cellView = graphCellViews[i];

        Rectangle cellViewBounds = cellView.getBounds().getBounds();

        // checking min area
        try
        {
          if(cellViewBounds.x < min_x)
            min_x = cellViewBounds.x;
          if(cellViewBounds.y < min_y)
            min_y = cellViewBounds.y;
          /*
          if (cellViewBounds.width > spacing.x)
            spacing.x = cellViewBounds.width;
          if (cellViewBounds.height > spacing.y)
            spacing.y = cellViewBounds.height;
            */

        }
        catch(Exception e)
        {
          System.err.println("---------> ERROR in calculateValues."/*#Frozen*/);
          e.printStackTrace();
        }
      }
      // if the cell sice is bigger than the userspacing
      // dublicate the spacingfactor
      return new Point(min_x, min_y);

    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    return null;
  }

  /** Updates the progress based on the movements count
   *
   */
  protected void updateProgress4Movements()
  {
    // adds the current loop count
    movements.add(new Integer(movementsCurrentLoop));
    iteration++;

    // if the current loop count is higher than the max movements count
    // memorize the new max
    if(movementsCurrentLoop > movementsMax)
    {
      movementsMax = movementsCurrentLoop;
    }

  }

  protected void solveEdgeCrosses(JGraph jgraph, List levels)
  {
    movements = new ArrayList(100);
    movementsCurrentLoop = -1;
    movementsMax = Integer.MIN_VALUE;
    iteration = 0;

    while(movementsCurrentLoop != 0)
    {

      // reset the movements per loop count
      movementsCurrentLoop = 0;

      if(verbose)
      {
        System.out.println("---------------------------- vor Sort"/*#Frozen*/);
        displayEdgeCrossesValues(levels);
      }

      // top down
      for(int i = 0; i < levels.size() - 1; i++)
      {
        movementsCurrentLoop += solveEdgeCrosses(jgraph, true, levels, i);
      }

      // bottom up
      for(int i = levels.size() - 1; i >= 1; i--)
      {
        movementsCurrentLoop += solveEdgeCrosses(jgraph, false, levels, i);
      }

      if(verbose)
      {
        System.out.println("---------------------------- nach Sort"/*#Frozen*/);
        displayEdgeCrossesValues(levels);
      }

      updateProgress4Movements();
    }
  }

  /**
   *  @return movements
   */
  protected int solveEdgeCrosses(JGraph jgraph, boolean down, List levels, int levelIndex)
  {
    // Get the current level
    List currentLevel = (List)levels.get(levelIndex);
    int movements = 0;

    // restore the old sort
    Object[] levelSortBefore = currentLevel.toArray();

    // new sort
    Collections.sort(currentLevel);

    // test for movements
    for(int j = 0; j < levelSortBefore.length; j++)
    {
      if(((CellWrapper)levelSortBefore[j]).getEdgeCrossesIndicator() != ((CellWrapper)currentLevel.get(j)).getEdgeCrossesIndicator())
      {
        movements++;

      }
    }

    GraphModel model = jgraph.getModel();

    // Collecations Sort sorts the highest value to the first value
    for(int j = currentLevel.size() - 1; j >= 0; j--)
    {
      CellWrapper sourceWrapper = (CellWrapper)currentLevel.get(j);

      VertexView sourceView = sourceWrapper.getVertexView();

      Object sourceVertex = sourceView.getCell();
      int sourcePortCount = model.getChildCount(sourceVertex);

      for(int k = 0; k < sourcePortCount; k++)
      {
        Object sourcePort = model.getChild(sourceVertex, k);

        Iterator sourceEdges = model.edges(sourcePort);
        while(sourceEdges.hasNext())
        {
          Object edge = sourceEdges.next();

          // if it is a forward edge follow it
          Object targetPort = null;
          if(down && sourcePort == model.getSource(edge))
          {
            targetPort = model.getTarget(edge);
          }
          if(!down && sourcePort == model.getTarget(edge))
          {
            targetPort = model.getSource(edge);
          }
          if(targetPort == null)
            continue;

          Object targetCell = model.getParent(targetPort);
          VertexView targetVertexView = (VertexView)jgraph.getGraphLayoutCache().getMapping(targetCell, false);
          CellWrapper targetWrapper = (CellWrapper)targetVertexView.getAttributes().get(SUGIYAMA_CELL_WRAPPER);

          // do it only if the edge is a forward edge to a deeper level
          if(down && targetWrapper != null && targetWrapper.getLevel() > levelIndex)
          {
            targetWrapper.addToEdgeCrossesIndicator(sourceWrapper.getEdgeCrossesIndicator());
          }
          if(!down && targetWrapper != null && targetWrapper.getLevel() < levelIndex)
          {
            targetWrapper.addToEdgeCrossesIndicator(sourceWrapper.getEdgeCrossesIndicator());
          }
        }
      }
    }

    return movements;
  }

  protected void moveToBarycenter(JGraph jgraph, CellView[] allSelectedViews, List levels)
  {

    //================================================================
    // iterate any ReViewNodePort
    GraphModel model = jgraph.getModel();
    for(int i = 0; i < allSelectedViews.length; i++)
    {
      if(!(allSelectedViews[i] instanceof VertexView))
        continue;

      VertexView vertexView = (VertexView)allSelectedViews[i];

      CellWrapper currentwrapper = (CellWrapper)vertexView.getAttributes().get(SUGIYAMA_CELL_WRAPPER);

      Object vertex = vertexView.getCell();
      int portCount = model.getChildCount(vertex);

      for(int k = 0; k < portCount; k++)
      {
        Object port = model.getChild(vertex, k);

        // iterate any Edge in the port

        Iterator edges = model.edges(port);
        while(edges.hasNext())
        {
          Object edge = edges.next();

          Object neighborPort = null;
          // if the Edge is a forward edge we should follow this edge
          if(port == model.getSource(edge))
          {
            neighborPort = model.getTarget(edge);
          }
          else
          {
            if(port == model.getTarget(edge))
            {
              neighborPort = model.getSource(edge);
            }
            else
            {
              continue;
            }
          }

          Object neighborVertex = model.getParent(neighborPort);

          VertexView neighborVertexView = (VertexView)jgraph.getGraphLayoutCache().getMapping(neighborVertex, false);

          if(neighborVertexView == vertexView)
            continue;

          CellWrapper neighborWrapper = (CellWrapper)neighborVertexView.getAttributes().get(SUGIYAMA_CELL_WRAPPER);

          if(currentwrapper == null || neighborWrapper == null || currentwrapper.level == neighborWrapper.level)
            continue;

          currentwrapper.priority++;

        }
      }
    }

    //================================================================
    for(int j = 0; j < levels.size(); j++)
    {
      List level = (List)levels.get(j);
      for(int i = 0; i < level.size(); i++)
      {
        // calculate the initial Grid Positions 1, 2, 3, .... per Level
        CellWrapper wrapper = (CellWrapper)level.get(i);
        wrapper.setGridPosition(i);
      }
    }

    if(verbose)
    {
      System.out.println("----------------Grid Pos before top down"/*#Frozen*/);
      displayPriorities(levels);
      displayGridPositions(levels);
      System.out.println("======================================="/*#Frozen*/);
    }

    movements = new ArrayList(100);
    movementsCurrentLoop = -1;
    movementsMax = Integer.MIN_VALUE;
    iteration = 0;

    //int movements = 1;

    while(movementsCurrentLoop != 0)
    {

      // reset movements
      movementsCurrentLoop = 0;

      // top down
      for(int i = 1; i < levels.size(); i++)
      {
        movementsCurrentLoop += moveToBarycenter(jgraph, levels, i);
      }

      if(verbose)
      {
        System.out.println("----------------Grid Pos after top down"/*#Frozen*/);
        displayGridPositions(levels);
        System.out.println("======================================="/*#Frozen*/);
      }

      // bottom up
      for(int i = levels.size() - 1; i >= 0; i--)
      {
        movementsCurrentLoop += moveToBarycenter(jgraph, levels, i);
      }

      if(verbose)
      {
        System.out.println("----------------Grid Pos after bottom up"/*#Frozen*/);
        displayGridPositions(levels);
        //displayDownPriorities();
        System.out.println("======================================="/*#Frozen*/);
      }

      this.updateProgress4Movements();
    }

  }

  protected int moveToBarycenter(JGraph jgraph, List levels, int levelIndex)
  {

    // Counter for the movements
    int movements = 0;

    // Get the current level
    List currentLevel = (List)levels.get(levelIndex);
    GraphModel model = jgraph.getModel();

    for(int currentIndexInTheLevel = 0; currentIndexInTheLevel < currentLevel.size(); currentIndexInTheLevel++)
    {

      CellWrapper sourceWrapper = (CellWrapper)currentLevel.get(currentIndexInTheLevel);

      float gridPositionsSum = 0;
      float countNodes = 0;

      VertexView vertexView = sourceWrapper.getVertexView();
      Object vertex = vertexView.getCell();
      int portCount = model.getChildCount(vertex);

      for(int i = 0; i < portCount; i++)
      {
        Object port = model.getChild(vertex, i);

        Iterator edges = model.edges(port);
        while(edges.hasNext())
        {
          Object edge = edges.next();

          // if it is a forward edge follow it
          Object neighborPort = null;
          if(port == model.getSource(edge))
          {
            neighborPort = model.getTarget(edge);
          }
          else
          {
            if(port == model.getTarget(edge))
            {
              neighborPort = model.getSource(edge);
            }
            else
            {
              continue;
            }
          }

          Object neighborVertex = model.getParent(neighborPort);

          VertexView neighborVertexView = (VertexView)jgraph.getGraphLayoutCache().getMapping(neighborVertex, false);
          CellWrapper targetWrapper = (CellWrapper)neighborVertexView.getAttributes().get(SUGIYAMA_CELL_WRAPPER);

          if(targetWrapper == sourceWrapper)
            continue;
          if(targetWrapper == null || targetWrapper.getLevel() == levelIndex)
            continue;

          gridPositionsSum += targetWrapper.getGridPosition();
          countNodes++;
        }
      }

      //----------------------------------------------------------
      // move node to new x coord
      //----------------------------------------------------------

      if(countNodes > 0)
      {
        float tmp = (gridPositionsSum / countNodes);
        int newGridPosition = Math.round(tmp);
        boolean toRight = (newGridPosition > sourceWrapper.getGridPosition());

        boolean moved = true;

        while(newGridPosition != sourceWrapper.getGridPosition() && moved)
        {
          int tmpGridPos = sourceWrapper.getGridPosition();

          moved = move(toRight, currentLevel, currentIndexInTheLevel, sourceWrapper.getPriority());

          if(moved)
            movements++;

          if(verbose)
          {

            System.out.print("try move at Level " + levelIndex + " with index " + currentIndexInTheLevel + " to " + (toRight ? "Right" : "Left") + " CurrentGridPos: " + tmpGridPos + " NewGridPos: " + newGridPosition + " exact: " + NumberFormat.getInstance().format(tmp) + "..."/*#Frozen*/);
            System.out.println(moved ? "success"/*#Frozen*/ : "can't move"/*#Frozen*/);

          }
        }
      }
    }
    return movements;
  }

  /**@param  toRight <tt>true</tt> = try to move the currentWrapper to right; <tt>false</tt> = try to move the currentWrapper to left;
   * @param  currentLevel List which contains the CellWrappers for the current level
   * @param  currentIndexInTheLevel
   * @param  currentPriority
   *
   * @return The free GridPosition or -1 is position is not free.
   */
  protected boolean move(boolean toRight, List currentLevel, int currentIndexInTheLevel, int currentPriority)
  {

    CellWrapper currentWrapper = (CellWrapper)currentLevel.get(currentIndexInTheLevel);

    boolean moved = false;
    int neighborIndexInTheLevel = currentIndexInTheLevel + (toRight ? 1 : -1);
    int newGridPosition = currentWrapper.getGridPosition() + (toRight ? 1 : -1);

    // is the grid position possible?

    if(0 > newGridPosition || newGridPosition >= gridAreaSize)
    {
      return false;
    }

    // if the node is the first or the last we can move
    if(toRight && currentIndexInTheLevel == currentLevel.size() - 1 || !toRight && currentIndexInTheLevel == 0)
    {

      moved = true;

    }
    else
    {
      // else get the neighbor and ask his gridposition
      // if he has the requested new grid position
      // check the priority

      CellWrapper neighborWrapper = (CellWrapper)currentLevel.get(neighborIndexInTheLevel);

      int neighborPriority = neighborWrapper.getPriority();

      if(neighborWrapper.getGridPosition() == newGridPosition)
      {
        if(neighborPriority >= currentPriority)
        {
          return false;
        }
        else
        {
          moved = move(toRight, currentLevel, neighborIndexInTheLevel, currentPriority);
        }
      }
      else
      {
        moved = true;
      }
    }

    if(moved)
    {
      currentWrapper.setGridPosition(newGridPosition);
    }
    return moved;
  }

  /** This Method draws the graph. For the horizontal position
   *  we are using the grid position from each graphcell.
   *  For the vertical position we are using the level position.
   *
   */
  protected void drawGraph(JGraph jgraph, List levels, Point min, Point spacing)
  {
    // paint the graph

    Map viewMap = new HashMap();

    for(int rowCellCount = 0; rowCellCount < levels.size(); rowCellCount++)
    {
      List level = (List)levels.get(rowCellCount);

      for(int colCellCount = 0; colCellCount < level.size(); colCellCount++)
      {
        CellWrapper wrapper = (CellWrapper)level.get(colCellCount);
        VertexView view = wrapper.vertexView;

        // remove the temp objects
        /* While the Algorithm is running we are putting some
         *  attributeNames to the MyGraphCells. This method
         *  cleans this objects from the MyGraphCells.
         *
         */
        view.getAttributes().remove(SUGIYAMA_CELL_WRAPPER);
        view.getAttributes().remove(SUGIYAMA_VISITED);
        wrapper.vertexView = null;

        // get the bounds from the cellView
        Rectangle bounds = (Rectangle)view.getBounds().clone();

        // adjust
        bounds.x = min.x + spacing.x * wrapper.getGridPosition();
        bounds.y = min.y + spacing.y * rowCellCount;

        Object cell = view.getCell();
        Map map = new AttributeMap();
        GraphConstants.setBounds(map, bounds);
        viewMap.put(cell, map);
      }

    }
    jgraph.getGraphLayoutCache().edit(viewMap, null, null, null);
  }

  /** cell wrapper contains all values
   *  for one node
   */
  class CellWrapper implements Comparable
  {

    /** sum value for edge Crosses
     */
    private double edgeCrossesIndicator = 0;
    /** counter for additions to the edgeCrossesIndicator
     */
    private int additions = 0;
    /** the vertical level where the cell wrapper is inserted
     */
    int level = 0;
    /** current position in the grid
     */
    int gridPosition = 0;
    /** priority for movements to the barycenter
     */
    int priority = 0;
    /** reference to the wrapped cell
     */
    VertexView vertexView = null;

    /** creates an instance and memorizes the parameters
     *
     */
    CellWrapper(int level, double edgeCrossesIndicator, VertexView vertexView)
    {
      this.level = level;
      this.edgeCrossesIndicator = edgeCrossesIndicator;
      this.vertexView = vertexView;
      additions++;
    }

    /** returns the wrapped cell
     */
    VertexView getVertexView()
    {
      return vertexView;
    }

    /** resets the indicator for edge crosses to 0
     */
    void resetEdgeCrossesIndicator()
    {
      edgeCrossesIndicator = 0;
      additions = 0;
    }

    /** retruns the average value for the edge crosses indicator
     *
     *  for the wrapped cell
     *
     */

    double getEdgeCrossesIndicator()
    {
      if(additions == 0)
        return 0;
      return edgeCrossesIndicator / additions;
    }

    /** Addes a value to the edge crosses indicator
     *  for the wrapped cell
     *
     */
    void addToEdgeCrossesIndicator(double addValue)
    {
      edgeCrossesIndicator += addValue;
      additions++;
    }

    /** gets the level of the wrapped cell
     */
    int getLevel()
    {
      return level;
    }

    /** gets the grid position for the wrapped cell
     */
    int getGridPosition()
    {
      return gridPosition;
    }

    /** Sets the grid position for the wrapped cell
     */
    void setGridPosition(int pos)
    {
      this.gridPosition = pos;
    }

    /** increments the the priority of this cell wrapper.
     *
     *  The priority was used by moving the cell to its
     *  barycenter.
     *
     */

    void incrementPriority()
    {
      priority++;
    }

    /** returns the priority of this cell wrapper.
     *
     *  The priority was used by moving the cell to its
     *  barycenter.
     */
    int getPriority()
    {
      return priority;
    }

    /**
     * @see java.lang.Comparable#compareTo(Object)
     */
    public int compareTo(Object compare)
    {
      if(((CellWrapper)compare).getEdgeCrossesIndicator() == this.getEdgeCrossesIndicator())
        return 0;

      double compareValue = (((CellWrapper)compare).getEdgeCrossesIndicator() - this.getEdgeCrossesIndicator());

      return (int)(compareValue * 1000);

    }
  }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.