AsyncResult<List<TreeNode>> (NodeDescriptor<?> descriptor, @NotNull MutualMap<Object, Integer> elementToIndexMap, DefaultMutableTreeNode parent, boolean addLoadingNode, @NotNull LoadedChildren loadedChildren) { AsyncResult<List<TreeNode>> result = new AsyncResult<>(); List<TreeNode> nodesToInsert = new ArrayList<>(); Collection<Object> allElements = elementToIndexMap.getKeys(); ActionCallback processingDone = allElements.isEmpty() ? ActionCallback.DONE : new ActionCallback(allElements.size()); for (Object child : allElements) { Integer index = elementToIndexMap.getValue(child); boolean needToUpdate = false; NodeDescriptor<?> loadedDesc = loadedChildren.getDescriptor(child); NodeDescriptor<?> childDescr; if (!isValid(loadedDesc, descriptor)) { childDescr = getTreeStructure().createDescriptor(child, descriptor); needToUpdate = true; } else { childDescr = loadedDesc; } if (index == null) { index = Integer.MAX_VALUE; needToUpdate = true; } childDescr.setIndex(index.intValue()); ActionCallback update = new ActionCallback(); if (needToUpdate) { update(childDescr, false) .onSuccess(changes -> { loadedChildren.putDescriptor(child, childDescr, changes); update.setDone(); }); } else { update.setDone(); } update.doWhenDone(new TreeRunnable("AbstractTreeUi.collectNodesToInsert: on done update") { @Override public void perform() { Object element = getElementFromDescriptor(childDescr); if (!isNodeNull(element)) { DefaultMutableTreeNode node = getNodeForElement(element, false); if (node == null || node.getParent() != parent) { DefaultMutableTreeNode childNode = createChildNode(childDescr); if (addLoadingNode || getBuilder().isAlwaysShowPlus(childDescr)) { insertLoadingNode(childNode, true); } else { addToUnbuilt(childNode); } nodesToInsert.add(childNode); createMapping(element, childNode); } } processingDone.setDone(); } }); } processingDone.doWhenDone(new TreeRunnable("AbstractTreeUi.collectNodesToInsert: on done processing") { @Override public void perform() { result.setDone(nodesToInsert); } }); return result; }