private void layoutElements() {
    // System.out.println();

    for (String id : this.orderedIds) {
      // System.out.println(id);
      BPMNElement currentElement = (BPMNElement) this.diagram.getElement(id);
      List<LayoutingElement> precedingElements = currentElement.getPrecedingElements();
      GridContext context = getContextByElement(currentElement);
      Cell<BPMNElement> cellOfElement = null;
      cellOfElement = placeElement(currentElement, precedingElements, context);

      boolean comesFromOtherGrid =
          precedingElements.size() == 1
              && precedingElements.get(0).getParent() != currentElement.getParent();
      if (!currentElement.isJoin() && !comesFromOtherGrid && cellOfElement.getPrevCell() != null) {
        // there is an edge hitting us left, so lets forbid
        // interleaving to use the left cell, if it's empty
        cellOfElement.getPrevCell().setPackable(false);
      }

      if (currentElement.isSplit()) {
        prelayoutSuccessors(currentElement, context, cellOfElement);
      }

      if (BPMNType.isAActivity(currentElement.getType())) {
        // search for attached events
        for (LayoutingElement e : currentElement.getOutgoingLinks()) {
          if (BPMNType.isACatchingIntermediateEvent(e.getType())) {
            context.grid.setCellOfItem((BPMNElement) e, cellOfElement);
          }
        }
      }
    }
  }
  /**
   * @param currentElement
   * @param context
   * @param cellOfElement
   */
  private void prelayoutSuccessors(
      BPMNElement currentElement, GridContext context, Cell<BPMNElement> cellOfElement) {
    // preLayout following Elements
    Cell<BPMNElement> baseCell = cellOfElement.after();
    Cell<BPMNElement> topCell = baseCell;
    List<LayoutingElement> followingElements = currentElement.getFollowingElements();

    if (BPMNType.isAActivity(currentElement.getType())) {
      // special case for docked events
      List<BPMNElement> dockedEventFollowers = new LinkedList<BPMNElement>();
      for (LayoutingElement el : currentElement.getOutgoingLinks()) {
        BPMNElement element = (BPMNElement) el;
        if (element.isADockedIntermediateEvent()) {
          for (LayoutingElement follower : element.getFollowingElements()) {
            dockedEventFollowers.add((BPMNElement) follower);
          }
        }
      }
      // to avoid crossing edges if there is more than one
      // docked event
      Collections.reverse(dockedEventFollowers);

      // put them under the task
      Cell<BPMNElement> insertCell = baseCell;
      for (BPMNElement dockedEventFollower : dockedEventFollowers) {
        Cell<BPMNElement> oldCell = context.grid.getCellOfItem(dockedEventFollower);
        if (oldCell != null) {
          if (oldCell.getValue() == dockedEventFollower) {
            continue; // Bug-Workaround: Don't prelayout
            // layouted elements;
          }
        }
        insertCell.getParent().insertRowBeneath();
        insertCell = insertCell.beneath();
        context.grid.setCellOfItem(dockedEventFollower, insertCell); // prelayout
      }

      // remove them from the following processing
      followingElements.removeAll(dockedEventFollowers);
    }

    // heuristic for text- & data-objects: put them to the top
    List<BPMNElement> textAnnotations = new LinkedList<BPMNElement>();
    List<BPMNElement> dataObjects = new LinkedList<BPMNElement>();
    for (LayoutingElement el : followingElements) {
      BPMNElement e = (BPMNElement) el;
      if (e.getType().equals(BPMNType.TextAnnotation)) {
        textAnnotations.add(e);
      } else if (e.getType().equals(BPMNType.DataObject)) {
        dataObjects.add(e);
      }
    }
    followingElements.removeAll(textAnnotations);
    followingElements.removeAll(dataObjects);
    // add them at the front
    followingElements.addAll(0, dataObjects);
    followingElements.addAll(0, textAnnotations);

    // heuristic for direct connection to join
    BPMNElement directJoin = null;
    for (LayoutingElement possibleJoin : followingElements) {
      if (possibleJoin.isJoin()) {
        directJoin = (BPMNElement) possibleJoin;
      }
    }
    if (directJoin != null) {
      // put in the middle
      followingElements.remove(directJoin);
      int position = (followingElements.size() / 2);
      followingElements.add(position, directJoin);
    }

    // normal preLayout following Elements
    int follow = 0;
    for (LayoutingElement newElem : followingElements) {
      if (newElem.getParent() == currentElement.getParent()) {
        follow++;
      }
    }
    for (int i = 0; i < follow / 2; i++) {
      topCell.getParent().insertRowAbove();
      baseCell.getParent().insertRowBeneath();
      topCell = topCell.above();
    }

    for (LayoutingElement newElem : followingElements) {
      if (newElem.getParent() != currentElement.getParent()) {
        continue;
      }
      context.grid.setCellOfItem((BPMNElement) newElem, topCell); // prelayout
      topCell = topCell.beneath();
      if (topCell == baseCell && follow % 2 == 0) {
        // skip baseCell if an even amount of elements is
        // following
        topCell = topCell.beneath();
      }
    }
  }