Package lupos.gui.operatorgraph.arrange

Source Code of lupos.gui.operatorgraph.arrange.LayeredDrawing

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.gui.operatorgraph.arrange;

import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.TreeSet;

import lupos.gui.operatorgraph.AbstractSuperGuiComponent;
import lupos.gui.operatorgraph.GraphBox;
import lupos.gui.operatorgraph.GraphWrapperIDTuple;
import lupos.gui.operatorgraph.OperatorGraph;
import lupos.gui.operatorgraph.graphwrapper.GraphWrapper;

public final class LayeredDrawing {

  public static void updateX(final OperatorGraph operatorgraph,
      final GraphBox box,
      final HashMap<GraphWrapper, Integer> levels, final int level,
      final int x,
      final HashSet<GraphBox> visited) {
    if (visited.contains(box)) {
      return;
    }

    visited.add(box);

    final int offset = box.getX() - x;

    box.setX(x);

    // --- update position of subtree - begin ---
    for (final Object o : box.getOp().getSucceedingElements()) {
      final GraphWrapperIDTuple gwIDt = (GraphWrapperIDTuple) o;
      final GraphBox box2 = operatorgraph.getBoxes().get(
          gwIDt.getOperator());
      if (levels.get(box2.getOp()) > level) {
        updateX(operatorgraph, box2, levels, level, box2.getX()
            + offset, visited);
      }
    }
    // --- update position of subtree - end ---
  }

  public static void updateXWithoutUpdatingParentsSize(
      final OperatorGraph operatorgraph, final GraphBox box,
      final HashMap<GraphWrapper, Integer> levels, final int level,
      final int x, final HashSet<GraphBox> visited) {
    if (visited.contains(box)) {
      return;
    }

    visited.add(box);

    final int offset = box.getX() - x;

    box.setXWithoutUpdatingParentsSize(x);

    // --- update position of subtree - begin ---
    for (final Object o : box.getOp().getSucceedingElements()) {
      final GraphWrapperIDTuple gwIDt = (GraphWrapperIDTuple) o;
      final GraphBox box2 = operatorgraph.getBoxes().get(
          gwIDt.getOperator());
      if (levels.get(box2.getOp()) > level) {
        updateXWithoutUpdatingParentsSize(operatorgraph, box2, levels,
            level, box2.getX() + offset, visited);
      }
    }
    // --- update position of subtree - end ---
  }

  protected static HashMap<GraphWrapper, Integer> generateGraph(
      final OperatorGraph operatorgraph) {
    final HashMap<GraphWrapper, Integer> levels = new HashMap<GraphWrapper, Integer>();
    // walk through the list of root elements...
    for (final GraphWrapper gw : operatorgraph.getRootList(false)) {
      depthFirstDetermineLevel(new HashSet<GraphWrapper>(),
          new HashSet<GraphWrapper>(), gw, 0, operatorgraph, levels);
      // build level tree of current root element
    }
    return levels;
  }

  @SuppressWarnings("unchecked")
  protected static void depthFirstDetermineLevel(
      final HashSet<GraphWrapper> visited,
      final HashSet<GraphWrapper> visitedNotCloned,
      final GraphWrapper op, final int level,
      final OperatorGraph operatorgraph,
      final HashMap<GraphWrapper, Integer> levels) {
    if (visited.contains(op)) { // if current operator was visited before...
      return; // abort
    }

    visited.add(op); // add current operator the list of visited

    // all operatorss have already a GraphBox...
    // if (boxes.containsKey(op)) {
      if (!visitedNotCloned.contains(op)) {
        levels.put(op, level);
      } else {
        // if the current level is higher than the level of the existing
        // GraphBox...
        if (levels.get(op) < level) {
          levels.put(op, level); // update the level of the
          // GraphBox
        } else {
          return;
        }
      }

    visitedNotCloned.add(op);

    // walk trough the children of the current operator and add them
    // recursively...
    for (final GraphWrapperIDTuple child : op.getSucceedingElements()) {
      depthFirstDetermineLevel((HashSet<GraphWrapper>) visited.clone(),
          visitedNotCloned, child.getOperator(), level + 1,
          operatorgraph, levels);
    }
  }

