private void restoreUsageExpandState(final Collection<UsageState> states) {
   // always expand the last level group
   final DefaultMutableTreeNode root = (DefaultMutableTreeNode) myTree.getModel().getRoot();
   for (int i = root.getChildCount() - 1; i >= 0; i--) {
     final DefaultMutableTreeNode child = (DefaultMutableTreeNode) root.getChildAt(i);
     if (child instanceof GroupNode) {
       final TreePath treePath = new TreePath(child.getPath());
       myTree.expandPath(treePath);
     }
   }
   myTree.getSelectionModel().clearSelection();
   for (final UsageState usageState : states) {
     usageState.restore();
   }
 }
  @Override
  public void selectUsages(@NotNull Usage[] usages) {
    List<TreePath> paths = new LinkedList<TreePath>();

    for (Usage usage : usages) {
      final UsageNode node = myUsageNodes.get(usage);

      if (node != NULL_NODE && node != null) {
        paths.add(new TreePath(node.getPath()));
      }
    }

    myTree.setSelectionPaths(paths.toArray(new TreePath[paths.size()]));
    if (!paths.isEmpty()) myTree.scrollPathToVisible(paths.get(0));
  }
 private void updateImmediately() {
   if (myProject.isDisposed()) return;
   checkNodeValidity((DefaultMutableTreeNode) myTree.getModel().getRoot());
   if (myUsagePreviewPanel != null) {
     myUsagePreviewPanel.updateLayout(getSelectedUsageInfos());
   }
 }
  @Nullable
  private Node getSelectedNode() {
    TreePath leadSelectionPath = myTree.getLeadSelectionPath();
    if (leadSelectionPath == null) return null;

    DefaultMutableTreeNode node = (DefaultMutableTreeNode) leadSelectionPath.getLastPathComponent();
    return node instanceof Node ? (Node) node : null;
  }
 private void captureUsagesExpandState(TreePath pathFrom, final Collection<UsageState> states) {
   if (!myTree.isExpanded(pathFrom)) {
     return;
   }
   final DefaultMutableTreeNode node = (DefaultMutableTreeNode) pathFrom.getLastPathComponent();
   final int childCount = node.getChildCount();
   for (int idx = 0; idx < childCount; idx++) {
     final TreeNode child = node.getChildAt(idx);
     if (child instanceof UsageNode) {
       final Usage usage = ((UsageNode) child).getUsage();
       states.add(
           new UsageState(
               usage,
               myTree.getSelectionModel().isPathSelected(pathFrom.pathByAddingChild(child))));
     } else {
       captureUsagesExpandState(pathFrom.pathByAddingChild(child), states);
     }
   }
 }
  private void initTree() {
    myTree.setRootVisible(false);
    myTree.setShowsRootHandles(true);
    SmartExpander.installOn(myTree);
    TreeUtil.installActions(myTree);
    EditSourceOnDoubleClickHandler.install(myTree);
    myTree.addKeyListener(
        new KeyAdapter() {
          @Override
          public void keyPressed(KeyEvent e) {
            if (KeyEvent.VK_ENTER == e.getKeyCode()) {
              TreePath leadSelectionPath = myTree.getLeadSelectionPath();
              if (leadSelectionPath == null) return;

              DefaultMutableTreeNode node =
                  (DefaultMutableTreeNode) leadSelectionPath.getLastPathComponent();
              if (node instanceof UsageNode) {
                final Usage usage = ((UsageNode) node).getUsage();
                usage.navigate(false);
                usage.highlightInEditor();
              } else if (node.isLeaf()) {
                Navigatable navigatable = getNavigatableForNode(node);
                if (navigatable != null && navigatable.canNavigate()) {
                  navigatable.navigate(false);
                }
              }
            }
          }
        });

    TreeUtil.selectFirstNode(myTree);
    PopupHandler.installPopupHandler(
        myTree, IdeActions.GROUP_USAGE_VIEW_POPUP, ActionPlaces.USAGE_VIEW_POPUP);
    // TODO: install speed search. Not in openapi though. It makes sense to create a common
    // TreeEnchancer service.
  }
  @Nullable
  private Node[] getSelectedNodes() {
    TreePath[] leadSelectionPath = myTree.getSelectionPaths();
    if (leadSelectionPath == null || leadSelectionPath.length == 0) return null;

    final List<Node> result = new ArrayList<Node>();
    for (TreePath comp : leadSelectionPath) {
      final Object lastPathComponent = comp.getLastPathComponent();
      if (lastPathComponent instanceof Node) {
        final Node node = (Node) lastPathComponent;
        result.add(node);
      }
    }
    return result.isEmpty() ? null : result.toArray(new Node[result.size()]);
  }
  @Override
  @Nullable
  public Set<Usage> getSelectedUsages() {
    TreePath[] selectionPaths = myTree.getSelectionPaths();
    if (selectionPaths == null) {
      return null;
    }

    Set<Usage> usages = new THashSet<Usage>();
    for (TreePath selectionPath : selectionPaths) {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
      collectUsages(node, usages);
    }

    return usages;
  }
  @Nullable
  private UsageTarget[] getSelectedUsageTargets() {
    TreePath[] selectionPaths = myTree.getSelectionPaths();
    if (selectionPaths == null) return null;

    Set<UsageTarget> targets = new THashSet<UsageTarget>();
    for (TreePath selectionPath : selectionPaths) {
      Object lastPathComponent = selectionPath.getLastPathComponent();
      if (lastPathComponent instanceof UsageTargetNode) {
        UsageTargetNode usageTargetNode = (UsageTargetNode) lastPathComponent;
        UsageTarget target = usageTargetNode.getTarget();
        if (target != null && target.isValid()) {
          targets.add(target);
        }
      }
    }

    return targets.isEmpty() ? null : targets.toArray(new UsageTarget[targets.size()]);
  }
 private void rulesChanged() {
   ApplicationManager.getApplication().assertIsDispatchThread();
   final ArrayList<UsageState> states = new ArrayList<UsageState>();
   captureUsagesExpandState(new TreePath(myTree.getModel().getRoot()), states);
   final List<Usage> allUsages = new ArrayList<Usage>(myUsageNodes.keySet());
   Collections.sort(allUsages, USAGE_COMPARATOR);
   final Set<Usage> excludedUsages = getExcludedUsages();
   reset();
   myBuilder.setGroupingRules(getActiveGroupingRules(myProject));
   myBuilder.setFilteringRules(getActiveFilteringRules(myProject));
   ApplicationManager.getApplication()
       .runReadAction(
           new Runnable() {
             @Override
             public void run() {
               for (Usage usage : allUsages) {
                 if (!usage.isValid()) {
                   continue;
                 }
                 if (usage instanceof MergeableUsage) {
                   ((MergeableUsage) usage).reset();
                 }
                 appendUsage(usage);
               }
             }
           });
   excludeUsages(excludedUsages.toArray(new Usage[excludedUsages.size()]));
   if (myCentralPanel != null) {
     setupCentralPanel();
   }
   SwingUtilities.invokeLater(
       new Runnable() {
         @Override
         public void run() {
           if (isDisposed) return;
           restoreUsageExpandState(states);
           updateImmediately();
         }
       });
 }
 public void select() {
   if (myTree != null) {
     myTree.requestFocusInWindow();
   }
 }
 public DefaultMutableTreeNode getModelRoot() {
   return (DefaultMutableTreeNode) myTree.getModel().getRoot();
 }