boolean (@NotNull TreeUpdatePass pass) { boolean wasCleanedUp = false; if (myRootNodeWasQueuedToInitialize) { Object root = getTreeStructure().getRootElement(); Object currentRoot = getElementFor(myRootNode); if (Comparing.equal(root, currentRoot)) return false; Object rootAgain = getTreeStructure().getRootElement(); if (root != rootAgain && !root.equals(rootAgain)) { assert false : "getRootElement() if called twice must return either root1 == root2 or root1.equals(root2)"; } cleanUpNow(); wasCleanedUp = true; } if (myRootNodeWasQueuedToInitialize) return true; myRootNodeWasQueuedToInitialize = true; Object rootElement = getTreeStructure().getRootElement(); addNodeAction(rootElement, false, node -> processDeferredActions()); Ref<NodeDescriptor<?>> rootDescriptor = new Ref<>(null); boolean bgLoading = isToBuildChildrenInBackground(rootElement); Runnable build = new TreeRunnable("AbstractTreeUi.initRootNodeNowIfNeeded: build") { @Override public void perform() { rootDescriptor.set(getTreeStructure().createDescriptor(rootElement, null)); getRootNode().setUserObject(rootDescriptor.get()); update(rootDescriptor.get(), true); pass.addToUpdated(rootDescriptor.get()); } }; Runnable update = new TreeRunnable("AbstractTreeUi.initRootNodeNowIfNeeded: update") { @Override public void perform() { Object fromDescriptor = getElementFromDescriptor(rootDescriptor.get()); if (!isNodeNull(fromDescriptor)) { createMapping(fromDescriptor, getRootNode()); } insertLoadingNode(getRootNode(), true); boolean willUpdate = false; if (!rootDescriptor.isNull() && isAutoExpand(rootDescriptor.get())) { willUpdate = myUnbuiltNodes.contains(getRootNode()); expand(getRootNode(), true); } ActionCallback callback; if (willUpdate) { callback = ActionCallback.DONE; } else { callback = updateNodeChildren(getRootNode(), pass, null, false, false, false, true, true); } callback.doWhenDone(new TreeRunnable("AbstractTreeUi.initRootNodeNowIfNeeded: on done updateNodeChildren") { @Override public void perform() { if (getRootNode().getChildCount() == 0) { myTreeModel.nodeChanged(getRootNode()); } } }); } }; if (bgLoading) { queueToBackground(build, update) .onSuccess(new TreeConsumer<>("AbstractTreeUi.initRootNodeNowIfNeeded: on processed queueToBackground") { @Override public void perform() { invokeLaterIfNeeded(false, new TreeRunnable("AbstractTreeUi.initRootNodeNowIfNeeded: on processed queueToBackground later") { @Override public void perform() { myRootNodeInitialized = true; processNodeActionsIfReady(myRootNode); } }); } }); } else { build.run(); update.run(); myRootNodeInitialized = true; processNodeActionsIfReady(myRootNode); } return wasCleanedUp; }