  public static void arrange(final OperatorGraph operatorgraph) {

    final HashMap<GraphWrapper, Integer> levels = generateGraph(operatorgraph);

    final LinkedList<GraphRow> rows = new LinkedList<GraphRow>();

    // create a HashMap which holds a List of GraphWrapper objects for each
    // level...
    final LinkedHashMap<Integer, LinkedList<GraphWrapper>> graphWrapperOfLevel = new LinkedHashMap<Integer, LinkedList<GraphWrapper>>();
    final HashMap<GraphWrapper, GraphBox> boxes = operatorgraph.getBoxes();

    // walk trough all GraphWrapper objects that have a GraphBox...
    for (final GraphWrapper gw : boxes.keySet()) {
      // get the GraphBox to the GraphWrapper...
      final int currentLevel = levels.get(gw);

      // get list of GraphWrapper objects for the level of the GraphBox...
      LinkedList<GraphWrapper> lgw = graphWrapperOfLevel
          .get(currentLevel);

      if (lgw == null) { // if list of the level is null...
        lgw = new LinkedList<GraphWrapper>(); // create list
      }

      lgw.add(gw); // add current GraphWrapper object to list

      // add list of GraphWrappers to the HashMap for the level...
      graphWrapperOfLevel.put(currentLevel, lgw);
    }

    // initialize some more variables...
    int level = 0;
    int y = (int) Math.ceil(operatorgraph.PADDING);

    // get GraphWrapper elements for the current level...
    while (graphWrapperOfLevel.get(level) != null) {
      // create a row for this level...
      final GraphRow row = new GraphRow(operatorgraph, y,
          graphWrapperOfLevel.get(
          level).size());

      rows.add(row); // add row to rows list

      // define order!
      final TreeSet<GraphWrapper> toSort = new TreeSet<GraphWrapper>(
          new Comparator<GraphWrapper>() {
            @Override
            public int compare(final GraphWrapper arg0,
                final GraphWrapper arg1) {
              if (arg0.getPrecedingElements() == null
                  || arg0.getPrecedingElements().size() == 0) {
                return -1;
              }

              if (arg1.getPrecedingElements() == null
                  || arg1.getPrecedingElements().size() == 0) {
                return 1;
              }

              final GraphWrapper parent0 = arg0
                  .getPrecedingElements().get(0);
              final GraphWrapper parent1 = arg1
                  .getPrecedingElements().get(0);

              if (parent0.equals(parent1)) {
                final GraphWrapperIDTuple gwidT0 = parent0
                    .getGraphWrapperIDTuple(arg0);
                final GraphWrapperIDTuple gwidT1 = parent1
                    .getGraphWrapperIDTuple(arg1);

                if (gwidT0.getId() == gwidT1.getId()) { // siblings
                                    // !
                  for (final GraphWrapperIDTuple gwidtuple : parent0
                      .getSucceedingElements()) {
                    if (gwidtuple.getOperator()
                        .equals(arg0)) {
                      return -1;
                    } else if (gwidtuple.getOperator()
                        .equals(arg1)) {
                      return 1;
                    }
                  }
                } else if (gwidT0.getId() < gwidT1.getId()) {
                  return -1;
                } else if (gwidT0.getId() > gwidT1.getId()) {
                  return 1;
                }

                System.err
                    .println("QueryGraph: GraphWrapper object not found!");

                return -1;
              } else {
                final GraphBox b0 = boxes.get(parent0);
                final GraphBox b1 = boxes.get(parent1);

                if (b0.getX() < b1.getX()) {
                  return -1;
                } else {
                  return 1;
                }
              }
            }
          });

      toSort.addAll(graphWrapperOfLevel.get(level));

      // add the GraphBoxes of all GraphWrappers of this level to the
      // row...
      row.addAllWithoutUpdatingParentsSize(toSort, boxes);

      // add row height and spacing height to y...
      y += row.getHeight() + operatorgraph.SPACING_Y;

      level++; // increment level
    }

    int maxRowId = 0;

    // move each box under it's preceding box / boxes...
    for (int r = 0; r < rows.size(); ++r) { // walk through rows...
      final GraphRow row = rows.get(r); // get current row

      // move first row to most left corner...
      if (levels.get(row.getBoxes().get(0).getOp()) == 0) {
        // define x value for far left box...
        int localX = (int) Math.ceil(operatorgraph.PADDING);

        // walk through boxes of the first row...
        for (final GraphBox localBox : row.getBoxes()) {
          updateXWithoutUpdatingParentsSize(operatorgraph, localBox,
              levels, level,
              localX,
              new HashSet<GraphBox>());

          // update the x value for the next box...
          localX += localBox.width + operatorgraph.PADDING;
        }
      } else {
        // center boxes under preceding boxes...

        // walk through boxes...
        for (final GraphBox box : row.getBoxes()) {
          // get preceding OPs of current box...
          final LinkedList<GraphWrapper> precOps = box.getOp()
              .getPrecedingElements();

          // remove preceding OPs from higher levels...
          for (int j = 0; j < precOps.size(); ++j) {
            if (levels.get(boxes.get(precOps.get(j)).getOp()) > levels
                .get(box.getOp())) {
              precOps.remove(j);
            }
          }

          if (precOps.size() == 0) {
            continue;
          }

          int center = 0;

          // switch over number of preceding OPs...
          if (precOps.size() == 1) { // one preceding OP...
            // move the box under it's preceding box...

            // get preceding box...
            final GraphBox precBox = boxes.get(precOps.get(0));

            // determine center of preceding box...
            center = precBox.getX() + (precBox.width / 2);

            // move box so that center of both boxes are equal...
            updateXWithoutUpdatingParentsSize(operatorgraph, box,
                levels, level,
                center
                - (box.width / 2), new HashSet<GraphBox>());
          } else {
            // center box under preceding boxes...

            // get first preceding box...
            GraphBox preBox = boxes.get(precOps.get(0));

            // determine center of first preceding box...
            center = preBox.getX() + (preBox.width / 2);

            // walk through preceding operators...
            for (int j = 1; j < precOps.size(); ++j) {
              // get preceding box...
              preBox = boxes.get(precOps.get(j));

              // determine center of preceding box...
              final int preBoxCenter = preBox.getX()
                  + (preBox.width / 2);

              // determine new center...
              center = (center + preBoxCenter) / 2;
            }

            // move box to center of preceding boxes...
            updateXWithoutUpdatingParentsSize(operatorgraph, box,
                levels, level,
                center
                - (box.width / 2), new HashSet<GraphBox>());
          }
        }
      }

      // resolve box overlapping...
      GraphBox box = row.getBoxes().get(0); // get first box

      // move left box if not at the right position...
      if (box.getX() < (int) Math.ceil(operatorgraph.PADDING)) {
        updateXWithoutUpdatingParentsSize(operatorgraph, box, levels,
            level,
            (int) Math.ceil(operatorgraph.PADDING),
            new HashSet<GraphBox>());
      }

      // walk through boxes...
      for (int i = 1; i < row.getBoxes().size(); ++i) {
        // get previous box...
        final GraphBox preBox = row.getBoxes().get(i - 1);

        box = row.getBoxes().get(i); // get current box

        // if previous box and current box overlap...
        if (preBox.getX() + preBox.width
            + (int) Math.ceil(operatorgraph.SPACING_X) > box.getX()) {
          // move current box...
          updateXWithoutUpdatingParentsSize(operatorgraph,
              box,
              levels,
              level,
              preBox.getX() + preBox.width
                  + (int) Math.ceil(operatorgraph.SPACING_X),
              new HashSet<GraphBox>());
        }
      }

      // determine ID of longest row...
      if (row.getWidth() > rows.get(maxRowId).getWidth()) {
        maxRowId = r;
      }
    }

    if (rows.size() > 0) {
      final int maxWidth = rows.get(maxRowId).getWidth();

      // walk through all rows previous to maxRowId...
      for (int r = 0; r < maxRowId; ++r) {
        // center the current row...
        rows.get(r).centerWithoutUpdatingParentsSize(maxWidth / 2);
      }

      // --- resolve annotation overlapping - begin ---
      for (final GraphRow row : rows) { // walk through all rows...
        // walk through all boxes of the row...
        for (final GraphBox box : row.getBoxes()) {
          final Hashtable<GraphWrapper, AbstractSuperGuiComponent> lineAnnotations = box
              .getLineAnnotations();
          final Iterator<GraphWrapper> lineAnnotationsGWsIt = lineAnnotations
              .keySet().iterator();

          // box has less than two line annotations...
          if (lineAnnotations.size() < 2) {
            continue;
          }

          GraphWrapper previousAnnotationGW = lineAnnotationsGWsIt
              .next();
          AbstractSuperGuiComponent previousAnnotation = lineAnnotations
              .get(previousAnnotationGW);

          // walk through all but the first annotation...
          while (lineAnnotationsGWsIt.hasNext()) {
            // get current GW...
            final GraphWrapper lineAnnotationGW = lineAnnotationsGWsIt
                .next();

            // get current annotation....
            final AbstractSuperGuiComponent annotation = lineAnnotations
                .get(lineAnnotationGW);

            // check for overlapping...
            if (previousAnnotation.isOverlapping(annotation)) {
              final GraphBox previousAnnotationTargetBox = boxes
                  .get(previousAnnotationGW);
              final GraphBox annotationTargetBox = boxes
                  .get(lineAnnotationGW);

              // move annotation target box...
              if (previousAnnotationTargetBox.getX() <= annotationTargetBox
                  .getX()) {
                final int annotationDistance = (previousAnnotation
                    .getLocation().x + previousAnnotation
                    .getPreferredSize().width)
                    - annotation.getLocation().x;
                final int newX = annotationTargetBox.getX()
                    + annotationTargetBox.width
                    + (int) Math
                        .ceil(operatorgraph.PADDING)
                    + annotationDistance;

                annotationTargetBox
                    .setXWithoutUpdatingParentsSize(newX);
              }
              // move previousAnnotation target box...
              else if (previousAnnotationTargetBox.getX() > annotationTargetBox
                  .getX()) {
                final int annotationDistance = (annotation
                    .getLocation().x + annotation
                    .getPreferredSize().width)
                    - previousAnnotation.getLocation().x;
                final int newX = previousAnnotationTargetBox
                    .getX()
                    + previousAnnotationTargetBox.width
                    + (int) Math
                        .ceil(operatorgraph.PADDING)
                    + annotationDistance;

                previousAnnotationTargetBox
                    .setXWithoutUpdatingParentsSize(newX);
              }
            }

            // set current annotation GW as previous annotation GW
            // for he next run...
            previousAnnotationGW = lineAnnotationGW;

            // set current annotation as previous annotation for the
            // next run...
            previousAnnotation = annotation;
          }
        }
      }
      // --- resolve annotation overlapping - end ---
    }

  }
}
TOP

Related Classes of lupos.gui.operatorgraph.arrange.LayeredDrawing

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.