diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd89fd90..ab025708 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+- Added a setting to control whether the choice menu grabs keyboard focus (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/20)
- Added a global setting to choose the default dock position of the Claude Code session tab (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/24)
# 0.21.50 (2026-04-19)
diff --git a/pom.xml b/pom.xml
index a40b692c..fdd7e86e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.nbclaudecodegui
netbeans-claude-code-gui
- 0.22.6-SNAPSHOT
+ 0.22.7-SNAPSHOT
nbm
Netbeans Claude Code GUI
NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.
diff --git a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java
index 6806966a..320e5744 100644
--- a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java
+++ b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java
@@ -40,6 +40,15 @@
*/
public final class ClaudeCodeOptionsPanel extends JPanel {
+ private static final String[] CHOICE_MENU_FOCUS_VALUES = {
+ ClaudeCodePreferences.CHOICE_MENU_GRAB_FOCUS,
+ ClaudeCodePreferences.CHOICE_MENU_SHOW_NO_FOCUS,
+ ClaudeCodePreferences.CHOICE_MENU_HIDE_MENU
+ };
+ private static final String[] CHOICE_MENU_FOCUS_LABELS = {
+ "Grab focus (default)", "Show without grabbing focus", "Hide menu"
+ };
+
private static final String[] DOCK_MODE_VALUES = {
"editor", "commonpalette", "explorer", "navigator", "output"
};
@@ -77,6 +86,8 @@ public final class ClaudeCodeOptionsPanel extends JPanel {
private JSpinner sessionListLimitSpinner;
/** Dropdown for the dock position of the Claude Code session tab. */
private javax.swing.JComboBox dockModeCombo;
+ /** Dropdown for the choice menu focus behavior. */
+ private javax.swing.JComboBox choiceMenuFocusCombo;
/** Spinner for the hang-detection timeout in seconds (0 = disabled). */
private JSpinner hangTimeoutSpinner;
/** Checkbox to enable MCP integration (pass --mcp-config flag). */
@@ -238,6 +249,13 @@ private JPanel buildGeneralPanel() {
form.add(dockModeCombo, gbc(1, row, false));
row++;
+ // --- choice menu focus mode ---
+ form.add(new JLabel("Choice menu focus:"), gbc(0, row, false));
+ choiceMenuFocusCombo = new javax.swing.JComboBox<>(CHOICE_MENU_FOCUS_LABELS);
+ choiceMenuFocusCombo.setToolTipText("Controls whether the choice menu grabs keyboard focus when it appears");
+ form.add(choiceMenuFocusCombo, gbc(1, row, false));
+ row++;
+
// spacer
GridBagConstraints spacer = new GridBagConstraints();
spacer.gridx = 0; spacer.gridy = row;
@@ -376,6 +394,9 @@ void load() {
String dockMode = ClaudeCodePreferences.getSessionDockMode();
int dockIdx = java.util.Arrays.asList(DOCK_MODE_VALUES).indexOf(dockMode);
dockModeCombo.setSelectedIndex(dockIdx >= 0 ? dockIdx : 0);
+ String focusMode = ClaudeCodePreferences.getChoiceMenuFocusMode();
+ int focusIdx = java.util.Arrays.asList(CHOICE_MENU_FOCUS_VALUES).indexOf(focusMode);
+ choiceMenuFocusCombo.setSelectedIndex(focusIdx >= 0 ? focusIdx : 0);
hangTimeoutSpinner.setValue(ClaudeCodePreferences.getHangTimeoutSeconds());
mcpEnabledCheckBox.setSelected(ClaudeCodePreferences.isMcpEnabled());
@@ -415,6 +436,11 @@ void store() {
dockSel >= 0 && dockSel < DOCK_MODE_VALUES.length
? DOCK_MODE_VALUES[dockSel]
: ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE);
+ int focusSel = choiceMenuFocusCombo.getSelectedIndex();
+ ClaudeCodePreferences.setChoiceMenuFocusMode(
+ focusSel >= 0 && focusSel < CHOICE_MENU_FOCUS_VALUES.length
+ ? CHOICE_MENU_FOCUS_VALUES[focusSel]
+ : ClaudeCodePreferences.DEFAULT_CHOICE_MENU_FOCUS_MODE);
ClaudeCodePreferences.setHangTimeoutSeconds((Integer) hangTimeoutSpinner.getValue());
ClaudeCodePreferences.setMcpEnabled(mcpEnabledCheckBox.isSelected());
ClaudeCodePreferences.setSendKey(selectedValue(sendRadios));
diff --git a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java
index beb0ae05..314350f5 100644
--- a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java
+++ b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java
@@ -570,6 +570,31 @@ public static void setSessionDockMode(String mode) {
.put(KEY_SESSION_DOCK_MODE, mode != null ? mode : DEFAULT_SESSION_DOCK_MODE);
}
+ // -------------------------------------------------------------------------
+ // choiceMenuFocusMode
+ // -------------------------------------------------------------------------
+
+ /** Preference key: focus behavior when the choice menu appears. */
+ public static final String KEY_CHOICE_MENU_FOCUS_MODE = "choiceMenuFocusMode";
+ /** Value: grab keyboard focus (current / default behavior). */
+ public static final String CHOICE_MENU_GRAB_FOCUS = "grab_focus";
+ /** Value: show the panel without grabbing keyboard focus. */
+ public static final String CHOICE_MENU_SHOW_NO_FOCUS = "show_no_focus";
+ /** Value: do not show the choice menu panel at all. */
+ public static final String CHOICE_MENU_HIDE_MENU = "hide_menu";
+ /** Default: grab focus. */
+ public static final String DEFAULT_CHOICE_MENU_FOCUS_MODE = CHOICE_MENU_GRAB_FOCUS;
+
+ public static String getChoiceMenuFocusMode() {
+ return NbPreferences.forModule(ClaudeCodePreferences.class)
+ .get(KEY_CHOICE_MENU_FOCUS_MODE, DEFAULT_CHOICE_MENU_FOCUS_MODE);
+ }
+
+ public static void setChoiceMenuFocusMode(String mode) {
+ NbPreferences.forModule(ClaudeCodePreferences.class)
+ .put(KEY_CHOICE_MENU_FOCUS_MODE, mode != null ? mode : DEFAULT_CHOICE_MENU_FOCUS_MODE);
+ }
+
private static String validated(String value, String fallback) {
return ENTER.equals(value) || SHIFT_ENTER.equals(value)
|| CTRL_ENTER.equals(value) || ALT_ENTER.equals(value)
diff --git a/src/main/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanel.java b/src/main/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanel.java
index e381d929..a782b8ea 100644
--- a/src/main/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanel.java
+++ b/src/main/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanel.java
@@ -62,7 +62,7 @@ public ChoiceMenuPanel(Supplier workingDirSupplier) {
* @param model the menu model
* @param callback invoked with the chosen response string, or {@code null} on Cancel
*/
- public void show(ChoiceMenuModel model, Consumer callback) {
+ public void show(ChoiceMenuModel model, Consumer callback, boolean grabFocus) {
this.callback = callback;
removeAll();
@@ -520,7 +520,7 @@ public void keyPressed(java.awt.event.KeyEvent e) {
} else {
focusTarget = sendBtn;
}
- if (focusTarget != null) {
+ if (grabFocus && focusTarget != null) {
javax.swing.SwingUtilities.invokeLater(focusTarget::requestFocusInWindow);
}
}
diff --git a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
index ddbec957..b23aed89 100644
--- a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
+++ b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
@@ -489,13 +489,18 @@ public void onChoiceMenuChanged(ChoiceMenuModel menu) {
if (menu != null) {
LOG.fine(sessionTag + "[onChoiceMenuChanged] showing menu: \"" + menu.text()
+ "\" EDT=" + SwingUtilities.isEventDispatchThread());
+ String focusMode = io.github.nbclaudecodegui.settings.ClaudeCodePreferences.getChoiceMenuFocusMode();
+ if (io.github.nbclaudecodegui.settings.ClaudeCodePreferences.CHOICE_MENU_HIDE_MENU.equals(focusMode)) {
+ return;
+ }
+ boolean grabFocus = io.github.nbclaudecodegui.settings.ClaudeCodePreferences.CHOICE_MENU_GRAB_FOCUS.equals(focusMode);
choiceMenuPanel.show(menu, answer -> {
LOG.fine(sessionTag + "[PTY prompt answer] " + answer);
SwingUtilities.invokeLater(() -> switchSouthCard(CARD_PROMPT));
revalidate();
repaint();
controller.writePtyAnswer(answer);
- });
+ }, grabFocus);
switchSouthCard(CARD_CHOICE);
} else {
if (CARD_CHOICE.equals(activeCard)) {
diff --git a/src/test/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanelTest.java b/src/test/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanelTest.java
index 3426534c..e6fc022e 100644
--- a/src/test/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanelTest.java
+++ b/src/test/java/io/github/nbclaudecodegui/ui/ChoiceMenuPanelTest.java
@@ -40,7 +40,7 @@ void testShowWithOptionsCreatesButtons() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Allow?",
List.of(new Option("Yes", "1"), new Option("No", "2")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertTrue(panel.getComponentCount() > 0, "panel should have components after show()");
@@ -58,7 +58,7 @@ void testYesButtonIsGreen() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Q?",
List.of(new Option("Yes", "1"), new Option("No", "2")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JButton btn = findButton(panel, UiUtils.ICON_CHECK + " Yes");
assertNotNull(btn, "Yes button must exist");
@@ -72,7 +72,7 @@ void testNoButtonIsRed() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Q?",
List.of(new Option("Yes", "1"), new Option("No", "2")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JButton btn = findButton(panel, UiUtils.ICON_CROSS + " No");
assertNotNull(btn, "No button must exist");
@@ -86,7 +86,7 @@ void testRadioButtonForNonYesNoOption() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Q?",
List.of(new Option("Maybe", "3")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JRadioButton rb = findRadioButton(panel, "Maybe");
assertNotNull(rb, "Non-Yes/No option should render as JRadioButton");
@@ -98,21 +98,21 @@ void testCancelAlwaysPresent() throws Exception {
// With Yes/No only
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {}, true);
assertNotNull(findButton(panel, "Cancel"), "Cancel must be present with Yes/No options");
});
// With radio options
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {}, true);
assertNotNull(findButton(panel, "Cancel"), "Cancel must be present with radio options");
});
// Free-form
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(), -1), a -> {}, true);
assertNotNull(findButton(panel, "Cancel"), "Cancel must be present for free-form input");
});
}
@@ -121,7 +121,7 @@ void testCancelAlwaysPresent() throws Exception {
void testSendAbsentWhenOnlyYesNo() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {}, true);
assertNull(findButton(panel, "Send"), "Send button must NOT be present when only Yes/No options");
});
}
@@ -131,7 +131,7 @@ void testSendPresentWhenOtherOptionsExist() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
panel.show(new ChoiceMenuModel("Q?",
- List.of(new Option("Yes", "1"), new Option("Maybe", "3")), -1), a -> {});
+ List.of(new Option("Yes", "1"), new Option("Maybe", "3")), -1), a -> {}, true);
assertNotNull(findButton(panel, "Send"), "Send button must be present when other options exist");
});
}
@@ -140,7 +140,7 @@ void testSendPresentWhenOtherOptionsExist() throws Exception {
void testSendDisabledUntilRadioSelected() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {}, true);
JButton send = findButton(panel, "Send");
assertNotNull(send, "Send must exist");
assertFalse(send.isEnabled(), "Send must be disabled when no radio is selected");
@@ -156,7 +156,7 @@ void testSendDisabledUntilRadioSelected() throws Exception {
void testSendEnabledWhenDefaultRadioSelected() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "1")), 0), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "1")), 0), a -> {}, true);
JButton send = findButton(panel, "Send");
assertNotNull(send, "Send must exist");
assertTrue(send.isEnabled(), "Send must be enabled when default radio is pre-selected");
@@ -167,7 +167,7 @@ void testSendEnabledWhenDefaultRadioSelected() throws Exception {
void testDefaultRadioSelected() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "1")), 0), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "1")), 0), a -> {}, true);
JRadioButton rb = findRadioButton(panel, "Maybe");
assertNotNull(rb, "JRadioButton for Maybe must exist");
assertTrue(rb.isSelected(), "Radio button for default option should be selected");
@@ -182,7 +182,7 @@ void testButtonClickInvokesCallbackWithResponse() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Allow?",
List.of(new Option("Yes", "1"), new Option("No", "2")), -1);
- panel.show(model, received::add);
+ panel.show(model, received::add, true);
JButton yesBtn = findButton(panel, UiUtils.ICON_CHECK + " Yes");
assertNotNull(yesBtn, "Yes button must exist");
@@ -198,7 +198,7 @@ void testHideAfterButtonClick() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Go?", List.of(new Option("Yes", "1")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JButton btn = findButton(panel, UiUtils.ICON_CHECK + " Yes");
assertNotNull(btn);
@@ -219,7 +219,7 @@ void testCancelInvokesCallbackWithNull() throws Exception {
panel.show(model, answer -> {
if (answer == null) nullReceived.add(true);
else received.add(answer);
- });
+ }, true);
JButton cancelBtn = findButton(panel, "Cancel");
assertNotNull(cancelBtn, "Cancel button must exist");
@@ -237,7 +237,7 @@ void testHideMethodHidesPanel() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1")), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertTrue(panel.getComponentCount() > 0, "panel should have components after show()");
panel.dismiss();
@@ -250,7 +250,7 @@ void testShowWithNoOptionsShowsSendAndCancelButtons() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Enter your response:", List.of(), -1);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertTrue(panel.getComponentCount() > 0, "panel should have components after show()");
List btnLabels = collectButtonLabels(panel);
@@ -263,7 +263,7 @@ void testShowWithNoOptionsShowsSendAndCancelButtons() throws Exception {
void testCancelAndSendAreInRightCol() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Maybe", "3")), -1), a -> {}, true);
JPanel rightCol = findPanelByName(panel, "rightCol");
assertNotNull(rightCol, "rightCol panel must exist");
@@ -276,7 +276,7 @@ void testCancelAndSendAreInRightCol() throws Exception {
void testCancelInRightColWhenOnlyYesNo() throws Exception {
SwingUtilities.invokeAndWait(() -> {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
- panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {});
+ panel.show(new ChoiceMenuModel("Q?", List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {}, true);
JPanel rightCol = findPanelByName(panel, "rightCol");
assertNotNull(rightCol, "rightCol panel must exist");
@@ -297,7 +297,7 @@ void dismissIfActiveFiresNullCallbackImmediately() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Do you want to proceed?",
List.of(new Option(" Yes", "1"), new Option(" No", "3")), 0);
- panel.show(model, answer -> received.add(String.valueOf(answer)));
+ panel.show(model, answer -> received.add(String.valueOf(answer)), true);
assertTrue(panel.getComponentCount() > 0, "panel must have components after show()");
assertTrue(received.isEmpty(), "callback must not fire before user action");
@@ -322,7 +322,7 @@ void testTypeInputOptionRendersTextField() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Option A", "1"),
new Option("Type something.", "2")), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JTextField tf = findTextField(panel);
assertNotNull(tf, "panel must contain a JTextField for 'Type something.' option");
@@ -336,7 +336,7 @@ void testTypeInputFieldDisabledByDefault() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Option A", "1"),
new Option("Type something.", "2")), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JTextField tf = findTextField(panel);
assertNotNull(tf);
@@ -352,7 +352,7 @@ void testTypeInputFieldEnabledWhenRadioSelected() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Option A", "1"),
new Option("Type something.", "2")), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
JRadioButton typeRb = findRadioButtonByName(panel, "typeInputRb");
assertNotNull(typeRb, "type-input radio button must exist");
@@ -375,7 +375,7 @@ void testTypeInputOptionCallbackIncludesOptionNumber() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Option A", "1"),
new Option("Type something.", "2")), 0);
- panel.show(model, captured::add);
+ panel.show(model, captured::add, true);
JRadioButton typeRb = findRadioButtonByName(panel, "typeInputRb");
assertNotNull(typeRb, "type-input radio button must exist with name 'typeInputRb'");
@@ -406,7 +406,7 @@ void testTypeInputOptionLayoutIsHorizontal() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Option A", "1"),
new Option("Type something.", "2")), 0);
- panel.show(model, s -> {});
+ panel.show(model, s -> {}, true);
JPanel typeInputRow = findPanelByName(panel, "typeInputRow");
assertNotNull(typeInputRow, "typeInputRow panel must exist");
@@ -427,7 +427,7 @@ void testFocusTraversalOrderRadiosThenSendCancel() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose?",
List.of(new Option("Option A", "1"),
new Option("Option B", "2")), 0);
- panel.show(model, s -> {});
+ panel.show(model, s -> {}, true);
java.awt.FocusTraversalPolicy ftp = panel.getFocusTraversalPolicy();
assertNotNull(ftp, "panel must have an explicit FocusTraversalPolicy");
@@ -454,7 +454,7 @@ void testCheckboxOptionRendersAsJCheckBox() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose releases:",
List.of(new Option("Release A", "1", null, false, true),
new Option("Release B", "2", null, false, true)), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertNotNull(findCheckBox(panel, "Release A"), "hasCheckbox=true option must render as JCheckBox");
assertNotNull(findCheckBox(panel, "Release B"), "hasCheckbox=true option must render as JCheckBox");
@@ -469,7 +469,7 @@ void testNonCheckboxOptionInMixedMenuRendersAsRadio() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Release A", "1", null, false, true),
new Option("Chat about this", "2")), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertNotNull(findCheckBox(panel, "Release A"), "hasCheckbox=true must be JCheckBox");
assertNotNull(findRadioButton(panel, "Chat about this"), "hasCheckbox=false must be JRadioButton");
@@ -482,7 +482,7 @@ void testCheckboxMenuHasSubmitButton() throws Exception {
ChoiceMenuPanel panel = new ChoiceMenuPanel(() -> null);
ChoiceMenuModel model = new ChoiceMenuModel("Choose releases:",
List.of(new Option("Release A", "1", null, false, true)), 0);
- panel.show(model, answer -> {});
+ panel.show(model, answer -> {}, true);
assertNotNull(findButton(panel, "Submit"), "must have Submit button when checkbox options exist");
assertNull(findButton(panel, "Send"), "must NOT have Send button when checkbox options exist");
@@ -497,7 +497,7 @@ void testSubmitButtonSendsMultiResponse() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose releases:",
List.of(new Option("Release A", "1", null, false, true),
new Option("Release B", "2", null, false, true)), 0);
- panel.show(model, captured::add);
+ panel.show(model, captured::add, true);
JCheckBox cb = findCheckBox(panel, "Release A");
assertNotNull(cb);
@@ -520,7 +520,7 @@ void testRadioInMixedMenuSendsDirectResponse() throws Exception {
ChoiceMenuModel model = new ChoiceMenuModel("Choose:",
List.of(new Option("Release A", "1", null, false, true),
new Option("Chat about this", "6")), 0);
- panel.show(model, captured::add);
+ panel.show(model, captured::add, true);
JRadioButton rb = findRadioButton(panel, "Chat about this");
assertNotNull(rb, "Chat about this must be a radio button");
@@ -553,7 +553,7 @@ void preferredHeightIsZeroBeforeShowCausesInvisiblePanel() throws Exception {
int heightBefore = panel.getPreferredSize().height;
panel.show(new ChoiceMenuModel("Allow?",
- List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {});
+ List.of(new Option("Yes", "1"), new Option("No", "2")), -1), a -> {}, true);
int heightAfter = panel.getPreferredSize().height;
@@ -607,7 +607,7 @@ void preferredHeightAfterSplitPaneValidateCoversAllContent() throws Exception {
List.of(new Option("Yes", "1"),
new Option("Yes, and allow Claude to edit its own settings for this session", "2"),
new Option("No", "3")), -1),
- answer -> {});
+ answer -> {}, true);
cardLayout.show(southCard, "choice");
// Simulate lockDividerForChoiceMenu WITH validate() (the fix)
@@ -670,7 +670,7 @@ void splitPaneRemainsEnabledWhenChoiceMenuShown() throws Exception {
try {
choiceMenuPanel.show(new ChoiceMenuModel("Continue?",
List.of(new Option("Yes", "1"), new Option("No", "2")), -1),
- answer -> {});
+ answer -> {}, true);
cardLayout.show(southCard, "choice");
// Simulate the production switchSouthCard(CARD_CHOICE) path: