public TreePath getPathClosestTo(final int x, final int y) {
    if (getStateRoot() == null) {
      return null;
    }

    if (isFixedRowHeight()) {
      return getFixedHeightPathClosestToImpl(x, y);
    }

    if (!getStateRoot().isExpanded()) {
      return isRootVisible() ? getStateRoot().getModelPath() : null;
    }

    int cummulativeHeight = 0;
    VariableHeightStateNode currentParent = (VariableHeightStateNode) getStateRoot();
    if (isRootVisible()) {
      if (currentParent.getHeight() > y) {
        return currentParent.getModelPath();
      }
      cummulativeHeight += currentParent.getHeight();
    }

    while (true) {
      int modelChildCount = currentParent.getModelChildCount();
      if (modelChildCount == 0) {
        return currentParent.getModelPath();
      }
      for (int i = 0; i < modelChildCount; i++) {
        if (cummulativeHeight + currentParent.getChildrenHeights()[i] > y
            || i + 1 == modelChildCount) {
          Object modelChild = currentParent.getModelChildNode(i);
          VariableHeightStateNode childNode =
              (VariableHeightStateNode) currentParent.getChild(modelChild);
          if (childNode != null) {
            currentParent = childNode;
            if (cummulativeHeight + currentParent.getHeight() > y || !currentParent.isExpanded()) {

              return currentParent.getModelPath();
            }
            cummulativeHeight += currentParent.getHeight();
            break;
          }
          return currentParent.getModelPath().pathByAddingChild(modelChild);
        }
        cummulativeHeight += currentParent.getChildrenHeights()[i];
      }
    }
  }
  public TreePath getPathForRow(final int row) {
    if (row < 0 || row >= getRowCount()) {
      return null;
    }

    if (isRootVisible() && row == 0) {
      return getStateRoot().getModelPath();
    }

    VariableHeightStateNode parent = (VariableHeightStateNode) getStateRoot();

    while (true) {
      if (parent.getChildCount() == 0) {
        int modelIndex = row - parent.getRow() - 1;
        Object modelChild = parent.getModelChildNode(modelIndex);
        return parent.getModelPath().pathByAddingChild(modelChild);
      }

      for (int i = 0; i < parent.getChildCount(); i++) {
        VariableHeightStateNode childNode = (VariableHeightStateNode) parent.get(i);
        if (childNode.getRow() == row) {
          return childNode.getModelPath();
        }
        if (childNode.getRow() > row) {
          int modelChildIndex = parent.getModelIndexOfChild(childNode.getModelNode());
          int modelIndex = modelChildIndex - (childNode.getRow() - row);
          Object modelChild = parent.getModelChildNode(modelIndex);
          return parent.getModelPath().pathByAddingChild(modelChild);
        }
        if (childNode.getRow() < row
            && childNode.getRow() + childNode.getTotalChildrenCount() >= row) {
          parent = childNode;
          break;
        }
        if (i == parent.getChildCount() - 1) {
          int modelChildIndex = parent.getModelIndexOfChild(childNode.getModelNode());
          int modelIndex =
              modelChildIndex + row - (childNode.getRow() + childNode.getTotalChildrenCount());
          Object modelChild = parent.getModelChildNode(modelIndex);
          return parent.getModelPath().pathByAddingChild(modelChild);
        }
      }
    }
  }