JBPopup (@NotNull Project project, final @NotNull Consumer<? super ConfigurationFactory> creator, final @Nullable ConfigurationType selectedConfigurationType, boolean showTitle) { NewRunConfigurationTreePopupFactory treePopupFactory = ApplicationManager.getApplication().getService(NewRunConfigurationTreePopupFactory.class); treePopupFactory.initStructure(project); AbstractTreeStructure structure = new AbstractTreeStructure() { private final Map<NodeDescriptor<?>, NodeDescriptor<?>[]> myCache = new HashMap<>(); @Override public @NotNull Object getRootElement() { return treePopupFactory.getRootElement(); } @Override public NodeDescriptor<?> @NotNull [] getChildElements(@NotNull Object element) { NodeDescriptor<?> nodeDescriptor = (NodeDescriptor<?>)element; if (!myCache.containsKey(nodeDescriptor)) { myCache.put(nodeDescriptor, treePopupFactory.createChildElements(project, nodeDescriptor)); } return myCache.get(nodeDescriptor); } @Override public @Nullable Object getParentElement(@NotNull Object element) { return ((NodeDescriptor<?>)element).getParentDescriptor(); } @Override public @NotNull NodeDescriptor<?> createDescriptor(@NotNull Object element, @Nullable NodeDescriptor parentDescriptor) { return treePopupFactory.createDescriptor(project, element, parentDescriptor, NodeDescriptor.DEFAULT_WEIGHT); } @Override public void commit() { } @Override public boolean hasSomethingToCommit() { return false; } }; final AtomicBoolean isAutoSelectionPassed = new AtomicBoolean(selectedConfigurationType == null); BaseTreePopupStep<Object> treePopupStep = new BaseTreePopupStep<>( project, showTitle ? ExecutionBundle.message("add.new.run.configuration.action2.name") : null, structure ) { @Override public boolean isSelectable(Object node, Object userData) { if (!(userData instanceof NodeDescriptor)) return false; if (getStructure().getChildElements(userData).length > 0) return false; userData = ((NodeDescriptor<?>)userData).getElement(); if (!project.isDefault() && DumbService.getInstance(project).isDumb() && !NewRunConfigurationTreePopupFactory.isEditableInDumbMode(userData)) { return false; } return isAutoSelectionPassed.get() || userData == selectedConfigurationType; } @Override public PopupStep<?> onChosen(Object selectedValue, boolean finalChoice) { Object element = ((NodeDescriptor<?>)selectedValue).getElement(); if (element instanceof ConfigurationType) { ConfigurationFactory[] factories = ((ConfigurationType)element).getConfigurationFactories(); if (factories.length == 1) { creator.consume(factories[0]); return FINAL_CHOICE; } } if (element instanceof ConfigurationFactory) { creator.consume((ConfigurationFactory)element); return FINAL_CHOICE; } return super.onChosen(selectedValue, finalChoice); } }; TreePopupImpl treePopup = new TreePopupImpl(project, null, treePopupStep, null) { @Override protected void afterShow() { super.afterShow(); isAutoSelectionPassed.set(true); scrollToSelection(); } @Override public boolean shouldBeShowing(Object value) { NodeDescriptor<?> parent = (value instanceof NodeDescriptor) ? ((NodeDescriptor<?>)value).getParentDescriptor() : null; return super.shouldBeShowing(value) || (parent != null && super.shouldBeShowing(parent)); } }; DumbAwareAction collapseAllAction = new DumbAwareAction(UIBundle.message("tree.view.collapse.all.action.name"), null, AllIcons.Actions.Collapseall) { @Override public void actionPerformed(@NotNull AnActionEvent e) { treePopup.collapseAll(); } }; ActionToolbarImpl toolbar = (ActionToolbarImpl)ActionManager.getInstance() .createActionToolbar(ActionPlaces.POPUP, new DefaultActionGroup(collapseAllAction), true); toolbar.setTargetComponent(treePopup.getComponent()); toolbar.setMiniMode(true); var toolbarInsets = JBUI.CurrentTheme.Popup.headerInsets(); if (toolbarInsets instanceof JBInsets scaledInsets) { toolbarInsets = scaledInsets.getUnscaled(); // JBUI.Borders.empty() will scale, need this to avoid double scaling } JBEmptyBorder toolbarBorder = ExperimentalUI.isNewUI() ? JBUI.Borders.empty(toolbarInsets.top, 1, toolbarInsets.bottom, 1) : JBUI.Borders.empty(2, 1, 0, 1); treePopup.getTitle().setButtonComponent(new ActiveComponent() { @Override public void setActive(boolean active) { } @Override public @NotNull JComponent getComponent() { return toolbar.getComponent(); } }, toolbarBorder); return treePopup; }