JComponent () { myTreeController = new BreakpointItemsTreeController(myRulesEnabled) { @Override public void nodeStateWillChangeImpl(CheckedTreeNode node) { if (node instanceof BreakpointItemNode) { ((BreakpointItemNode)node).getBreakpointItem().saveState(); } super.nodeStateWillChangeImpl(node); } @Override public void nodeStateDidChangeImpl(CheckedTreeNode node) { super.nodeStateDidChangeImpl(node); if (node instanceof BreakpointItemNode) { myDetailController.doUpdateDetailView(true); } } @Override protected void selectionChangedImpl() { super.selectionChangedImpl(); saveCurrentItem(); myDetailController.updateDetailView(); } }; BreakpointsCheckboxTree tree = new BreakpointsCheckboxTree(myProject, myTreeController) { @Override protected void onDoubleClick(CheckedTreeNode node) { if (node instanceof BreakpointsGroupNode) { TreePath path = TreeUtil.getPathFromRoot(node); if (isExpanded(path)) { collapsePath(path); } else { expandPath(path); } } else { navigate(false); } } }; tree.setHorizontalAutoScrollingEnabled(false); PopupHandler.installPopupMenu(tree, new ActionGroup() { @Override public AnAction @NotNull [] getChildren(@Nullable AnActionEvent e) { ActionGroup group = new ActionGroup(XDebuggerBundle.message("move.to.group"), true) { @Override public AnAction @NotNull [] getChildren(@Nullable AnActionEvent e) { Set<String> groups = getBreakpointManager().getAllGroups(); AnAction[] res = new AnAction[groups.size() + 3]; int i = 0; res[i++] = new MoveToGroupAction(null); for (@NlsSafe String group : groups) { res[i++] = new MoveToGroupAction(group); } res[i++] = new Separator(); res[i] = new MoveToGroupAction(); return res; } }; List<AnAction> res = new ArrayList<>(); res.add(group); Object component = tree.getLastSelectedPathComponent(); if (tree.getSelectionCount() == 1 && component instanceof BreakpointsGroupNode && ((BreakpointsGroupNode<?>)component).getGroup() instanceof XBreakpointCustomGroup) { res.add(new SetAsDefaultGroupAction((XBreakpointCustomGroup)((BreakpointsGroupNode<?>)component).getGroup())); } if (tree.getSelectionCount() == 1 && component instanceof BreakpointItemNode) { res.add(new EditDescriptionAction((XBreakpointBase)((BreakpointItemNode)component).getBreakpointItem().getBreakpoint())); } return res.toArray(AnAction.EMPTY_ARRAY); } }, "BreakpointTreePopup"); new AnAction(XDebuggerBundle.messagePointer("action.Anonymous.text.breakpointdialog.gotosource")) { @Override public void actionPerformed(@NotNull AnActionEvent e) { navigate(true); close(OK_EXIT_CODE); } }.registerCustomShortcutSet(CommonShortcuts.ENTER, tree, myDisposable); new AnAction(XDebuggerBundle.messagePointer("action.Anonymous.text.breakpointdialog.showsource")) { @Override public void actionPerformed(@NotNull AnActionEvent e) { navigate(true); close(OK_EXIT_CODE); } }.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), tree, myDisposable); DefaultActionGroup breakpointTypes = XBreakpointUtil.breakpointTypes() .filter(XBreakpointType::isAddBreakpointButtonVisible) .map(AddXBreakpointAction::new) .toListAndThen(DefaultActionGroup::new); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(tree). setToolbarPosition(ActionToolbarPosition.TOP). setPanelBorder(JBUI.Borders.empty()). setAddAction(button -> JBPopupFactory.getInstance() .createActionGroupPopup(null, breakpointTypes, DataManager.getInstance().getDataContext(button.getContextComponent()), JBPopupFactory.ActionSelectionAid.NUMBERING, false) .show(button.getPreferredPopupPoint())). setRemoveAction(button -> myTreeController.removeSelectedBreakpoints(myProject)). setRemoveActionUpdater(e -> { for (BreakpointItem item : myTreeController.getSelectedBreakpoints(true)) { if (item.allowedToRemove()) { return true; } } return false; }); myToggleRuleActions.forEach(decorator::addExtraAction); JPanel decoratorPanel = decorator.createPanel(); myTreeController.setTreeView(tree); myTreeController.buildTree(myBreakpointItems); initSelection(myBreakpointItems); myBreakpointsPanelProviders.forEach(provider -> provider.addListener(myRebuildAlarm::cancelAndRequest, myProject, myListenerDisposable)); return decoratorPanel; }