@Override
    protected void action() {
      final DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();

      final DebugProcessImpl debugProcess = mySession.getProcess();
      if (!debugProcess.isAttached()) {
        return;
      }
      final DebuggerContextImpl context = mySession.getContextManager().getContext();
      final SuspendContextImpl suspendContext = context.getSuspendContext();
      final ThreadReferenceProxyImpl suspendContextThread = suspendContext != null ? suspendContext.getEventThread() : null;

      final boolean showGroups = ThreadsViewSettings.getInstance().SHOW_THREAD_GROUPS;
      try {
        final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? suspendContextThread : null;
        final VirtualMachineProxyImpl vm = suspendContext != null ? suspendContext.getVirtualMachine() : debugProcess.getVirtualMachineProxy();

        final EvaluationContextImpl evaluationContext = suspendContext != null ? getDebuggerContext().createEvaluationContext() : null;
        final NodeManagerImpl nodeManager = getNodeFactory();

        if (showGroups) {
          ThreadGroupReferenceProxyImpl topCurrentGroup = null;

          if (currentThread != null) {
            topCurrentGroup = currentThread.threadGroupProxy();
            if (topCurrentGroup != null) {
              for (ThreadGroupReferenceProxyImpl parentGroup = topCurrentGroup.parent(); parentGroup != null; parentGroup = parentGroup.parent()) {
                topCurrentGroup = parentGroup;
              }
            }

            if (topCurrentGroup != null) {
              root.add(nodeManager.createNode(nodeManager.getThreadGroupDescriptor(null, topCurrentGroup), evaluationContext));
            }
            else {
              root.add(nodeManager.createNode(nodeManager.getThreadDescriptor(null, currentThread), evaluationContext));
            }
          }

          for (ThreadGroupReferenceProxyImpl group : vm.topLevelThreadGroups()) {
            if (group != topCurrentGroup) {
              DebuggerTreeNodeImpl threadGroup = nodeManager.createNode(nodeManager.getThreadGroupDescriptor(null, group), evaluationContext);
              root.add(threadGroup);
            }
          }
        }
        else {
          // do not show thread groups
          if (currentThread != null) {
            root.insert(nodeManager.createNode(nodeManager.getThreadDescriptor(null, currentThread), evaluationContext), 0);
          }
          List<ThreadReferenceProxyImpl> allThreads = new ArrayList<>(vm.allThreads());
          allThreads.sort(ThreadReferenceProxyImpl.ourComparator);

          for (ThreadReferenceProxyImpl threadProxy : allThreads) {
            if (threadProxy.equals(currentThread)) {
              continue;
            }
            root.add(nodeManager.createNode(nodeManager.getThreadDescriptor(null, threadProxy), evaluationContext));
          }
        }
      }
      catch (Exception ex) {
        root.add(MessageDescriptor.DEBUG_INFO_UNAVAILABLE);
        LOG.debug(ex);
      }

      final boolean hasThreadToSelect = suspendContextThread != null; // thread can be null if pause was pressed
      final List<ThreadGroupReferenceProxyImpl> groups;
      if (hasThreadToSelect && showGroups) {
        groups = new ArrayList<>();
        for (ThreadGroupReferenceProxyImpl group = suspendContextThread.threadGroupProxy(); group != null; group = group.parent()) {
          groups.add(group);
        }
        Collections.reverse(groups);
      }
      else {
        groups = Collections.emptyList();
      }

      DebuggerInvocationUtil.swingInvokeLater(getProject(), () -> {
        getMutableModel().setRoot(root);
        treeChanged();
        if (hasThreadToSelect) {
          selectThread(groups, suspendContextThread, true);
        }
      });
    }
@Override
    protected void action()