void collapsePaths(@NotNull Iterable<@NotNull TreePath> paths) {
      var started = 0L;
      var count = 0L;
      if (LOG.isDebugEnabled()) {
        started = System.currentTimeMillis();
      }
      var pathList = toList(paths);
      if (pathList.size() == 1) {
        var path = pathList.get(0);
        if (isNotLeaf(path)) {
          setExpandedState(path, false);
        }
        else { // the path has become a leaf, remove it to save memory
          expandedState.remove(path);
        }
        return;
      }
      pathList.sort(Comparator.comparing(TreePath::getPathCount));
      Set<TreePath> toExpand = new LinkedHashSet<>();
      Set<TreePath> toNotExpand = new HashSet<>();
      Set<TreePath> toCollapse = new LinkedHashSet<>();
      Set<TreePath> collapseRoots = new LinkedHashSet<>();
      for (TreePath path : pathList) {
        ++count;
        TreePath parent = path.getParentPath();
        boolean parentWillBeCollapsed = toCollapse.contains(parent);
        boolean pathWillBeCollapsed = false;
        if (parent == null || toExpand.contains(parent) || parentWillBeCollapsed) {
          toCollapse.add(path);
          pathWillBeCollapsed = true;
        }
        else if (!toNotExpand.contains(parent)) {
          if (shouldAllParentsBeExpanded(parent, toExpand, toNotExpand)) {
            toCollapse.add(path);
            pathWillBeCollapsed = true;
          }
        }
        if (!parentWillBeCollapsed && pathWillBeCollapsed) {
          collapseRoots.add(path);
        }
      }
      List<TreePath> toCollapseList = new ArrayList<>(toCollapse);
      Collections.reverse(toCollapseList);
      try {
        beginBulkOperation();
        fireBulkCollapseStarted();
        suspendExpandCollapseAccessibilityAnnouncements();
        for (TreePath path : toExpand) {
          markPathExpanded(path);
          fireTreeExpanded(path);
        }
        for (TreePath path : toCollapseList) {
          if (isNotLeaf(path)) {
            markPathCollapsed(path);
            fireTreeCollapsed(path);
            if (removeDescendantSelectedPaths(path, false) && !isPathSelected(path)) {
              addSelectionPath(path);
            }
          }
          else { // the path has become a leaf, remove it to save memory
            expandedState.remove(path);
          }
        }
      }
      finally {
        resumeExpandCollapseAccessibilityAnnouncements();
        fireBulkCollapseEnded();
        endBulkOperation();
      }
      if (accessibleContext != null) {
        // Only announce the topmost collapsed nodes, to avoid spamming announcements.
        for (TreePath collapseRoot : collapseRoots) {
          fireAccessibleTreeCollapsed(collapseRoot);
        }
        ((AccessibleJTree)accessibleContext).fireVisibleDataPropertyChange();
      }
      if (LOG.isDebugEnabled()) {
        LOG.debug("Collapsed " + count + " paths, time: " + (System.currentTimeMillis() - started) + " ms");
      }
    }
void collapsePaths(@NotNull Iterable<@NotNull TreePath> paths)