@Override
  protected void updateCachedPreferredSize() {
    JTree tree = getTree();
    AbstractLayoutCache cache = treeState;
    if (tree == null || !isValid(tree) || cache == null) {
      preferredSize.width = 0;
      preferredSize.height = 0;
      validCachedPreferredSize = true;
    }
    else if (is("ide.tree.experimental.preferred.width", true)) {
      Rectangle paintBounds = tree.getVisibleRect();
      Insets insets = tree.getInsets();
      int visibleRowCount = tree.getVisibleRowCount();
      if (paintBounds.isEmpty()) {
        // no valid bounds yet, fall back to something that will work at least, mimic DefaultTreeUI
        paintBounds.width = 1 + insets.left + insets.right;
        paintBounds.height = tree.getRowHeight() * visibleRowCount + insets.top + insets.bottom;
      }
      JScrollPane pane = UIUtil.getParentOfType(JScrollPane.class, tree);
      if (pane != null) {
        JScrollBar bar = pane.getHorizontalScrollBar();
        if (bar != null && bar.isOpaque() && bar.isVisible()) {
          paintBounds.height += bar.getPreferredSize().height;
        }
      }
      TreePath path = cache.getPathClosestTo(0, paintBounds.y - insets.top);
      int width = 0;
      int row = cache.getRowForPath(path);
      if (row >= 0) {
        Rectangle buffer = new Rectangle();
        int maxPaintX = paintBounds.x + paintBounds.width;
        int maxPaintY = paintBounds.y + paintBounds.height;
        int rowsUsed = 0;
        for (; path != null; path = cache.getPathForRow(++row)) {
          Rectangle bounds = cache.getBounds(path, buffer);
          if (bounds == null) {
            LOG.warn("The bounds for the row " + row + " of the tree " + tree + " with model " + treeModel +
                     " are null, looks like a bug in " + cache);
            continue;
          }
          width = Math.max(width, bounds.x + bounds.width);
          ++rowsUsed;
          if (
            (bounds.y + bounds.height) >= maxPaintY &&
            (visibleRowCount <= 0 || rowsUsed >= visibleRowCount)
          ) {
            break;
          }
        }
        width += insets.left + insets.right;
        if (width < maxPaintX) {
          if (!is("ide.tree.prefer.to.shrink.width.on.scroll")) {
            width = maxPaintX;
          }
          else if (paintBounds.width < width || !is("ide.tree.prefer.aggressive.scrolling.to.the.left")) {
            int margin = intValue("ide.tree.preferable.right.margin", 25);
            if (margin > 0) {
              width = Math.min(width + paintBounds.width * margin / 100, maxPaintX);
            }
          }
        }
      }
      else { // row == -1, the tree is empty
        width = insets.left + insets.right;
      }
      preferredSize.width = width;
      preferredSize.height = insets.top + insets.bottom + cache.getPreferredHeight();
      validCachedPreferredSize = true;
    }
    else {
      super.updateCachedPreferredSize();
    }
  }
@Override
  protected void updateCachedPreferredSize()