From e38d670e95c23dee12ea0810c2ef589ed25f6c07 Mon Sep 17 00:00:00 2001 From: Oleg Samarin Date: Mon, 20 Apr 2026 17:27:25 +0300 Subject: [PATCH] Added a global setting to choose the default dock position of the Claude Code session tab (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/24) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves: #24 Added KEY_SESSION_DOCK_MODE preference to ClaudeCodePreferences with "editor" as default. Added "Session tab dock position" dropdown to the General tab in Tools → Options → Claude Code, with options: Editor area, Right side, Left side top, Left side bottom, Bottom dock. Applied via WindowManager.findMode().dockInto() before tab.open() in openNewOrFocus() and openForDirectory() for newly created tabs only. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 5 +++- pom.xml | 2 +- .../settings/ClaudeCodeOptionsPanel.java | 24 +++++++++++++++++++ .../settings/ClaudeCodePreferences.java | 19 +++++++++++++++ .../nbclaudecodegui/ui/ClaudeSessionTab.java | 15 ++++++++++-- .../settings/ClaudeCodePreferencesTest.java | 21 ++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e80f6088..cd89fd90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ +- 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) + - Fixed diff panel appearing at wrong height (nearly invisible) after Reset Windows or on first use -- Fixed second diff in the same Claude session being invisible (stale card accumulation) - Fixed terminal scrolling to the beginning when a choice menu or diff panel appears (regression since 0.20.20) # 0.21.46 (2026-04-17) diff --git a/pom.xml b/pom.xml index 8df8b29b..a40b692c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.nbclaudecodegui netbeans-claude-code-gui - 0.22.3-SNAPSHOT + 0.22.6-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 86d62941..6806966a 100644 --- a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java +++ b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodeOptionsPanel.java @@ -40,6 +40,13 @@ */ public final class ClaudeCodeOptionsPanel extends JPanel { + private static final String[] DOCK_MODE_VALUES = { + "editor", "commonpalette", "explorer", "navigator", "output" + }; + private static final String[] DOCK_MODE_LABELS = { + "Editor area (default)", "Right side", "Left side top", "Left side bottom", "Bottom dock" + }; + private static final String[] KEY_VALUES = { ClaudeCodePreferences.ENTER, ClaudeCodePreferences.SHIFT_ENTER, @@ -68,6 +75,8 @@ public final class ClaudeCodeOptionsPanel extends JPanel { private javax.swing.JCheckBox startNewSessionCheck; /** Spinner for the maximum number of sessions shown in the session list. */ private JSpinner sessionListLimitSpinner; + /** Dropdown for the dock position of the Claude Code session tab. */ + private javax.swing.JComboBox dockModeCombo; /** Spinner for the hang-detection timeout in seconds (0 = disabled). */ private JSpinner hangTimeoutSpinner; /** Checkbox to enable MCP integration (pass --mcp-config flag). */ @@ -222,6 +231,13 @@ private JPanel buildGeneralPanel() { form.add(sessionListLimitSpinner, gbc(1, row, false)); row++; + // --- session tab dock position --- + form.add(new JLabel("Session tab dock position:"), gbc(0, row, false)); + dockModeCombo = new javax.swing.JComboBox<>(DOCK_MODE_LABELS); + dockModeCombo.setToolTipText("Where to dock the Claude Code session tab when opening it"); + form.add(dockModeCombo, gbc(1, row, false)); + row++; + // spacer GridBagConstraints spacer = new GridBagConstraints(); spacer.gridx = 0; spacer.gridy = row; @@ -357,6 +373,9 @@ void load() { ClaudeCodePreferences.getContextMenuSessionMode() == io.github.nbclaudecodegui.model.SessionMode.NEW); sessionListLimitSpinner.setValue(ClaudeCodePreferences.getSessionListLimit()); + String dockMode = ClaudeCodePreferences.getSessionDockMode(); + int dockIdx = java.util.Arrays.asList(DOCK_MODE_VALUES).indexOf(dockMode); + dockModeCombo.setSelectedIndex(dockIdx >= 0 ? dockIdx : 0); hangTimeoutSpinner.setValue(ClaudeCodePreferences.getHangTimeoutSeconds()); mcpEnabledCheckBox.setSelected(ClaudeCodePreferences.isMcpEnabled()); @@ -391,6 +410,11 @@ void store() { ? io.github.nbclaudecodegui.model.SessionMode.NEW : io.github.nbclaudecodegui.model.SessionMode.CONTINUE_LAST); ClaudeCodePreferences.setSessionListLimit((Integer) sessionListLimitSpinner.getValue()); + int dockSel = dockModeCombo.getSelectedIndex(); + ClaudeCodePreferences.setSessionDockMode( + dockSel >= 0 && dockSel < DOCK_MODE_VALUES.length + ? DOCK_MODE_VALUES[dockSel] + : ClaudeCodePreferences.DEFAULT_SESSION_DOCK_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 80f01caf..beb0ae05 100644 --- a/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java +++ b/src/main/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferences.java @@ -551,6 +551,25 @@ public static void setMcpEnabled(boolean v) { NbPreferences.forModule(ClaudeCodePreferences.class).putBoolean(MCP_ENABLED, v); } + // ------------------------------------------------------------------------- + // sessionDockMode + // ------------------------------------------------------------------------- + + /** Preference key: dock mode for the Claude Code session tab. */ + public static final String KEY_SESSION_DOCK_MODE = "sessionDockMode"; + /** Default: editor area. */ + public static final String DEFAULT_SESSION_DOCK_MODE = "editor"; + + public static String getSessionDockMode() { + return NbPreferences.forModule(ClaudeCodePreferences.class) + .get(KEY_SESSION_DOCK_MODE, DEFAULT_SESSION_DOCK_MODE); + } + + public static void setSessionDockMode(String mode) { + NbPreferences.forModule(ClaudeCodePreferences.class) + .put(KEY_SESSION_DOCK_MODE, mode != null ? mode : DEFAULT_SESSION_DOCK_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/ClaudeSessionTab.java b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java index 02b3b0a8..ddbec957 100644 --- a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java +++ b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java @@ -294,6 +294,17 @@ public ClaudeSessionTab(File dir) { * *

