public void updateSelectionFromService()

in flutter-idea/src/io/flutter/view/InspectorPanel.java [867:969]


  public void updateSelectionFromService(boolean textEditorUpdated) {
    treeLoadStarted = true;
    selectionGroups.cancelNext();

    final CompletableFuture<DiagnosticsNode> pendingSelectionFuture =
      selectionGroups.getNext().getSelection(getSelectedDiagnostic(), treeType, isSummaryTree);

    CompletableFuture<?> allPending;
    final CompletableFuture<DiagnosticsNode> pendingDetailsFuture =
      isSummaryTree ? selectionGroups.getNext().getSelection(getSelectedDiagnostic(), treeType, false) : null;

    final CompletableFuture<?> selectionsReady =
      isSummaryTree ? CompletableFuture.allOf(pendingDetailsFuture, pendingSelectionFuture) : pendingSelectionFuture;
    selectionGroups.getNext().safeWhenComplete(selectionsReady, (ignored, error) -> {
      if (error != null) {
        FlutterUtils.warn(LOG, error);
        selectionGroups.cancelNext();
        return;
      }

      selectionGroups.promoteNext();

      final DiagnosticsNode newSelection = pendingSelectionFuture.getNow(null);

      if (!legacyMode) {
        DiagnosticsNode detailsSelection = null;
        if (pendingDetailsFuture != null) {
          detailsSelection = pendingDetailsFuture.getNow(null);
        }
        subtreeRoot = newSelection;

        applyNewSelection(newSelection, detailsSelection, true, textEditorUpdated);
      }
      else {
        // Legacy case. TODO(jacobr): deprecate and remove this code.
        // This case only exists for the RenderObject tree which we haven't updated yet to use the new UI style.
        // TODO(jacobr): delete it.
        if (newSelection == null) {
          recomputeTreeRoot(null, null, false, true);
          return;
        }
        // TODO(jacobr): switch to using current and next groups in this case
        // as well to avoid memory leaks.
        treeGroups.getCurrent()
          .safeWhenComplete(treeGroups.getCurrent().getParentChain(newSelection), (ArrayList<DiagnosticsPathNode> path, Throwable ex) -> {
            if (ex != null) {
              FlutterUtils.warn(LOG, ex);
              return;
            }
            DefaultMutableTreeNode treeNode = getRootNode();
            final DefaultTreeModel model = getTreeModel();
            final DefaultMutableTreeNode[] treePath = new DefaultMutableTreeNode[path.size()];
            for (int i = 0; i < path.size(); ++i) {
              treePath[i] = treeNode;
              final DiagnosticsPathNode pathNode = path.get(i);
              final DiagnosticsNode pathDiagnosticNode = pathNode.getNode();
              final ArrayList<DiagnosticsNode> newChildren = pathNode.getChildren();
              final DiagnosticsNode existingNode = getDiagnosticNode(treeNode);
              if (!identicalDiagnosticsNodes(pathDiagnosticNode, existingNode)) {
                treeNode.setUserObject(pathDiagnosticNode);
              }
              treeNode.setAllowsChildren(!newChildren.isEmpty());
              for (int j = 0; j < newChildren.size(); ++j) {
                final DiagnosticsNode newChild = newChildren.get(j);
                if (j >= treeNode.getChildCount() || !identicalDiagnosticsNodes(newChild, getDiagnosticNode(treeNode.getChildAt(j)))) {
                  final DefaultMutableTreeNode child;
                  if (j >= treeNode.getChildCount()) {
                    child = new DefaultMutableTreeNode();
                    treeNode.add(child);
                  }
                  else {
                    child = (DefaultMutableTreeNode)treeNode.getChildAt(j);
                  }
                  if (j != pathNode.getChildIndex()) {
                    setupTreeNode(child, newChild, false);
                    model.reload(child);
                  }
                  else {
                    child.setUserObject(newChild);
                    child.setAllowsChildren(newChild.hasChildren());
                    child.removeAllChildren();
                  }

                  // TODO(jacobr): we are likely calling the wrong node structure changed APIs.
                  // For example, we should be getting these change notifications for free if we
                  // switched to call methods on the model object directly to manipulate the tree.
                  model.nodeStructureChanged(child);
                  model.nodeChanged(child);
                }
                model.reload(treeNode);
              }
              if (i != path.size() - 1) {
                treeNode = (DefaultMutableTreeNode)treeNode.getChildAt(pathNode.getChildIndex());
              }
            }
            // TODO(jacobr): review and simplify this.
            final TreePath selectionPath = new TreePath(treePath);
            myRootsTree.setSelectionPath(selectionPath);
            animateTo(treePath[treePath.length - 1]);
          });
      }
    });
  }