private ActionCallback processAjusted(
      final Map<Object, Condition> adjusted, final Set<Object> originallySelected) {
    final ActionCallback result = new ActionCallback();

    final Set<Object> allSelected = myUi.getSelectedElements();

    Set<Object> toSelect = new HashSet<Object>();
    for (Map.Entry<Object, Condition> entry : adjusted.entrySet()) {
      if (entry.getValue().value(entry.getKey())) continue;

      for (final Object eachSelected : allSelected) {
        if (isParentOrSame(entry.getKey(), eachSelected)) continue;
        toSelect.add(entry.getKey());
      }
      if (allSelected.isEmpty()) {
        toSelect.add(entry.getKey());
      }
    }

    final Object[] newSelection = ArrayUtil.toObjectArray(toSelect);

    if (newSelection.length > 0) {
      myUi._select(
          newSelection,
          new Runnable() {
            @Override
            public void run() {
              final Set<Object> hangByParent = new HashSet<Object>();
              processUnsuccessfulSelections(
                  newSelection,
                  new Function<Object, Object>() {
                    @Override
                    public Object fun(final Object o) {
                      if (myUi.isInStructure(o) && !adjusted.get(o).value(o)) {
                        hangByParent.add(o);
                      } else {
                        addAdjustedSelection(o, adjusted.get(o), null);
                      }
                      return null;
                    }
                  },
                  originallySelected);

              processHangByParent(hangByParent).notify(result);
            }
          },
          false,
          true,
          true);
    } else {
      result.setDone();
    }

    return result;
  }
  private boolean isParentOrSame(Object parent, Object child) {
    Object eachParent = child;
    while (eachParent != null) {
      if (parent.equals(eachParent)) return true;
      eachParent = myUi.getTreeStructure().getParentElement(eachParent);
    }

    return false;
  }
 public void setProcessingNow(boolean processingNow) {
   if (processingNow) {
     myProcessingCount++;
   } else {
     myProcessingCount--;
   }
   if (!isProcessingNow()) {
     myUi.maybeReady();
   }
 }
 private void processNextHang(Object element, final ActionCallback callback) {
   if (element == null || myUi.getSelectedElements().contains(element)) {
     callback.setDone();
   } else {
     final Object nextElement = myUi.getTreeStructure().getParentElement(element);
     if (nextElement == null) {
       callback.setDone();
     } else {
       myUi.select(
           nextElement,
           new Runnable() {
             public void run() {
               processNextHang(nextElement, callback);
             }
           },
           true);
     }
   }
 }
  public UpdaterTreeState(AbstractTreeUi ui, boolean isEmpty) {
    myUi = ui;

    if (!isEmpty) {
      final JTree tree = myUi.getTree();
      putAll(addPaths(tree.getSelectionPaths()), myToSelect);
      putAll(
          addPaths(tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot()))),
          myToExpand);
    }
  }
 private void invalidateToSelectWithRefsToParent(DefaultMutableTreeNode actionNode) {
   if (actionNode != null) {
     Object readyElement = myUi.getElementFor(actionNode);
     if (readyElement != null) {
       Iterator<Object> toSelect = myToSelect.keySet().iterator();
       while (toSelect.hasNext()) {
         Object eachToSelect = toSelect.next();
         if (readyElement.equals(myUi.getTreeStructure().getParentElement(eachToSelect))) {
           List<Object> children = myUi.getLoadedChildrenFor(readyElement);
           if (!children.contains(eachToSelect)) {
             toSelect.remove();
             if (!myToSelect.containsKey(readyElement)
                 && !myUi.getSelectedElements().contains(eachToSelect)) {
               addAdjustedSelection(eachToSelect, Conditions.alwaysFalse(), null);
             }
           }
         }
       }
     }
   }
 }
  private Set<Object> addPaths(Collection elements) {
    Set<Object> target = new HashSet<Object>();

    if (elements != null) {
      for (Object each : elements) {
        final Object node = ((TreePath) each).getLastPathComponent();
        if (node instanceof DefaultMutableTreeNode) {
          final Object descriptor = ((DefaultMutableTreeNode) node).getUserObject();
          if (descriptor instanceof NodeDescriptor) {
            final Object element = myUi.getElementFromDescriptor((NodeDescriptor) descriptor);
            if (element != null) {
              target.add(element);
            }
          }
        }
      }
    }
    return target;
  }
  private void processUnsuccessfulSelections(
      final Object[] toSelect, Function<Object, Object> restore, Set<Object> originallySelected) {
    final Set<Object> selected = myUi.getSelectedElements();

    boolean wasFullyRejected = false;
    if (toSelect.length > 0 && !selected.isEmpty() && !originallySelected.containsAll(selected)) {
      final Set<Object> successfulSelections = new HashSet<Object>();
      ContainerUtil.addAll(successfulSelections, toSelect);

      successfulSelections.retainAll(selected);
      wasFullyRejected = successfulSelections.isEmpty();
    } else if (selected.isEmpty() && originallySelected.isEmpty()) {
      wasFullyRejected = true;
    }

    if (wasFullyRejected && !selected.isEmpty()) return;

    for (Object eachToSelect : toSelect) {
      if (!selected.contains(eachToSelect)) {
        restore.fun(eachToSelect);
      }
    }
  }
  public boolean restore(@Nullable DefaultMutableTreeNode actionNode) {
    if (isProcessingNow() || !myCanRunRestore || myUi.hasNodesToUpdate()) {
      return false;
    }

    invalidateToSelectWithRefsToParent(actionNode);

    setProcessingNow(true);

    final Object[] toSelect = getToSelect();
    final Object[] toExpand = getToExpand();

    final Map<Object, Condition> adjusted = new WeakHashMap<Object, Condition>();
    adjusted.putAll(myAdjustedSelection);

    clearSelection();
    clearExpansion();

    final Set<Object> originallySelected = myUi.getSelectedElements();

    myUi._select(
        toSelect,
        new Runnable() {
          @Override
          public void run() {
            processUnsuccessfulSelections(
                toSelect,
                new Function<Object, Object>() {
                  @Override
                  public Object fun(final Object o) {
                    if (myUi.getTree().isRootVisible()
                        || !myUi.getTreeStructure().getRootElement().equals(o)) {
                      addSelection(o);
                    }
                    return o;
                  }
                },
                originallySelected);

            processAjusted(adjusted, originallySelected)
                .doWhenDone(
                    new Runnable() {
                      @Override
                      public void run() {
                        myUi.expand(
                            toExpand,
                            new Runnable() {
                              @Override
                              public void run() {
                                myUi.clearUpdaterState();
                                setProcessingNow(false);
                              }
                            },
                            true);
                      }
                    });
          }
        },
        false,
        true,
        true,
        false);

    return true;
  }