public void init() {
    Disposer.register(myProject, this);
    initTree();

    MessageBusConnection busConnection = myProject.getMessageBus().connect(this);
    busConnection.subscribe(ToolWindowManagerListener.TOPIC, new ToolWindowManagerListener() {
      boolean wasVisible;

      @Override
      public void stateChanged(@NotNull ToolWindowManager toolWindowManager) {
        if (myToolWindow.isDisposed()) {
          return;
        }

        boolean visible = ((ToolWindowManagerEx)toolWindowManager).shouldUpdateToolWindowContent(myToolWindow);
        if (!visible || wasVisible) {
          wasVisible = visible;
          if (!visible) {
            scheduleStructureCleanupCache();
          }
          return;
        }

        scheduleStructureUpdate();
        wasVisible = true;
      }
    });

    getShortcutsManager().addListener(() -> scheduleTaskAndRunConfigUpdate(), this);

    getTaskActivator().addListener(() -> scheduleTaskAndRunConfigUpdate(), this);

    busConnection.subscribe(RunManagerListener.TOPIC, new RunManagerListener() {
      private void changed() {
        scheduleStructureRequest(() -> {
          assert myStructure != null;
          myStructure.visitExistingNodes(ModuleNode.class, node -> node.updateRunConfigurations());
        });
      }

      @Override
      public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) {
        changed();
      }

      @Override
      public void runConfigurationRemoved(@NotNull RunnerAndConfigurationSettings settings) {
        changed();
      }

      @Override
      public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) {
        changed();
      }
    });

    myToolWindow.setAdditionalGearActions(createAdditionalGearActionsGroup());

    scheduleStructureUpdate();
  }
public void init()