Focuses an existing idle session if one is open; otherwise opens a new one. */ + private static void dockAndOpen(ClaudeSessionTab tab) { + String modeName = ClaudeCodePreferences.getSessionDockMode(); + if (!ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE.equals(modeName)) { + org.openide.windows.Mode mode = WindowManager.getDefault().findMode(modeName); + if (mode != null) { + mode.dockInto(tab); + } + } + tab.open(); + } + public static void openNewOrFocus() { SwingUtilities.invokeLater(() -> { for (TopComponent tc : WindowManager.getDefault().getRegistry().getOpened()) { @@ -310,7 +321,7 @@ public static void openNewOrFocus() { } LOG.fine("openNewOrFocus: no idle tab found, opening new tab"); ClaudeSessionTab tab = new ClaudeSessionTab(); - tab.open(); + dockAndOpen(tab); tab.requestActive(); }); } @@ -342,7 +353,7 @@ public static void openForDirectory(File dir, String profileName) { } } ClaudeSessionTab tab = new ClaudeSessionTab(dir); - tab.open(); + dockAndOpen(tab); tab.requestActive(); tab.autoStart(dir, profileName); }); diff --git a/src/test/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferencesTest.java b/src/test/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferencesTest.java index a1b6e5e9..1a2a4d92 100644 --- a/src/test/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferencesTest.java +++ b/src/test/java/io/github/nbclaudecodegui/settings/ClaudeCodePreferencesTest.java @@ -17,6 +17,7 @@ void tearDown() { ClaudeCodePreferences.setMcpPort(ClaudeCodePreferences.DEFAULT_MCP_PORT); ClaudeCodePreferences.setOpenDiffInSeparateTab(ClaudeCodePreferences.DEFAULT_OPEN_DIFF_IN_SEPARATE_TAB); ClaudeCodePreferences.setMdPreviewInDiff(ClaudeCodePreferences.DEFAULT_MD_PREVIEW_IN_DIFF); + ClaudeCodePreferences.setSessionDockMode(ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE); } @Test @@ -97,4 +98,24 @@ void mdPreviewInDiffStoreAndRetrieve() { ClaudeCodePreferences.setMdPreviewInDiff(false); assertFalse(ClaudeCodePreferences.isMdPreviewInDiff()); } + + @Test + void sessionDockModeDefaultIsEditor() { + assertEquals(ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE, + ClaudeCodePreferences.getSessionDockMode()); + assertEquals("editor", ClaudeCodePreferences.getSessionDockMode()); + } + + @Test + void sessionDockModeStoreAndRetrieve() { + ClaudeCodePreferences.setSessionDockMode("output"); + assertEquals("output", ClaudeCodePreferences.getSessionDockMode()); + } + + @Test + void sessionDockModeNullFallsBackToDefault() { + ClaudeCodePreferences.setSessionDockMode(null); + assertEquals(ClaudeCodePreferences.DEFAULT_SESSION_DOCK_MODE, + ClaudeCodePreferences.getSessionDockMode()); + } }