private Insertion calcInsertion(IBranchPart branch, ParentSearchKey key, boolean withDisabled) {
    Column2 col = getColumn(branch);
    Chart2 chart = col.getOwnedChart();
    Point pos = key.getCursorPos();
    Cell2 cell = col.findCell(pos);
    if (cell == null) return null;

    Dimension insSize = getInsSize(key.getFigure());
    if (cell.getItems().isEmpty()) {
      return new CellInsertion2(branch, -1, insSize, cell.getOwnedRow().getHead());
    }
    int y = cell.getY() + chart.getMinorSpacing() / 2;
    int insHeight = insSize.height;
    int spacing = col.getMinorSpacing(); // getMinorSpacing(branch);
    int index = 0;
    for (Item2 item : cell.getItems()) {
      IBranchPart itemBranch = item.getBranch();
      Dimension itemSize = itemBranch.getFigure().getSize();
      int hint = y + (itemSize.height + insHeight) / 2;
      if (pos.y < hint) {
        return new CellInsertion2(branch, index, insSize, cell.getOwnedRow().getHead());
      }
      y += itemSize.height + spacing;
      if (withDisabled || itemBranch.getFigure().isEnabled()) index++;
    }
    return new CellInsertion2(
        branch, withDisabled ? index : -1, insSize, cell.getOwnedRow().getHead());
  }
  protected int calcInsIndex(IBranchPart branch, ParentSearchKey key, boolean withDisabled) {
    Column2 column = getColumn(branch);
    Chart2 chart = column.getOwnedChart();
    Point pos = key.getCursorPos();
    Cell2 cell = column.findCell(pos);
    if (cell == null || cell.getItems().isEmpty()) return -1;

    Dimension insSize = getInsSize(key.getFigure());
    int y = cell.getY() + chart.getMinorSpacing() / 2;
    int insHeight = insSize.height;
    int spacing = column.getMinorSpacing();
    int disabled = 0;
    for (Item2 item : cell.getItems()) {
      IBranchPart itemBranch = item.getBranch();
      Dimension itemSize = itemBranch.getFigure().getSize();
      int hint = y + (itemSize.height + insHeight) / 2;
      if (pos.y < hint) {
        return getOldIndex(branch, itemBranch) - disabled;
      }
      y += itemSize.height + spacing;
      if (!itemBranch.getFigure().isEnabled() && !withDisabled) disabled++;
    }
    return -1;
  }
  protected void fillSubBranches(
      IBranchPart branch, List<IBranchPart> subBranches, LayoutInfo info) {
    Rectangle area = info.getCheckedClientArea();

    Column2 col = getColumn(branch);
    Chart2 chart = col.getOwnedChart();
    int lineWidth = chart.getLineWidth();
    int cellSpacing = chart.getMinorSpacing();
    int itemSpacing = col.getMinorSpacing();

    IInsertion insertion = getCurrentInsertion(branch);
    RowHead insHead = (RowHead) MindMapUtils.getCache(branch, Spreadsheet.KEY_INSERTION_ROW_HEAD);

    int startX = info.getReference().x - col.getPrefCellWidth() / 2;
    int y = area.y + chart.getColHeadHeight() + cellSpacing / 2 + lineWidth;
    List<Row2> rows = chart.getRows();
    IInsertion rowIns =
        (IInsertion) MindMapUtils.getCache(chart.getTitle(), Spreadsheet.CACHE_ROW_INSERTION);
    for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) {
      if (rowIns != null && rowIns.getIndex() == rowIndex) {
        y += rowIns.getSize().height + chart.getMinorSpacing() + lineWidth;
      }

      Row2 row = rows.get(rowIndex);
      int x = startX;
      boolean insertionInRow = insertion != null && row.getHead().equals(insHead);
      Cell2 cell = col.findCellByRow(row);
      if (cell != null) {
        info.add(new Rectangle(x, y, col.getPrefCellWidth(), cell.getContentHeight()));
        List<Item2> items = cell.getItems();
        int num = items.size();
        int itemY = y;
        for (int i = 0; i < num; i++) {
          Item2 item = items.get(i);
          if (insertionInRow && insertion.getIndex() == i) {
            Rectangle r = insertion.createRectangle(x, y);
            info.add(r);
            itemY += r.height + itemSpacing;
          }
          IBranchPart child = item.getBranch();
          IFigure childFigure = child.getFigure();
          Dimension size = childFigure.getPreferredSize();

          int bh = 0;
          if (!branch.getBoundaries().isEmpty()) {
            for (IBoundaryPart boundary : branch.getBoundaries()) {
              List<IBranchPart> enclosingBranches = boundary.getEnclosingBranches();
              if (child.equals(enclosingBranches.get(0))) {
                bh = boundary.getFigure().getInsets().top;
                if (boundary.getTitle() != null && boundary.getTitle().getFigure() != null) {
                  Dimension s = boundary.getTitle().getFigure().getPreferredSize();
                  bh = Math.max(bh, s.height);
                }
                List<ITopic> topics = boundary.getBoundary().getEnclosingTopics();
                if (topics.size() > 1) {
                  itemY += bh;
                }
                bh = 0;
              }
              if (child.equals(enclosingBranches.get(enclosingBranches.size() - 1))) {
                bh = boundary.getFigure().getInsets().bottom;
              }
            }
          }

          Rectangle childBounds = new Rectangle(x, itemY, size.width, size.height + 10);
          info.put(childFigure, childBounds);
          itemY += size.height + itemSpacing + bh;
        }
        if (insertionInRow && insertion.getIndex() == num) {
          info.add(insertion.createRectangle(x, y));
        }
      } else if (insertionInRow) {
        info.add(insertion.createRectangle(x, y));
      }
      y += row.getPrefCellHeight() + cellSpacing + lineWidth;
    }
    if (rowIns != null && rowIns.getIndex() == rows.size()) {
      info.add(new Rectangle(startX, y, rowIns.getSize().width, 1));
    }
  }