From 59b8f93061b373fc61eb112de68e9596b634a260 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Sun, 7 Sep 2025 11:46:08 -0600 Subject: [PATCH 01/14] Add sidebar preferences and toggle command - Introduced new user preferences for sidebar visibility and location in UserPrefValues.hpp and user-prefs-schema.json. - Added toggleSidebar command with corresponding labels in English and French in CmdConstants files. - Updated Commands.cmd.xml to include the toggleSidebar command in the View menu. - Enhanced UserPrefsAccessor to manage sidebar preferences. - Implemented a placeholder for toggleSidebar in DummyCommands for future functionality. --- .../include/session/prefs/UserPrefValues.hpp | 3 ++ .../resources/schema/user-prefs-schema.json | 28 +++++++++++++++++-- .../workbench/commands/CmdConstants.java | 6 ++++ .../commands/CmdConstants_en.properties | 4 +++ .../commands/CmdConstants_fr.properties | 4 +++ .../workbench/commands/Commands.cmd.xml | 5 ++++ .../workbench/commands/Commands.cmd.xml.MD5 | 2 +- .../client/workbench/commands/Commands.java | 1 + .../prefs/model/UserPrefsAccessor.java | 15 +++++++++- .../workbench/commands/DummyCommands.java | 5 ++++ 10 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/cpp/session/include/session/prefs/UserPrefValues.hpp b/src/cpp/session/include/session/prefs/UserPrefValues.hpp index 90f85d6a44e..2bff968b79e 100644 --- a/src/cpp/session/include/session/prefs/UserPrefValues.hpp +++ b/src/cpp/session/include/session/prefs/UserPrefValues.hpp @@ -78,9 +78,12 @@ namespace prefs { #define kPanesTabSet1 "tabSet1" #define kPanesTabSet2 "tabSet2" #define kPanesHiddenTabSet "hiddenTabSet" +#define kPanesSidebar "sidebar" #define kPanesConsoleLeftOnTop "console_left_on_top" #define kPanesConsoleRightOnTop "console_right_on_top" #define kPanesAdditionalSourceColumns "additional_source_columns" +#define kPanesSidebarVisible "sidebar_visible" +#define kPanesSidebarLocation "sidebar_location" #define kAllowSourceColumns "allow_source_columns" #define kUseSpacesForTab "use_spaces_for_tab" #define kNumSpacesForTab "num_spaces_for_tab" diff --git a/src/cpp/session/resources/schema/user-prefs-schema.json b/src/cpp/session/resources/schema/user-prefs-schema.json index 9916d232423..ff61d3f11f6 100644 --- a/src/cpp/session/resources/schema/user-prefs-schema.json +++ b/src/cpp/session/resources/schema/user-prefs-schema.json @@ -162,7 +162,7 @@ "description": "Allocation of panes to quadrants.", "items": { "type": "string", - "enum": ["Source", "Console", "TabSet1", "TabSet2", "HiddenTabSet"] + "enum": ["Source", "Console", "TabSet1", "TabSet2", "HiddenTabSet", "Sidebar"] } }, "tabSet1": { @@ -186,6 +186,13 @@ "type": "string" } }, + "sidebar": { + "type": "array", + "description": "The panes included in the sidebar.", + "items": { + "type": "string" + } + }, "console_left_on_top": { "type": "boolean", "description": "Whether the console is on top when it is on the left side of the workbench." @@ -198,6 +205,17 @@ "type": "integer", "default": 0, "description": "The number of columns of full source columns." + }, + "sidebar_visible": { + "type": "boolean", + "default": false, + "description": "Whether the sidebar is visible." + }, + "sidebar_location": { + "type": "string", + "enum": ["left", "right", "satellite"], + "default": "right", + "description": "The location of the sidebar." } }, "default": { @@ -206,13 +224,17 @@ "Console", "TabSet1", "TabSet2", - "HiddenTabSet"], + "HiddenTabSet", + "Sidebar"], "tabSet1": ["Environment", "History", "Connections", "Build", "VCS", "Tutorial", "Presentation"], "tabSet2": ["Files", "Plots", "Packages", "Help", "Viewer", "Presentations"], "hiddenTabSet": [], + "sidebar": [], "console_left_on_top": false, "console_right_on_top": true, - "additional_source_columns": 0 + "additional_source_columns": 0, + "sidebar_visible": false, + "sidebar_location": "right" }, "description": "Layout of panes in the RStudio workbench." }, diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java index 9f4dab36f96..f9022c1bb8a 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java @@ -536,6 +536,12 @@ public interface CmdConstants extends Constants { @DefaultStringValue("") // $NON-NLS-1$ String projectSweaveOptionsDesc(); + // toggleSidebar + @DefaultStringValue("Toggle Visibility of Sidebar") // $NON-NLS-1$ + String toggleSidebarLabel(); + @DefaultStringValue("To_ggle Sidebar") // $NON-NLS-1$ + String toggleSidebarMenuLabel(); + // showToolbar @DefaultStringValue("Show _Toolbar") // $NON-NLS-1$ String showToolbarMenuLabel(); diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties index 1d629915dda..7502d10c753 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties @@ -350,6 +350,10 @@ projectSweaveOptionsButtonLabel = projectSweaveOptionsMenuLabel = projectSweaveOptionsDesc = +# toggleSidebar +toggleSidebarLabel = Toggle Visibility of Sidebar +toggleSidebarMenuLabel = To_ggle Sidebar + # showToolbar showToolbarMenuLabel = Show _Toolbar diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties index 0f0d4b2acba..356b5de23b7 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties @@ -350,6 +350,10 @@ projectSweaveOptionsButtonLabel = projectSweaveOptionsMenuLabel = projectSweaveOptionsDesc = +# toggleSidebar +toggleSidebarLabel = Basculer la visibilité de la barre latérale +toggleSidebarMenuLabel = Basculer la barre latérale + # showToolbar showToolbarMenuLabel = Afficher la barre d\u0027ou_tils diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml index 7b14251545c..cd20a399087 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml @@ -280,6 +280,7 @@ See `/src/gwt/tools/i18n-helpers/README.md`. + @@ -1373,6 +1374,10 @@ See `/src/gwt/tools/i18n-helpers/README.md`. buttonLabel="" desc=""/> + + diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 index 557a4400644..0f39d8fc7ab 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 @@ -1 +1 @@ -4b58c8a119104c4b6f014c5c2f96b35a +7f198e283117f4514eadb5e77e53f2b0 diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java index 1261a5aedfb..c30f8e219e4 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java @@ -355,6 +355,7 @@ // View public abstract AppCommand showToolbar(); public abstract AppCommand hideToolbar(); + public abstract AppCommand toggleSidebar(); public abstract AppCommand toggleToolbar(); public abstract AppCommand zoomActualSize(); public abstract AppCommand zoomIn(); diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java index 026be3afb5e..71e81cef5ba 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java @@ -389,9 +389,10 @@ protected Panes() {} public final static String QUADRANTS_TABSET1 = "TabSet1"; public final static String QUADRANTS_TABSET2 = "TabSet2"; public final static String QUADRANTS_HIDDENTABSET = "HiddenTabSet"; + public final static String QUADRANTS_SIDEBAR = "Sidebar"; public final native JsArrayString getQuadrants() /*-{ - return this && this.quadrants || ["Source","Console","TabSet1","TabSet2","HiddenTabSet"]; + return this && this.quadrants || ["Source","Console","TabSet1","TabSet2","HiddenTabSet","Sidebar"]; }-*/; public final native JsArrayString getTabSet1() /*-{ @@ -406,6 +407,10 @@ public final native JsArrayString getHiddenTabSet() /*-{ return this && this.hiddenTabSet || []; }-*/; + public final native JsArrayString getSidebar() /*-{ + return this && this.sidebar || []; + }-*/; + public final native boolean getConsoleLeftOnTop() /*-{ return this && this.console_left_on_top || false; }-*/; @@ -418,6 +423,14 @@ public final native int getAdditionalSourceColumns() /*-{ return this && this.additional_source_columns || 0; }-*/; + public final native boolean getSidebarVisible() /*-{ + return this && this.sidebar_visible || false; + }-*/; + + public final native String getSidebarLocation() /*-{ + return this && this.sidebar_location || "right"; + }-*/; + } /** diff --git a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java index 50c4bf07a17..0c13c64a3b4 100644 --- a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java +++ b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java @@ -1559,6 +1559,11 @@ public AppCommand hideToolbar() { return null; } + @Override + public AppCommand toggleSidebar() { + return null; + } + @Override public AppCommand toggleToolbar() { return null; From 22000368621af6e54aed45f66736e5e5f8514f92 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Mon, 8 Sep 2025 09:43:53 -0600 Subject: [PATCH 02/14] Add sidebar functionality to MainSplitPanel and PaneManager --- .../client/workbench/ui/MainSplitPanel.java | 70 +++++++++-- .../client/workbench/ui/PaneConfig.java | 43 ++++++- .../client/workbench/ui/PaneManager.java | 109 +++++++++++++++++- 3 files changed, 203 insertions(+), 19 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java index 4459e179531..35d57a16362 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java @@ -134,10 +134,16 @@ public MainSplitPanel(EventBus events, } public void initialize(ArrayList leftList, Widget center, Widget right) + { + initialize(leftList, center, right, null); + } + + public void initialize(ArrayList leftList, Widget center, Widget right, Widget sidebar) { leftList_ = leftList; center_ = center; right_ = right; + sidebar_ = sidebar; new JSObjectStateValue(GROUP_WORKBENCH, KEY_RIGHTPANESIZE, @@ -150,31 +156,42 @@ protected void onInit(JsObject value) { // If we already have a set state, with the correct number of columns use that State state = value == null ? null : (State)value.cast(); + int expectedCount = leftList_.size() + 1 + (sidebar_ != null ? 1 : 0); if (state != null && state.validate() && state.hasSplitterPos() && - state.getSplitterCount() == leftList_.size() + 1) + state.getSplitterCount() == expectedCount) { if (state.hasPanelWidth() && state.hasWindowWidth() && state.getWindowWidth() != Window.getClientWidth()) { int delta = state.getWindowWidth() - state.getPanelWidth(); int offsetWidth = Window.getClientWidth() - delta; - double pct = (double)state.getSplitterPos()[0] + int idx = 0; + if (sidebar_ != null) + { + double pct = (double)state.getSplitterPos()[idx++] + / state.getPanelWidth(); + addEast(sidebar_, pct * offsetWidth); + } + double pct = (double)state.getSplitterPos()[idx++] / state.getPanelWidth(); addEast(right_, pct * offsetWidth); for (int i = 0; i < leftList_.size(); i++) { - pct = (double)state.getSplitterPos()[i + 1] + pct = (double)state.getSplitterPos()[idx++] / state.getPanelWidth(); addWest(leftList_.get(i), pct * offsetWidth); } } else { - addEast(right_, state.getSplitterPos()[0]); + int idx = 0; + if (sidebar_ != null) + addEast(sidebar_, state.getSplitterPos()[idx++]); + addEast(right_, state.getSplitterPos()[idx++]); for (int i = 0; i < leftList_.size(); i++) - addWest(leftList_.get(i), state.getSplitterPos()[i + 1]); + addWest(leftList_.get(i), state.getSplitterPos()[idx++]); } } else @@ -182,6 +199,8 @@ protected void onInit(JsObject value) // When there are only two panels, make the left side slightly larger than the right, // otherwise divide the space equally. double splitWidth = getDefaultSplitterWidth(); + if (sidebar_ != null) + addEast(sidebar_, splitWidth * 0.8); // Sidebar slightly narrower addEast(right_, splitWidth); for (Widget w : leftList_) @@ -207,12 +226,16 @@ protected JsObject getValue() // The widget's code determines the splitter positions from the width of each widget // so these value represent that width rather than the actual coordinates of the // splitter. - int[] splitterArray = new int[leftList_.size() + 1]; - splitterArray[0] = right_.getOffsetWidth(); + int sidebarCount = sidebar_ != null ? 1 : 0; + int[] splitterArray = new int[leftList_.size() + 1 + sidebarCount]; + int idx = 0; + if (sidebar_ != null) + splitterArray[idx++] = sidebar_.getOffsetWidth(); + splitterArray[idx++] = right_.getOffsetWidth(); if (!leftList_.isEmpty()) { for (int i = 0; i < leftList_.size(); i++) - splitterArray[i + 1] = leftList_.get(i).getOffsetWidth(); + splitterArray[idx++] = leftList_.get(i).getOffsetWidth(); } state.setSplitterPos(splitterArray); return state.cast(); @@ -248,14 +271,15 @@ public void addLeftWidget(Widget widget) { clearForRefresh(); leftList_.add(0, widget); - initialize(leftList_, center_, right_); + initialize(leftList_, center_, right_, sidebar_); } public double getDefaultSplitterWidth() { - return leftList_.isEmpty() ? + int columnCount = 2 + leftList_.size() + (sidebar_ != null ? 1 : 0); + return leftList_.isEmpty() && sidebar_ == null ? Window.getClientWidth() * 0.45 : - Window.getClientWidth() / (2 + leftList_.size()); + Window.getClientWidth() / columnCount; } public double getLeftSize() @@ -278,7 +302,26 @@ public void removeLeftWidget(Widget widget) { clearForRefresh(); leftList_.remove(widget); - initialize(leftList_, center_, right_); + initialize(leftList_, center_, right_, sidebar_); + } + + public void setSidebarWidget(Widget widget) + { + clearForRefresh(); + sidebar_ = widget; + initialize(leftList_, center_, right_, sidebar_); + } + + public void removeSidebarWidget() + { + clearForRefresh(); + sidebar_ = null; + initialize(leftList_, center_, right_, null); + } + + public boolean hasSidebarWidget() + { + return sidebar_ != null; } public void onSplitterResized(SplitterResizedEvent event) @@ -298,6 +341,8 @@ private void clearForRefresh() { remove(center_); remove(right_); + if (sidebar_ != null) + remove(sidebar_); for (Widget w : leftList_) remove(w); } @@ -368,6 +413,7 @@ public void execute() { private ArrayList leftList_; private Widget center_; private Widget right_; + private Widget sidebar_; private static final String GROUP_WORKBENCH = "workbenchp"; private static final String KEY_RIGHTPANESIZE = "rightpanesize"; private Command layoutCommand_; diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneConfig.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneConfig.java index 51f8308aea7..5d55d3a1703 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneConfig.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneConfig.java @@ -44,7 +44,34 @@ public native static PaneConfig create(JsArrayString panes, hiddenTabSet: hiddenTabSet, console_left_on_top: consoleLeftOnTop, console_right_on_top: consoleRightOnTop, - additional_source_columns: additionalSources + additional_source_columns: additionalSources, + sidebar: [], + sidebar_visible: false, + sidebar_location: "right" + }; + }-*/; + + public native static PaneConfig create(JsArrayString panes, + JsArrayString tabSet1, + JsArrayString tabSet2, + JsArrayString hiddenTabSet, + boolean consoleLeftOnTop, + boolean consoleRightOnTop, + int additionalSources, + JsArrayString sidebarTabs, + boolean sidebarVisible, + String sidebarLocation) /*-{ + return { + quadrants: panes, + tabSet1: tabSet1, + tabSet2: tabSet2, + hiddenTabSet: hiddenTabSet, + console_left_on_top: consoleLeftOnTop, + console_right_on_top: consoleRightOnTop, + additional_source_columns: additionalSources, + sidebar: sidebarTabs, + sidebar_visible: sidebarVisible, + sidebar_location: sidebarLocation }; }-*/; @@ -91,7 +118,8 @@ public static String[] getAllPanes() UserPrefsAccessor.Panes.QUADRANTS_CONSOLE, UserPrefsAccessor.Panes.QUADRANTS_TABSET1, UserPrefsAccessor.Panes.QUADRANTS_TABSET2, - UserPrefsAccessor.Panes.QUADRANTS_HIDDENTABSET + UserPrefsAccessor.Panes.QUADRANTS_HIDDENTABSET, + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR }; } @@ -101,7 +129,8 @@ public static String[] getVisiblePanes() UserPrefsAccessor.Panes.QUADRANTS_SOURCE, UserPrefsAccessor.Panes.QUADRANTS_CONSOLE, UserPrefsAccessor.Panes.QUADRANTS_TABSET1, - UserPrefsAccessor.Panes.QUADRANTS_TABSET2 + UserPrefsAccessor.Panes.QUADRANTS_TABSET2, + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR }; } @@ -282,7 +311,10 @@ public final PaneConfig copy() copy(getHiddenTabSet()), getConsoleLeftOnTop(), getConsoleRightOnTop(), - getAdditionalSourceColumns()); + getAdditionalSourceColumns(), + copy(getSidebar()), + getSidebarVisible(), + getSidebarLocation()); } public final native boolean isEqualTo(PaneConfig other) /*-{ @@ -290,7 +322,8 @@ public final native boolean isEqualTo(PaneConfig other) /*-{ this.panes.toString() == other.panes.toString() && this.tabSet1.toString() == other.tabSet1.toString() && this.tabSet2.toString() == other.tabSet2.toString() && - this.hiddenTabSet.toString() == other.hiddenTabSet.toString(); + this.hiddenTabSet.toString() == other.hiddenTabSet.toString() && + this.sidebar.toString() == other.sidebar.toString(); }-*/; private boolean sameElements(JsArrayString a, String[] b) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index 18935c00ec0..74c2d09a25f 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -103,6 +103,7 @@ public enum Tab { public static final String LEFT_COLUMN = "left"; public static final String RIGHT_COLUMN = "right"; + public static final String SIDEBAR_COLUMN = "sidebar"; class SelectedTabStateValue extends IntStateValue { @@ -330,7 +331,28 @@ public PaneManager(Provider pSplitPanel, 0).cast()); } } - panel_.initialize(leftList_, center_, right_); + // Initialize sidebar if configured + Widget sidebarWidget = null; + if (config.getSidebarVisible() && sidebarTabPanel_ != null) + { + LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); + if (sidebarWindow != null) + { + // Create a simple panel for the sidebar (no vertical split for now) + sidebar_ = new DualWindowLayoutPanel( + eventBus_, + sidebarWindow, + new LogicalWindow(null, null), + session_, + SIDEBAR_COLUMN, + WindowState.NORMAL, + (int) (Window.getClientHeight() * 0.5), + 7); + sidebarWidget = sidebar_; + } + } + + panel_.initialize(leftList_, center_, right_, sidebarWidget); for (LogicalWindow window : sourceLogicalWindows_) { @@ -376,6 +398,7 @@ else if (numDocs > 0 && window.getState() == WindowState.HIDE) } source_.loadDisplay(); + userPrefs.panes().addValueChangeHandler(evt -> { ArrayList newPanes = createPanes( @@ -937,7 +960,72 @@ public void onPaneLayout() { optionsLoader_.showOptions(PaneLayoutPreferencesPane.class, true); } - + + @Handler + public void onToggleSidebar() + { + if (isSidebarVisible()) + hideSidebar(); + else + showSidebar(); + } + + public void showSidebar() + { + if (sidebar_ == null) + { + // Create sidebar configuration + PaneConfig config = userPrefs_.panes().getValue().cast(); + JsArrayString sidebarTabs = config.getSidebar(); + + // Create sidebar tabset + Triad sidebar = createTabSet( + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, + tabNamesToTabs(sidebarTabs)); + panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); + sidebarTabPanel_ = sidebar.second; + sidebarMinPanel_ = sidebar.third; + sidebarTabs_ = tabNamesToTabs(sidebarTabs); + + LogicalWindow sidebarWindow = sidebar.first; + if (sidebarWindow != null) + { + sidebar_ = new DualWindowLayoutPanel( + eventBus_, + sidebarWindow, + new LogicalWindow(null, null), + session_, + SIDEBAR_COLUMN, + WindowState.NORMAL, + (int) (Window.getClientHeight() * 0.5), + 7); + panel_.setSidebarWidget(sidebar_); + } + } + } + + public void hideSidebar() + { + if (sidebar_ != null) + { + panel_.removeSidebarWidget(); + sidebar_ = null; + } + } + + public boolean isSidebarVisible() + { + PaneConfig config = userPrefs_.panes().getValue().cast(); + return config.getSidebarVisible(); + // return sidebar_ != null && panel_.hasSidebarWidget(); + } + + public void setSidebarLocation(String location) + { + // This will be implemented to handle "left" vs "right" positioning + // For now, sidebar is always on the right + } + private boolean equals(T lhs, T rhs) { if (lhs == null) @@ -1016,6 +1104,8 @@ else if (sourceLogicalWindows_.contains(window)) DomUtils.contains(right_.getElement(), window.getActiveWidget().getElement()); boolean isCenterWidget = DomUtils.contains(center_.getElement(), window.getActiveWidget().getElement()); + boolean isSidebarWidget = sidebar_ != null && + DomUtils.contains(sidebar_.getElement(), window.getActiveWidget().getElement()); window.onWindowStateChange(new WindowStateChangeEvent(WindowState.EXCLUSIVE)); @@ -1299,6 +1389,17 @@ private void initPanes(PaneConfig config) hiddenTabSetTabPanel_ = tsHide.second; hiddenTabSetTabPanel_.setNeverVisible(true); hiddenTabSetMinPanel_ = tsHide.third; + + // Initialize sidebar if configured + if (config.getSidebarVisible()) + { + Triad sidebar = createTabSet( + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, + tabNamesToTabs(config.getSidebar())); + panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); + sidebarTabPanel_ = sidebar.second; + sidebarMinPanel_ = sidebar.third; + } } private ArrayList tabNamesToTabs(JsArrayString tabNames) @@ -2096,6 +2197,10 @@ private void clearFocusIndicator() private MinimizedModuleTabLayoutPanel tabSet2MinPanel_; private WorkbenchTabPanel hiddenTabSetTabPanel_; private MinimizedModuleTabLayoutPanel hiddenTabSetMinPanel_; + private WorkbenchTabPanel sidebarTabPanel_; + private MinimizedModuleTabLayoutPanel sidebarMinPanel_; + private DualWindowLayoutPanel sidebar_; + private ArrayList sidebarTabs_; // Zoom-related members ---- private Tab lastSelectedTab_ = null; From e12088575a689c7dfb151e657ea0d6f9b1007ef2 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Mon, 8 Sep 2025 10:23:38 -0600 Subject: [PATCH 03/14] fixes so pane will toggle on/off --- .../client/workbench/ui/PaneManager.java | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index 74c2d09a25f..195de95951b 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -338,17 +338,10 @@ public PaneManager(Provider pSplitPanel, LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); if (sidebarWindow != null) { - // Create a simple panel for the sidebar (no vertical split for now) - sidebar_ = new DualWindowLayoutPanel( - eventBus_, - sidebarWindow, - new LogicalWindow(null, null), - session_, - SIDEBAR_COLUMN, - WindowState.NORMAL, - (int) (Window.getClientHeight() * 0.5), - 7); - sidebarWidget = sidebar_; + // For sidebar, we use just the WindowFrame directly (no vertical split) + sidebarWindow.transitionToState(WindowState.NORMAL); + sidebarWidget = sidebarWindow.getNormal(); + sidebar_ = sidebarWidget; } } @@ -964,10 +957,28 @@ public void onPaneLayout() @Handler public void onToggleSidebar() { - if (isSidebarVisible()) - hideSidebar(); - else + // Toggle the preference value and update UI + PaneConfig paneConfig = userPrefs_.panes().getValue().cast(); + boolean newVisibility = !paneConfig.getSidebarVisible(); + + // Update the preference + userPrefs_.panes().setGlobalValue(PaneConfig.create( + JsArrayUtil.copy(paneConfig.getQuadrants()), + paneConfig.getTabSet1(), + paneConfig.getTabSet2(), + paneConfig.getHiddenTabSet(), + paneConfig.getConsoleLeftOnTop(), + paneConfig.getConsoleRightOnTop(), + paneConfig.getAdditionalSourceColumns(), + paneConfig.getSidebar(), + newVisibility, + paneConfig.getSidebarLocation())); + + // Update the UI + if (newVisibility) showSidebar(); + else + hideSidebar(); } public void showSidebar() @@ -978,27 +989,25 @@ public void showSidebar() PaneConfig config = userPrefs_.panes().getValue().cast(); JsArrayString sidebarTabs = config.getSidebar(); - // Create sidebar tabset - Triad sidebar = createTabSet( - UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, - tabNamesToTabs(sidebarTabs)); - panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); - sidebarTabPanel_ = sidebar.second; - sidebarMinPanel_ = sidebar.third; - sidebarTabs_ = tabNamesToTabs(sidebarTabs); + // Create sidebar tabset if not already created + LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); + if (sidebarWindow == null) + { + Triad sidebar = createTabSet( + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, + tabNamesToTabs(sidebarTabs)); + panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); + sidebarTabPanel_ = sidebar.second; + sidebarMinPanel_ = sidebar.third; + sidebarTabs_ = tabNamesToTabs(sidebarTabs); + sidebarWindow = sidebar.first; + } - LogicalWindow sidebarWindow = sidebar.first; if (sidebarWindow != null) { - sidebar_ = new DualWindowLayoutPanel( - eventBus_, - sidebarWindow, - new LogicalWindow(null, null), - session_, - SIDEBAR_COLUMN, - WindowState.NORMAL, - (int) (Window.getClientHeight() * 0.5), - 7); + // For sidebar, we use just the WindowFrame directly (no vertical split) + sidebarWindow.transitionToState(WindowState.NORMAL); + sidebar_ = sidebarWindow.getNormal(); panel_.setSidebarWidget(sidebar_); } } @@ -2199,7 +2208,7 @@ private void clearFocusIndicator() private MinimizedModuleTabLayoutPanel hiddenTabSetMinPanel_; private WorkbenchTabPanel sidebarTabPanel_; private MinimizedModuleTabLayoutPanel sidebarMinPanel_; - private DualWindowLayoutPanel sidebar_; + private Widget sidebar_; private ArrayList sidebarTabs_; // Zoom-related members ---- From d56c44593274ae587ff3e08242f6020de6be5e42 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Mon, 8 Sep 2025 10:47:02 -0600 Subject: [PATCH 04/14] persist sidebar visibility --- .../client/workbench/ui/PaneManager.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index 195de95951b..a04064d7566 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -333,7 +333,7 @@ public PaneManager(Provider pSplitPanel, } // Initialize sidebar if configured Widget sidebarWidget = null; - if (config.getSidebarVisible() && sidebarTabPanel_ != null) + if (config.getSidebarVisible()) { LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); if (sidebarWindow != null) @@ -974,6 +974,9 @@ public void onToggleSidebar() newVisibility, paneConfig.getSidebarLocation())); + // Persist the preference change + userPrefs_.writeUserPrefs(); + // Update the UI if (newVisibility) showSidebar(); @@ -1399,16 +1402,13 @@ private void initPanes(PaneConfig config) hiddenTabSetTabPanel_.setNeverVisible(true); hiddenTabSetMinPanel_ = tsHide.third; - // Initialize sidebar if configured - if (config.getSidebarVisible()) - { - Triad sidebar = createTabSet( - UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, - tabNamesToTabs(config.getSidebar())); - panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); - sidebarTabPanel_ = sidebar.second; - sidebarMinPanel_ = sidebar.third; - } + // Initialize sidebar (always create it, even if not initially visible) + Triad sidebar = createTabSet( + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, + tabNamesToTabs(config.getSidebar())); + panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); + sidebarTabPanel_ = sidebar.second; + sidebarMinPanel_ = sidebar.third; } private ArrayList tabNamesToTabs(JsArrayString tabNames) From 0a3ba67c3c2d32b9b8eff373be6458ccc02d186f Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Mon, 8 Sep 2025 16:08:25 -0600 Subject: [PATCH 05/14] show on left or right with command --- .../resources/schema/user-prefs-schema.json | 7 +- .../workbench/commands/CmdConstants.java | 6 ++ .../commands/CmdConstants_en.properties | 4 + .../commands/CmdConstants_fr.properties | 4 + .../workbench/commands/Commands.cmd.xml | 4 + .../workbench/commands/Commands.cmd.xml.MD5 | 2 +- .../client/workbench/commands/Commands.java | 1 + .../prefs/model/UserPrefsAccessor.java | 6 +- .../client/workbench/ui/MainSplitPanel.java | 87 +++++++++++++++---- .../client/workbench/ui/PaneManager.java | 67 +++++++++++++- .../workbench/commands/DummyCommands.java | 5 ++ 11 files changed, 162 insertions(+), 31 deletions(-) diff --git a/src/cpp/session/resources/schema/user-prefs-schema.json b/src/cpp/session/resources/schema/user-prefs-schema.json index ff61d3f11f6..fc372b5c6f5 100644 --- a/src/cpp/session/resources/schema/user-prefs-schema.json +++ b/src/cpp/session/resources/schema/user-prefs-schema.json @@ -214,7 +214,6 @@ "sidebar_location": { "type": "string", "enum": ["left", "right", "satellite"], - "default": "right", "description": "The location of the sidebar." } }, @@ -226,10 +225,10 @@ "TabSet2", "HiddenTabSet", "Sidebar"], - "tabSet1": ["Environment", "History", "Connections", "Build", "VCS", "Tutorial", "Presentation"], - "tabSet2": ["Files", "Plots", "Packages", "Help", "Viewer", "Presentations"], + "tabSet1": ["Environment", "Connections", "Build", "VCS", "Tutorial", "Presentation"], + "tabSet2": ["Plots", "Packages", "Help", "Viewer", "Presentations"], "hiddenTabSet": [], - "sidebar": [], + "sidebar": ["Files", "History"], "console_left_on_top": false, "console_right_on_top": true, "additional_source_columns": 0, diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java index f9022c1bb8a..d1dfbd0b9b7 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java @@ -542,6 +542,12 @@ public interface CmdConstants extends Constants { @DefaultStringValue("To_ggle Sidebar") // $NON-NLS-1$ String toggleSidebarMenuLabel(); + // moveSidebar + @DefaultStringValue("Move Sidebar Left or Right") // $NON-NLS-1$ + String moveSidebarLabel(); + @DefaultStringValue("Move Sidebar Left or Right") // $NON-NLS-1$ + String moveSidebarMenuLabel(); + // showToolbar @DefaultStringValue("Show _Toolbar") // $NON-NLS-1$ String showToolbarMenuLabel(); diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties index 7502d10c753..7846c379213 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties @@ -354,6 +354,10 @@ projectSweaveOptionsDesc = toggleSidebarLabel = Toggle Visibility of Sidebar toggleSidebarMenuLabel = To_ggle Sidebar +# moveSidebar +moveSidebarLabel = Move Sidebar Left or Right +moveSidebarMenuLabel = Move Sidebar Left or Right + # showToolbar showToolbarMenuLabel = Show _Toolbar diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties index 356b5de23b7..b29f8b0af69 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties @@ -354,6 +354,10 @@ projectSweaveOptionsDesc = toggleSidebarLabel = Basculer la visibilité de la barre latérale toggleSidebarMenuLabel = Basculer la barre latérale +# moveSidebar +moveSidebarLabel = Déplacer la barre latérale à gauche ou à droite +moveSidebarMenuLabel = Déplacer la barre latérale à gauche ou à droite + # showToolbar showToolbarMenuLabel = Afficher la barre d\u0027ou_tils diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml index cd20a399087..a5657969d18 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml @@ -1378,6 +1378,10 @@ See `/src/gwt/tools/i18n-helpers/README.md`. label="Toggle Visibility of Sidebar" menuLabel="To_ggle Sidebar"/> + + diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 index 0f39d8fc7ab..1f8042e05fe 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 @@ -1 +1 @@ -7f198e283117f4514eadb5e77e53f2b0 +4a260641c3e87cbfb77fd30f220d5a66 diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java index c30f8e219e4..6aaef39be49 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.java @@ -356,6 +356,7 @@ public abstract AppCommand showToolbar(); public abstract AppCommand hideToolbar(); public abstract AppCommand toggleSidebar(); + public abstract AppCommand moveSidebar(); public abstract AppCommand toggleToolbar(); public abstract AppCommand zoomActualSize(); public abstract AppCommand zoomIn(); diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java index 71e81cef5ba..0d76c25b9ad 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/model/UserPrefsAccessor.java @@ -396,11 +396,11 @@ public final native JsArrayString getQuadrants() /*-{ }-*/; public final native JsArrayString getTabSet1() /*-{ - return this && this.tabSet1 || ["Environment","History","Connections","Build","VCS","Tutorial","Presentation"]; + return this && this.tabSet1 || ["Environment","Connections","Build","VCS","Tutorial","Presentation"]; }-*/; public final native JsArrayString getTabSet2() /*-{ - return this && this.tabSet2 || ["Files","Plots","Packages","Help","Viewer","Presentations"]; + return this && this.tabSet2 || ["Plots","Packages","Help","Viewer","Presentations"]; }-*/; public final native JsArrayString getHiddenTabSet() /*-{ @@ -408,7 +408,7 @@ public final native JsArrayString getHiddenTabSet() /*-{ }-*/; public final native JsArrayString getSidebar() /*-{ - return this && this.sidebar || []; + return this && this.sidebar || ["Files","History"]; }-*/; public final native boolean getConsoleLeftOnTop() /*-{ diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java index 35d57a16362..49684321386 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java @@ -135,15 +135,21 @@ public MainSplitPanel(EventBus events, public void initialize(ArrayList leftList, Widget center, Widget right) { - initialize(leftList, center, right, null); + initialize(leftList, center, right, null, "right"); } public void initialize(ArrayList leftList, Widget center, Widget right, Widget sidebar) + { + initialize(leftList, center, right, sidebar, "right"); + } + + public void initialize(ArrayList leftList, Widget center, Widget right, Widget sidebar, String sidebarLocation) { leftList_ = leftList; center_ = center; right_ = right; sidebar_ = sidebar; + sidebarLocation_ = sidebarLocation; new JSObjectStateValue(GROUP_WORKBENCH, KEY_RIGHTPANESIZE, @@ -168,30 +174,47 @@ protected void onInit(JsObject value) int delta = state.getWindowWidth() - state.getPanelWidth(); int offsetWidth = Window.getClientWidth() - delta; int idx = 0; - if (sidebar_ != null) + double pct; + // Add sidebar if on left + if (sidebar_ != null && "left".equals(sidebarLocation_)) { - double pct = (double)state.getSplitterPos()[idx++] + pct = (double)state.getSplitterPos()[idx++] / state.getPanelWidth(); - addEast(sidebar_, pct * offsetWidth); + addWest(sidebar_, pct * offsetWidth); } - double pct = (double)state.getSplitterPos()[idx++] - / state.getPanelWidth(); - addEast(right_, pct * offsetWidth); + // Add left widgets for (int i = 0; i < leftList_.size(); i++) { pct = (double)state.getSplitterPos()[idx++] / state.getPanelWidth(); addWest(leftList_.get(i), pct * offsetWidth); } + // Add sidebar if on right (add first so it's rightmost) + if (sidebar_ != null && !"left".equals(sidebarLocation_)) + { + pct = (double)state.getSplitterPos()[idx++] + / state.getPanelWidth(); + addEast(sidebar_, pct * offsetWidth); + } + // Add right widget (after sidebar so it's to the left of sidebar) + pct = (double)state.getSplitterPos()[idx++] + / state.getPanelWidth(); + addEast(right_, pct * offsetWidth); } else { int idx = 0; - if (sidebar_ != null) - addEast(sidebar_, state.getSplitterPos()[idx++]); - addEast(right_, state.getSplitterPos()[idx++]); + // Add sidebar if on left + if (sidebar_ != null && "left".equals(sidebarLocation_)) + addWest(sidebar_, state.getSplitterPos()[idx++]); + // Add left widgets for (int i = 0; i < leftList_.size(); i++) addWest(leftList_.get(i), state.getSplitterPos()[idx++]); + // Add sidebar if on right (add first so it's rightmost) + if (sidebar_ != null && !"left".equals(sidebarLocation_)) + addEast(sidebar_, state.getSplitterPos()[idx++]); + // Add right widget (after sidebar so it's to the left of sidebar) + addEast(right_, state.getSplitterPos()[idx++]); } } else @@ -199,12 +222,21 @@ protected void onInit(JsObject value) // When there are only two panels, make the left side slightly larger than the right, // otherwise divide the space equally. double splitWidth = getDefaultSplitterWidth(); - if (sidebar_ != null) - addEast(sidebar_, splitWidth * 0.8); // Sidebar slightly narrower - addEast(right_, splitWidth); - + + // Add sidebar if on left + if (sidebar_ != null && "left".equals(sidebarLocation_)) + addWest(sidebar_, splitWidth * 0.8); // Sidebar slightly narrower + + // Add left widgets for (Widget w : leftList_) addWest(w, splitWidth); + + // Add sidebar if on right (add first so it's rightmost) + if (sidebar_ != null && !"left".equals(sidebarLocation_)) + addEast(sidebar_, splitWidth * 0.8); // Sidebar slightly narrower + + // Add right widget (after sidebar so it's to the left of sidebar) + addEast(right_, splitWidth); } Scheduler.get().scheduleDeferred(new ScheduledCommand() @@ -229,14 +261,24 @@ protected JsObject getValue() int sidebarCount = sidebar_ != null ? 1 : 0; int[] splitterArray = new int[leftList_.size() + 1 + sidebarCount]; int idx = 0; - if (sidebar_ != null) + + // Store sidebar width if on left + if (sidebar_ != null && "left".equals(sidebarLocation_)) splitterArray[idx++] = sidebar_.getOffsetWidth(); - splitterArray[idx++] = right_.getOffsetWidth(); + + // Store left widget widths if (!leftList_.isEmpty()) { for (int i = 0; i < leftList_.size(); i++) splitterArray[idx++] = leftList_.get(i).getOffsetWidth(); } + + // Store sidebar width if on right (before right widget in the array) + if (sidebar_ != null && !"left".equals(sidebarLocation_)) + splitterArray[idx++] = sidebar_.getOffsetWidth(); + + // Store right widget width + splitterArray[idx++] = right_.getOffsetWidth(); state.setSplitterPos(splitterArray); return state.cast(); } @@ -271,7 +313,7 @@ public void addLeftWidget(Widget widget) { clearForRefresh(); leftList_.add(0, widget); - initialize(leftList_, center_, right_, sidebar_); + initialize(leftList_, center_, right_, sidebar_, sidebarLocation_); } public double getDefaultSplitterWidth() @@ -302,14 +344,20 @@ public void removeLeftWidget(Widget widget) { clearForRefresh(); leftList_.remove(widget); - initialize(leftList_, center_, right_, sidebar_); + initialize(leftList_, center_, right_, sidebar_, sidebarLocation_); } public void setSidebarWidget(Widget widget) + { + setSidebarWidget(widget, "right"); + } + + public void setSidebarWidget(Widget widget, String location) { clearForRefresh(); sidebar_ = widget; - initialize(leftList_, center_, right_, sidebar_); + sidebarLocation_ = location; + initialize(leftList_, center_, right_, sidebar_, sidebarLocation_); } public void removeSidebarWidget() @@ -414,6 +462,7 @@ public void execute() { private Widget center_; private Widget right_; private Widget sidebar_; + private String sidebarLocation_ = "right"; private static final String GROUP_WORKBENCH = "workbenchp"; private static final String KEY_RIGHTPANESIZE = "rightpanesize"; private Command layoutCommand_; diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index a04064d7566..b2a11283f12 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -333,6 +333,7 @@ public PaneManager(Provider pSplitPanel, } // Initialize sidebar if configured Widget sidebarWidget = null; + String sidebarLocation = config.getSidebarLocation(); if (config.getSidebarVisible()) { LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); @@ -345,7 +346,7 @@ public PaneManager(Provider pSplitPanel, } } - panel_.initialize(leftList_, center_, right_, sidebarWidget); + panel_.initialize(leftList_, center_, right_, sidebarWidget, sidebarLocation); for (LogicalWindow window : sourceLogicalWindows_) { @@ -984,6 +985,38 @@ public void onToggleSidebar() hideSidebar(); } + @Handler + public void onMoveSidebar() + { + // Toggle the sidebar location between left and right + PaneConfig paneConfig = userPrefs_.panes().getValue().cast(); + String currentLocation = paneConfig.getSidebarLocation(); + String newLocation = "left".equals(currentLocation) ? "right" : "left"; + + // Update the preference + userPrefs_.panes().setGlobalValue(PaneConfig.create( + JsArrayUtil.copy(paneConfig.getQuadrants()), + paneConfig.getTabSet1(), + paneConfig.getTabSet2(), + paneConfig.getHiddenTabSet(), + paneConfig.getConsoleLeftOnTop(), + paneConfig.getConsoleRightOnTop(), + paneConfig.getAdditionalSourceColumns(), + paneConfig.getSidebar(), + paneConfig.getSidebarVisible(), + newLocation)); + + // Persist the preference change + userPrefs_.writeUserPrefs(); + + // Update the UI by hiding and re-showing the sidebar in the new location + if (sidebar_ != null) + { + hideSidebar(); + showSidebar(); + } + } + public void showSidebar() { if (sidebar_ == null) @@ -1011,7 +1044,8 @@ public void showSidebar() // For sidebar, we use just the WindowFrame directly (no vertical split) sidebarWindow.transitionToState(WindowState.NORMAL); sidebar_ = sidebarWindow.getNormal(); - panel_.setSidebarWidget(sidebar_); + String location = config.getSidebarLocation(); + panel_.setSidebarWidget(sidebar_, location); } } } @@ -1034,8 +1068,33 @@ public boolean isSidebarVisible() public void setSidebarLocation(String location) { - // This will be implemented to handle "left" vs "right" positioning - // For now, sidebar is always on the right + // Update preference and refresh the sidebar if visible + PaneConfig paneConfig = userPrefs_.panes().getValue().cast(); + + // Only update if location has changed + if (!location.equals(paneConfig.getSidebarLocation())) + { + userPrefs_.panes().setGlobalValue(PaneConfig.create( + JsArrayUtil.copy(paneConfig.getQuadrants()), + paneConfig.getTabSet1(), + paneConfig.getTabSet2(), + paneConfig.getHiddenTabSet(), + paneConfig.getConsoleLeftOnTop(), + paneConfig.getConsoleRightOnTop(), + paneConfig.getAdditionalSourceColumns(), + paneConfig.getSidebar(), + paneConfig.getSidebarVisible(), + location)); + + userPrefs_.writeUserPrefs(); + + // If sidebar is visible, refresh it in the new location + if (sidebar_ != null) + { + hideSidebar(); + showSidebar(); + } + } } private boolean equals(T lhs, T rhs) diff --git a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java index 0c13c64a3b4..3ecdaaf3639 100644 --- a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java +++ b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java @@ -1564,6 +1564,11 @@ public AppCommand toggleSidebar() { return null; } + @Override + public AppCommand moveSidebar() { + return null; + } + @Override public AppCommand toggleToolbar() { return null; From 9c115eb483e2de2ccc24fdef34c6b74c1735852f Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Tue, 9 Sep 2025 16:35:48 -0600 Subject: [PATCH 06/14] add command for moving sidebar to View menu --- .../studio/client/workbench/commands/CmdConstants.java | 2 +- .../client/workbench/commands/CmdConstants_en.properties | 2 +- .../studio/client/workbench/commands/Commands.cmd.xml | 6 +++--- .../studio/client/workbench/commands/Commands.cmd.xml.MD5 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java index d1dfbd0b9b7..859bfcd92d4 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java @@ -545,7 +545,7 @@ public interface CmdConstants extends Constants { // moveSidebar @DefaultStringValue("Move Sidebar Left or Right") // $NON-NLS-1$ String moveSidebarLabel(); - @DefaultStringValue("Move Sidebar Left or Right") // $NON-NLS-1$ + @DefaultStringValue("Move Si_debar Left or Right") // $NON-NLS-1$ String moveSidebarMenuLabel(); // showToolbar diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties index 7846c379213..b2907001c88 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties @@ -356,7 +356,7 @@ toggleSidebarMenuLabel = To_ggle Sidebar # moveSidebar moveSidebarLabel = Move Sidebar Left or Right -moveSidebarMenuLabel = Move Sidebar Left or Right +moveSidebarMenuLabel = Move Si_debar Left or Right # showToolbar showToolbarMenuLabel = Show _Toolbar diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml index a5657969d18..4d13c7db52a 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml @@ -281,11 +281,11 @@ See `/src/gwt/tools/i18n-helpers/README.md`. + + - - @@ -1380,7 +1380,7 @@ See `/src/gwt/tools/i18n-helpers/README.md`. + menuLabel="Move Si_debar Left or Right"/> Date: Wed, 10 Sep 2025 10:58:03 -0600 Subject: [PATCH 07/14] remove stray whitespace change --- .../rstudio/studio/client/workbench/commands/Commands.cmd.xml | 2 ++ .../studio/client/workbench/commands/Commands.cmd.xml.MD5 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml index 4d13c7db52a..87b7c6afa01 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml @@ -285,7 +285,9 @@ See `/src/gwt/tools/i18n-helpers/README.md`. + + diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 index 231d33f4adc..083879b01b8 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml.MD5 @@ -1 +1 @@ -9517231127ccde35cf161f23e81e8cbd +14dcda63f19eccdee4937f9105dc8500 From e02781301f2bdf48d8ac8db0c5592d8becf17b27 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Wed, 10 Sep 2025 13:58:36 -0600 Subject: [PATCH 08/14] always create sidebar --- .../client/workbench/ui/MainSplitPanel.java | 22 ++++ .../client/workbench/ui/PaneManager.java | 119 ++++++++++++------ 2 files changed, 102 insertions(+), 39 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java index 49684321386..18d40fc1656 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java @@ -371,6 +371,28 @@ public boolean hasSidebarWidget() { return sidebar_ != null; } + + public void setSidebarWidth(double width) + { + if (sidebar_ != null) + { + LayoutData layoutData = (LayoutData) sidebar_.getLayoutData(); + if (layoutData != null) + { + layoutData.size = width; + forceLayout(); + } + } + } + + public double getSidebarWidth() + { + if (sidebar_ != null) + { + return sidebar_.getOffsetWidth(); + } + return 0; + } public void onSplitterResized(SplitterResizedEvent event) { diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index b2a11283f12..25812e3211f 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -72,6 +72,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Element; import com.google.gwt.layout.client.Layout.AnimationCallback; import com.google.gwt.layout.client.Layout.Layer; @@ -331,22 +332,43 @@ public PaneManager(Provider pSplitPanel, 0).cast()); } } - // Initialize sidebar if configured + // Always initialize sidebar widget (will control visibility via width) Widget sidebarWidget = null; String sidebarLocation = config.getSidebarLocation(); - if (config.getSidebarVisible()) + LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); + if (sidebarWindow != null) { - LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); - if (sidebarWindow != null) - { - // For sidebar, we use just the WindowFrame directly (no vertical split) - sidebarWindow.transitionToState(WindowState.NORMAL); - sidebarWidget = sidebarWindow.getNormal(); - sidebar_ = sidebarWidget; - } + // For sidebar, we use just the WindowFrame directly (no vertical split) + sidebarWindow.transitionToState(WindowState.NORMAL); + sidebarWidget = sidebarWindow.getNormal(); + sidebar_ = sidebarWidget; + + // Set initial visibility state (width will be controlled after panel initialization) + sidebarVisible_ = config.getSidebarVisible(); } panel_.initialize(leftList_, center_, right_, sidebarWidget, sidebarLocation); + + // Set initial sidebar width based on visibility (deferred to allow layout to complete) + if (sidebar_ != null) + { + Scheduler.get().scheduleDeferred(() -> { + if (!sidebarVisible_) + { + // Hide sidebar by setting width to 0 + setSidebarWidth(0); + } + else + { + // Store the default width that was set + double currentWidth = panel_.getSidebarWidth(); + if (currentWidth > 0) + { + lastSidebarWidth_ = currentWidth; + } + } + }); + } for (LogicalWindow window : sourceLogicalWindows_) { @@ -1019,34 +1041,19 @@ public void onMoveSidebar() public void showSidebar() { - if (sidebar_ == null) + if (sidebar_ != null) { - // Create sidebar configuration - PaneConfig config = userPrefs_.panes().getValue().cast(); - JsArrayString sidebarTabs = config.getSidebar(); - - // Create sidebar tabset if not already created - LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); - if (sidebarWindow == null) + // Store current width if it's non-zero (in case it was manually resized) + double currentWidth = panel_.getSidebarWidth(); + if (currentWidth > 0) { - Triad sidebar = createTabSet( - UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, - tabNamesToTabs(sidebarTabs)); - panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); - sidebarTabPanel_ = sidebar.second; - sidebarMinPanel_ = sidebar.third; - sidebarTabs_ = tabNamesToTabs(sidebarTabs); - sidebarWindow = sidebar.first; + lastSidebarWidth_ = currentWidth; } - if (sidebarWindow != null) - { - // For sidebar, we use just the WindowFrame directly (no vertical split) - sidebarWindow.transitionToState(WindowState.NORMAL); - sidebar_ = sidebarWindow.getNormal(); - String location = config.getSidebarLocation(); - panel_.setSidebarWidget(sidebar_, location); - } + // Use last known width or default (20% of window width) + double targetWidth = lastSidebarWidth_ > 0 ? lastSidebarWidth_ : Window.getClientWidth() * 0.2; + setSidebarWidth(targetWidth); + sidebarVisible_ = true; } } @@ -1054,11 +1061,24 @@ public void hideSidebar() { if (sidebar_ != null) { - panel_.removeSidebarWidget(); - sidebar_ = null; + // Store current width before hiding + double currentWidth = panel_.getSidebarWidth(); + if (currentWidth > 0) + { + lastSidebarWidth_ = currentWidth; + } + + // Hide by setting width to 0 + setSidebarWidth(0); + sidebarVisible_ = false; } } + private void setSidebarWidth(double width) + { + panel_.setSidebarWidth(width); + } + public boolean isSidebarVisible() { PaneConfig config = userPrefs_.panes().getValue().cast(); @@ -1088,11 +1108,30 @@ public void setSidebarLocation(String location) userPrefs_.writeUserPrefs(); - // If sidebar is visible, refresh it in the new location + // If sidebar exists, we need to recreate the panel with sidebar in new location if (sidebar_ != null) { - hideSidebar(); - showSidebar(); + // Store current visibility and width + boolean wasVisible = sidebarVisible_; + double currentWidth = panel_.getSidebarWidth(); + if (currentWidth > 0) + { + lastSidebarWidth_ = currentWidth; + } + + // Remove and re-add all widgets with sidebar in new location + panel_.removeSidebarWidget(); + panel_.setSidebarWidget(sidebar_, location); + + // Restore visibility state + if (wasVisible) + { + setSidebarWidth(lastSidebarWidth_ > 0 ? lastSidebarWidth_ : Window.getClientWidth() * 0.2); + } + else + { + setSidebarWidth(0); + } } } } @@ -2269,6 +2308,8 @@ private void clearFocusIndicator() private MinimizedModuleTabLayoutPanel sidebarMinPanel_; private Widget sidebar_; private ArrayList sidebarTabs_; + private boolean sidebarVisible_ = false; + private double lastSidebarWidth_ = 0; // Zoom-related members ---- private Tab lastSelectedTab_ = null; From 2dfe15c543c4fd8bacfb4cc1fb384a57989317aa Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Wed, 10 Sep 2025 14:25:21 -0600 Subject: [PATCH 09/14] Revert "always create sidebar" This reverts commit e02781301f2bdf48d8ac8db0c5592d8becf17b27. --- .../client/workbench/ui/MainSplitPanel.java | 22 ---- .../client/workbench/ui/PaneManager.java | 119 ++++++------------ 2 files changed, 39 insertions(+), 102 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java index 18d40fc1656..49684321386 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java @@ -371,28 +371,6 @@ public boolean hasSidebarWidget() { return sidebar_ != null; } - - public void setSidebarWidth(double width) - { - if (sidebar_ != null) - { - LayoutData layoutData = (LayoutData) sidebar_.getLayoutData(); - if (layoutData != null) - { - layoutData.size = width; - forceLayout(); - } - } - } - - public double getSidebarWidth() - { - if (sidebar_ != null) - { - return sidebar_.getOffsetWidth(); - } - return 0; - } public void onSplitterResized(SplitterResizedEvent event) { diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java index 25812e3211f..b2a11283f12 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/PaneManager.java @@ -72,7 +72,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayString; -import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Element; import com.google.gwt.layout.client.Layout.AnimationCallback; import com.google.gwt.layout.client.Layout.Layer; @@ -332,43 +331,22 @@ public PaneManager(Provider pSplitPanel, 0).cast()); } } - // Always initialize sidebar widget (will control visibility via width) + // Initialize sidebar if configured Widget sidebarWidget = null; String sidebarLocation = config.getSidebarLocation(); - LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); - if (sidebarWindow != null) + if (config.getSidebarVisible()) { - // For sidebar, we use just the WindowFrame directly (no vertical split) - sidebarWindow.transitionToState(WindowState.NORMAL); - sidebarWidget = sidebarWindow.getNormal(); - sidebar_ = sidebarWidget; - - // Set initial visibility state (width will be controlled after panel initialization) - sidebarVisible_ = config.getSidebarVisible(); + LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); + if (sidebarWindow != null) + { + // For sidebar, we use just the WindowFrame directly (no vertical split) + sidebarWindow.transitionToState(WindowState.NORMAL); + sidebarWidget = sidebarWindow.getNormal(); + sidebar_ = sidebarWidget; + } } panel_.initialize(leftList_, center_, right_, sidebarWidget, sidebarLocation); - - // Set initial sidebar width based on visibility (deferred to allow layout to complete) - if (sidebar_ != null) - { - Scheduler.get().scheduleDeferred(() -> { - if (!sidebarVisible_) - { - // Hide sidebar by setting width to 0 - setSidebarWidth(0); - } - else - { - // Store the default width that was set - double currentWidth = panel_.getSidebarWidth(); - if (currentWidth > 0) - { - lastSidebarWidth_ = currentWidth; - } - } - }); - } for (LogicalWindow window : sourceLogicalWindows_) { @@ -1041,19 +1019,34 @@ public void onMoveSidebar() public void showSidebar() { - if (sidebar_ != null) + if (sidebar_ == null) { - // Store current width if it's non-zero (in case it was manually resized) - double currentWidth = panel_.getSidebarWidth(); - if (currentWidth > 0) + // Create sidebar configuration + PaneConfig config = userPrefs_.panes().getValue().cast(); + JsArrayString sidebarTabs = config.getSidebar(); + + // Create sidebar tabset if not already created + LogicalWindow sidebarWindow = panesByName_.get(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR); + if (sidebarWindow == null) { - lastSidebarWidth_ = currentWidth; + Triad sidebar = createTabSet( + UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, + tabNamesToTabs(sidebarTabs)); + panesByName_.put(UserPrefsAccessor.Panes.QUADRANTS_SIDEBAR, sidebar.first); + sidebarTabPanel_ = sidebar.second; + sidebarMinPanel_ = sidebar.third; + sidebarTabs_ = tabNamesToTabs(sidebarTabs); + sidebarWindow = sidebar.first; } - // Use last known width or default (20% of window width) - double targetWidth = lastSidebarWidth_ > 0 ? lastSidebarWidth_ : Window.getClientWidth() * 0.2; - setSidebarWidth(targetWidth); - sidebarVisible_ = true; + if (sidebarWindow != null) + { + // For sidebar, we use just the WindowFrame directly (no vertical split) + sidebarWindow.transitionToState(WindowState.NORMAL); + sidebar_ = sidebarWindow.getNormal(); + String location = config.getSidebarLocation(); + panel_.setSidebarWidget(sidebar_, location); + } } } @@ -1061,24 +1054,11 @@ public void hideSidebar() { if (sidebar_ != null) { - // Store current width before hiding - double currentWidth = panel_.getSidebarWidth(); - if (currentWidth > 0) - { - lastSidebarWidth_ = currentWidth; - } - - // Hide by setting width to 0 - setSidebarWidth(0); - sidebarVisible_ = false; + panel_.removeSidebarWidget(); + sidebar_ = null; } } - private void setSidebarWidth(double width) - { - panel_.setSidebarWidth(width); - } - public boolean isSidebarVisible() { PaneConfig config = userPrefs_.panes().getValue().cast(); @@ -1108,30 +1088,11 @@ public void setSidebarLocation(String location) userPrefs_.writeUserPrefs(); - // If sidebar exists, we need to recreate the panel with sidebar in new location + // If sidebar is visible, refresh it in the new location if (sidebar_ != null) { - // Store current visibility and width - boolean wasVisible = sidebarVisible_; - double currentWidth = panel_.getSidebarWidth(); - if (currentWidth > 0) - { - lastSidebarWidth_ = currentWidth; - } - - // Remove and re-add all widgets with sidebar in new location - panel_.removeSidebarWidget(); - panel_.setSidebarWidget(sidebar_, location); - - // Restore visibility state - if (wasVisible) - { - setSidebarWidth(lastSidebarWidth_ > 0 ? lastSidebarWidth_ : Window.getClientWidth() * 0.2); - } - else - { - setSidebarWidth(0); - } + hideSidebar(); + showSidebar(); } } } @@ -2308,8 +2269,6 @@ private void clearFocusIndicator() private MinimizedModuleTabLayoutPanel sidebarMinPanel_; private Widget sidebar_; private ArrayList sidebarTabs_; - private boolean sidebarVisible_ = false; - private double lastSidebarWidth_ = 0; // Zoom-related members ---- private Tab lastSelectedTab_ = null; From 97b886baa39ff1fc68732d536da47e3882828cf0 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Wed, 10 Sep 2025 15:27:51 -0600 Subject: [PATCH 10/14] resize fixes (WIP) --- .../client/workbench/ui/MainSplitPanel.java | 96 ++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java index 49684321386..3673c25d2f9 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/ui/MainSplitPanel.java @@ -189,17 +189,45 @@ protected void onInit(JsObject value) / state.getPanelWidth(); addWest(leftList_.get(i), pct * offsetWidth); } - // Add sidebar if on right (add first so it's rightmost) + // Handle right-side sidebar case differently for proper resizing if (sidebar_ != null && !"left".equals(sidebarLocation_)) { + // Add sidebar first using addEast (rightmost position) + double sidebarPct = (double)state.getSplitterPos()[idx++] + / state.getPanelWidth(); + addEast(sidebar_, sidebarPct * offsetWidth); + + // Get right widget width + double rightPct = (double)state.getSplitterPos()[idx++] + / state.getPanelWidth(); + + // Calculate center width: total - left widgets - sidebar - right + double centerWidth = offsetWidth; + // Subtract all left widget widths that were already added + int leftStartIdx = sidebar_ != null && "left".equals(sidebarLocation_) ? 1 : 0; + for (int i = 0; i < leftList_.size(); i++) + { + double leftPct = (double)state.getSplitterPos()[leftStartIdx + i] / state.getPanelWidth(); + centerWidth -= leftPct * offsetWidth; + } + // Subtract sidebar and right widths + centerWidth -= sidebarPct * offsetWidth; + centerWidth -= rightPct * offsetWidth; + + // Add center using addWest (last addWest call) + addWest(center_, centerWidth); + + // Add right using add() (last thing added) + add(right_); + } + else + { + // No sidebar on right - use original logic pct = (double)state.getSplitterPos()[idx++] / state.getPanelWidth(); - addEast(sidebar_, pct * offsetWidth); + addEast(right_, pct * offsetWidth); + add(center_); } - // Add right widget (after sidebar so it's to the left of sidebar) - pct = (double)state.getSplitterPos()[idx++] - / state.getPanelWidth(); - addEast(right_, pct * offsetWidth); } else { @@ -210,11 +238,38 @@ protected void onInit(JsObject value) // Add left widgets for (int i = 0; i < leftList_.size(); i++) addWest(leftList_.get(i), state.getSplitterPos()[idx++]); - // Add sidebar if on right (add first so it's rightmost) + // Handle right-side sidebar case differently for proper resizing if (sidebar_ != null && !"left".equals(sidebarLocation_)) - addEast(sidebar_, state.getSplitterPos()[idx++]); - // Add right widget (after sidebar so it's to the left of sidebar) - addEast(right_, state.getSplitterPos()[idx++]); + { + // Add sidebar first using addEast (rightmost position) + int sidebarWidth = state.getSplitterPos()[idx++]; + addEast(sidebar_, sidebarWidth); + + // Get right widget width + int rightWidth = state.getSplitterPos()[idx++]; + + // Calculate remaining width for center (total - left widgets - sidebar - right) + int centerWidth = state.getPanelWidth(); + // Subtract all left widget widths that were already added + int leftStartIdx = sidebar_ != null && "left".equals(sidebarLocation_) ? 1 : 0; + for (int i = 0; i < leftList_.size(); i++) + centerWidth -= state.getSplitterPos()[leftStartIdx + i]; + // Subtract sidebar and right widths + centerWidth -= sidebarWidth; + centerWidth -= rightWidth; + + // Add center using addWest (last addWest call) + addWest(center_, centerWidth); + + // Add right using add() (last thing added) + add(right_); + } + else + { + // No sidebar on right - use original logic + addEast(right_, state.getSplitterPos()[idx++]); + add(center_); + } } } else @@ -231,12 +286,24 @@ protected void onInit(JsObject value) for (Widget w : leftList_) addWest(w, splitWidth); - // Add sidebar if on right (add first so it's rightmost) + // Handle right-side sidebar case differently for proper resizing if (sidebar_ != null && !"left".equals(sidebarLocation_)) + { + // Add sidebar first using addEast (rightmost position) addEast(sidebar_, splitWidth * 0.8); // Sidebar slightly narrower - - // Add right widget (after sidebar so it's to the left of sidebar) - addEast(right_, splitWidth); + + // Add center using addWest (last addWest call) + addWest(center_, splitWidth); + + // Add right using add() (last thing added) + add(right_); + } + else + { + // No sidebar on right - use original logic + addEast(right_, splitWidth); + add(center_); + } } Scheduler.get().scheduleDeferred(new ScheduledCommand() @@ -298,7 +365,6 @@ protected boolean hasChanged() private State lastKnownValue_; }; - add(center_); setWidgetMinSize(right_, 0); } From aa97652d36eaa080445fa6d02d188c0d716634ed Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Thu, 11 Sep 2025 11:31:32 -0600 Subject: [PATCH 11/14] tweaking command / pref handling --- .../workbench/commands/CmdConstants.java | 10 ++- .../commands/CmdConstants_en.properties | 7 +- .../commands/CmdConstants_fr.properties | 6 ++ .../workbench/commands/Commands.cmd.xml | 17 ++-- .../workbench/commands/Commands.cmd.xml.MD5 | 2 +- .../client/workbench/commands/Commands.java | 4 +- .../client/workbench/ui/PaneManager.java | 87 +++++++++++-------- .../workbench/commands/DummyCommands.java | 16 +++- 8 files changed, 100 insertions(+), 49 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java index 859bfcd92d4..c7f63e24686 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants.java @@ -536,11 +536,17 @@ public interface CmdConstants extends Constants { @DefaultStringValue("") // $NON-NLS-1$ String projectSweaveOptionsDesc(); + // showSidebar + @DefaultStringValue("Show Si_debar") // $NON-NLS-1$ + String showSidebarMenuLabel(); + + // hideSidebar + @DefaultStringValue("Hide Sideb_ar") // $NON-NLS-1$ + String hideSidebarMenuLabel(); + // toggleSidebar @DefaultStringValue("Toggle Visibility of Sidebar") // $NON-NLS-1$ String toggleSidebarLabel(); - @DefaultStringValue("To_ggle Sidebar") // $NON-NLS-1$ - String toggleSidebarMenuLabel(); // moveSidebar @DefaultStringValue("Move Sidebar Left or Right") // $NON-NLS-1$ diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties index b2907001c88..ee27e1c6e8f 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_en.properties @@ -350,9 +350,14 @@ projectSweaveOptionsButtonLabel = projectSweaveOptionsMenuLabel = projectSweaveOptionsDesc = +# showSidebar +showSidebarMenuLabel = Show Si_debar + +# hideSidebar +hideSidebarMenuLabel = Hide Sideb_ar + # toggleSidebar toggleSidebarLabel = Toggle Visibility of Sidebar -toggleSidebarMenuLabel = To_ggle Sidebar # moveSidebar moveSidebarLabel = Move Sidebar Left or Right diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties index b29f8b0af69..34d0c2146cb 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/CmdConstants_fr.properties @@ -350,6 +350,12 @@ projectSweaveOptionsButtonLabel = projectSweaveOptionsMenuLabel = projectSweaveOptionsDesc = +# showSidebar +showSidebarMenuLabel = Afficher la barre latérale + +# hideSidebar +hideSidebarMenuLabel = Cacher la barre latérale + # toggleSidebar toggleSidebarLabel = Basculer la visibilité de la barre latérale toggleSidebarMenuLabel = Basculer la barre latérale diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml index 87b7c6afa01..05716b92d8a 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml +++ b/src/gwt/src/org/rstudio/studio/client/workbench/commands/Commands.cmd.xml @@ -280,9 +280,8 @@ See `/src/gwt/tools/i18n-helpers/README.md`. - - - + + @@ -291,6 +290,7 @@ See `/src/gwt/tools/i18n-helpers/README.md`. + @@ -1376,9 +1376,16 @@ See `/src/gwt/tools/i18n-helpers/README.md`. buttonLabel="" desc=""/> + + + + + label="Toggle Visibility of Sidebar"/> pSplitPanel, sidebarWidget = sidebarWindow.getNormal(); sidebar_ = sidebarWidget; } + showSidebar(true); + } else { + showSidebar(false); } panel_.initialize(leftList_, center_, right_, sidebarWidget, sidebarLocation); @@ -436,6 +439,9 @@ else if (center_.getOffsetWidth() == 0 || right_.getOffsetWidth() == 0) hiddenTabs_ = tabNamesToTabs(evt.getValue().getHiddenTabSet()); populateTabPanel(hiddenTabs_, hiddenTabSetTabPanel_, hiddenTabSetMinPanel_); + // manage sidebar + showSidebar(evt.getValue().getSidebarVisible()); + // manage source column commands boolean visible = userPrefs.allowSourceColumns().getValue() && (userPrefs.panes().getValue().getAdditionalSourceColumns() < MAX_COLUMN_COUNT); @@ -955,13 +961,12 @@ public void onPaneLayout() optionsLoader_.showOptions(PaneLayoutPreferencesPane.class, true); } - @Handler - public void onToggleSidebar() + private void setSidebarPref(boolean showSidebar) { - // Toggle the preference value and update UI PaneConfig paneConfig = userPrefs_.panes().getValue().cast(); - boolean newVisibility = !paneConfig.getSidebarVisible(); - + if (showSidebar == paneConfig.getSidebarVisible()) + return; + // Update the preference userPrefs_.panes().setGlobalValue(PaneConfig.create( JsArrayUtil.copy(paneConfig.getQuadrants()), @@ -972,17 +977,32 @@ public void onToggleSidebar() paneConfig.getConsoleRightOnTop(), paneConfig.getAdditionalSourceColumns(), paneConfig.getSidebar(), - newVisibility, + showSidebar, paneConfig.getSidebarLocation())); - - // Persist the preference change + userPrefs_.writeUserPrefs(); - - // Update the UI - if (newVisibility) - showSidebar(); - else - hideSidebar(); + } + + @Handler + public void onShowSidebar() + { + setSidebarPref(true); + } + + @Handler + public void onHideSidebar() + { + setSidebarPref(false); + } + + @Handler + public void onToggleSidebar() + { + // Toggle the preference value and update UI + PaneConfig paneConfig = userPrefs_.panes().getValue().cast(); + boolean newVisibility = !paneConfig.getSidebarVisible(); + + setSidebarPref(newVisibility); } @Handler @@ -1010,16 +1030,12 @@ public void onMoveSidebar() userPrefs_.writeUserPrefs(); // Update the UI by hiding and re-showing the sidebar in the new location - if (sidebar_ != null) - { - hideSidebar(); - showSidebar(); - } + refreshSidebar(); } - public void showSidebar() + public void showSidebar(boolean showSidebar) { - if (sidebar_ == null) + if (showSidebar && sidebar_ == null) { // Create sidebar configuration PaneConfig config = userPrefs_.panes().getValue().cast(); @@ -1048,24 +1064,27 @@ public void showSidebar() panel_.setSidebarWidget(sidebar_, location); } } - } - - public void hideSidebar() - { - if (sidebar_ != null) + else if (!showSidebar && sidebar_ != null) { panel_.removeSidebarWidget(); sidebar_ = null; } + + // manage commands + commands_.showSidebar().setVisible(!showSidebar); + commands_.hideSidebar().setVisible(showSidebar); } - public boolean isSidebarVisible() + public void refreshSidebar() { - PaneConfig config = userPrefs_.panes().getValue().cast(); - return config.getSidebarVisible(); - // return sidebar_ != null && panel_.hasSidebarWidget(); + // If sidebar is visible, refresh it (e.g. if the sidebar location has changed) + if (sidebar_ != null) + { + showSidebar(false); + showSidebar(true); + } } - + public void setSidebarLocation(String location) { // Update preference and refresh the sidebar if visible @@ -1089,11 +1108,7 @@ public void setSidebarLocation(String location) userPrefs_.writeUserPrefs(); // If sidebar is visible, refresh it in the new location - if (sidebar_ != null) - { - hideSidebar(); - showSidebar(); - } + refreshSidebar(); } } diff --git a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java index 3ecdaaf3639..0f807136f72 100644 --- a/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java +++ b/src/gwt/test/org/rstudio/studio/client/workbench/commands/DummyCommands.java @@ -1560,17 +1560,27 @@ public AppCommand hideToolbar() { } @Override - public AppCommand toggleSidebar() { + public AppCommand toggleToolbar() { return null; } @Override - public AppCommand moveSidebar() { + public AppCommand showSidebar() { return null; } @Override - public AppCommand toggleToolbar() { + public AppCommand hideSidebar() { + return null; + } + + @Override + public AppCommand toggleSidebar() { + return null; + } + + @Override + public AppCommand moveSidebar() { return null; } From 41b6e16ac92633aae56b8c2b38705d4771a3b208 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Thu, 11 Sep 2025 11:46:40 -0600 Subject: [PATCH 12/14] exclude AGENTS.md --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9bcd7463ee3..ef8ec634051 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,6 @@ venv/ .venv/ CLAUDE.md +AGENTS.md .claude/ spec/ From 6f0061978812d5399ec58e34f387fec6e4cdc687 Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Thu, 11 Sep 2025 13:57:11 -0600 Subject: [PATCH 13/14] preserve new settings with pane layout UI --- .../workbench/prefs/views/PaneLayoutPreferencesPane.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java index bee5275b321..b95ac5ff04a 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java @@ -530,9 +530,16 @@ else if (panes.get(3).equals(PaneManager.CONSOLE_PANE)) additionalColumnCount_ = paneManager_.syncAdditionalColumnCount(displayColumnCount_, true); + // Preserve existing sidebar settings + PaneConfig currentConfig = userPrefs_.panes().getGlobalValue().cast(); + JsArrayString sidebarTabs = currentConfig.getSidebar(); + boolean sidebarVisible = currentConfig.getSidebarVisible(); + String sidebarLocation = currentConfig.getSidebarLocation(); + userPrefs_.panes().setGlobalValue(PaneConfig.create( panes, tabSet1, tabSet2, hiddenTabSet, - consoleLeftOnTop, consoleRightOnTop, additionalColumnCount_)); + consoleLeftOnTop, consoleRightOnTop, additionalColumnCount_, + sidebarTabs, sidebarVisible, sidebarLocation)); dirty_ = false; } From 905e60ce4641b341e72908b01215d4f3907988fa Mon Sep 17 00:00:00 2001 From: Gary Ritchie Date: Thu, 11 Sep 2025 14:31:28 -0600 Subject: [PATCH 14/14] handle tabs assigned to sidebar when saving layout prefs --- .../views/PaneLayoutPreferencesPane.java | 75 ++++++++++++++----- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java index b95ac5ff04a..ebf003310cd 100644 --- a/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java +++ b/src/gwt/src/org/rstudio/studio/client/workbench/prefs/views/PaneLayoutPreferencesPane.java @@ -79,7 +79,7 @@ public void onChange(ChangeEvent event) private Integer notSelectedIndex() { - boolean[] seen = new boolean[4]; + boolean[] seen = new boolean[5]; // Updated to 5 to include Sidebar for (ListBox listBox : lists_) seen[listBox.getSelectedIndex()] = true; for (int i = 0; i < seen.length; i++) @@ -242,6 +242,10 @@ public PaneLayoutPreferencesPane(PreferencesDialogResources res, add(columnToolbar); String[] visiblePanes = PaneConfig.getVisiblePanes(); + // Add Sidebar to the list of visible panes + String[] visiblePanesWithSidebar = new String[visiblePanes.length + 1]; + System.arraycopy(visiblePanes, 0, visiblePanesWithSidebar, 0, visiblePanes.length); + visiblePanesWithSidebar[visiblePanes.length] = "Sidebar"; leftTop_ = new ListBox(); Roles.getListboxRole().setAriaLabelProperty(leftTop_.getElement(), "Top left panel"); @@ -254,7 +258,7 @@ public PaneLayoutPreferencesPane(PreferencesDialogResources res, visiblePanes_ = new ListBox[]{leftTop_, leftBottom_, rightTop_, rightBottom_}; for (ListBox lb : visiblePanes_) { - for (String value : visiblePanes) + for (String value : visiblePanesWithSidebar) lb.addItem(value); } @@ -290,6 +294,8 @@ public PaneLayoutPreferencesPane(PreferencesDialogResources res, tabSet1ModuleList_.setValue(toArrayList(userPrefs.panes().getGlobalValue().getTabSet1())); tabSet2ModuleList_ = new ModuleList(paneWidth); tabSet2ModuleList_.setValue(toArrayList(userPrefs.panes().getGlobalValue().getTabSet2())); + sidebarModuleList_ = new ModuleList(paneWidth); + sidebarModuleList_.setValue(toArrayList(userPrefs.panes().getGlobalValue().getSidebar())); hiddenTabSetModuleList_ = new ModuleList(paneWidth); hiddenTabSetModuleList_.setValue(toArrayList( userPrefs.panes().getGlobalValue().getHiddenTabSet())); @@ -301,35 +307,57 @@ public void onValueChange(ValueChangeEvent> e) dirty_ = true; ModuleList source = (ModuleList) e.getSource(); - ModuleList other = (source == tabSet1ModuleList_) - ? tabSet2ModuleList_ - : tabSet1ModuleList_; - - // an index should only be on for one of these lists, ArrayList indices = source.getSelectedIndices(); - ArrayList otherIndices = other.getSelectedIndices(); + ArrayList tabSet1Indices = tabSet1ModuleList_.getSelectedIndices(); + ArrayList tabSet2Indices = tabSet2ModuleList_.getSelectedIndices(); + ArrayList sidebarIndices = sidebarModuleList_.getSelectedIndices(); ArrayList hiddenIndices = hiddenTabSetModuleList_.getSelectedIndices(); + if (!PaneConfig.isValidConfig(source.getValue())) { // when the configuration is invalid, we must reset sources to the prior valid - // configuration based on the values of the other two lists + // configuration based on the values of the other lists for (int i = 0; i < indices.size(); i++) - indices.set(i, !(otherIndices.get(i) || hiddenIndices.get(i))); + { + if (source == tabSet1ModuleList_) + indices.set(i, !(tabSet2Indices.get(i) || sidebarIndices.get(i) || hiddenIndices.get(i))); + else if (source == tabSet2ModuleList_) + indices.set(i, !(tabSet1Indices.get(i) || sidebarIndices.get(i) || hiddenIndices.get(i))); + else if (source == sidebarModuleList_) + indices.set(i, !(tabSet1Indices.get(i) || tabSet2Indices.get(i) || hiddenIndices.get(i))); + } source.setSelectedIndices(indices); } else { + // Ensure 4-way exclusivity: a tab can only be in one of the four lists for (int i = 0; i < indices.size(); i++) { if (indices.get(i)) { - otherIndices.set(i, false); + // Clear this index from all other lists + if (source != tabSet1ModuleList_) + tabSet1Indices.set(i, false); + if (source != tabSet2ModuleList_) + tabSet2Indices.set(i, false); + if (source != sidebarModuleList_) + sidebarIndices.set(i, false); hiddenIndices.set(i, false); } - else if (!otherIndices.get(i)) - hiddenIndices.set(i, true); + else if (source != hiddenTabSetModuleList_) + { + // If unchecked and not in any other list, put in hidden + if (!tabSet1Indices.get(i) && !tabSet2Indices.get(i) && !sidebarIndices.get(i)) + hiddenIndices.set(i, true); + } } - other.setSelectedIndices(otherIndices); + + if (source != tabSet1ModuleList_) + tabSet1ModuleList_.setSelectedIndices(tabSet1Indices); + if (source != tabSet2ModuleList_) + tabSet2ModuleList_.setSelectedIndices(tabSet2Indices); + if (source != sidebarModuleList_) + sidebarModuleList_.setSelectedIndices(sidebarIndices); hiddenTabSetModuleList_.setSelectedIndices(hiddenIndices); updateTabSetLabels(); @@ -338,6 +366,7 @@ else if (!otherIndices.get(i)) }; tabSet1ModuleList_.addValueChangeHandler(vch); tabSet2ModuleList_.addValueChangeHandler(vch); + sidebarModuleList_.addValueChangeHandler(vch); updateTabSetPositions(); updateTabSetLabels(); @@ -434,6 +463,7 @@ private String updateTable(int newCount) grid_.getCellFormatter().setWidth(0, i, columnWidth); tabSet1ModuleList_.setWidth(cellWidth); tabSet2ModuleList_.setWidth(cellWidth); + sidebarModuleList_.setWidth(cellWidth); return cellWidth; } @@ -506,6 +536,10 @@ public RestartRequirement onApply(UserPrefs rPrefs) for (String tab : tabSet2ModuleList_.getValue()) tabSet2.push(tab); + JsArrayString sidebar = JsArrayString.createArray().cast(); + for (String tab : sidebarModuleList_.getValue()) + sidebar.push(tab); + JsArrayString hiddenTabSet = JsArrayString.createArray().cast(); for (String tab : hiddenTabSetModuleList_.getValue()) hiddenTabSet.push(tab); @@ -530,16 +564,15 @@ else if (panes.get(3).equals(PaneManager.CONSOLE_PANE)) additionalColumnCount_ = paneManager_.syncAdditionalColumnCount(displayColumnCount_, true); - // Preserve existing sidebar settings + // Get current sidebar visibility and location settings PaneConfig currentConfig = userPrefs_.panes().getGlobalValue().cast(); - JsArrayString sidebarTabs = currentConfig.getSidebar(); boolean sidebarVisible = currentConfig.getSidebarVisible(); String sidebarLocation = currentConfig.getSidebarLocation(); userPrefs_.panes().setGlobalValue(PaneConfig.create( panes, tabSet1, tabSet2, hiddenTabSet, consoleLeftOnTop, consoleRightOnTop, additionalColumnCount_, - sidebarTabs, sidebarVisible, sidebarLocation)); + sidebar, sidebarVisible, sidebarLocation)); dirty_ = false; } @@ -562,6 +595,8 @@ private void updateTabSetPositions() visiblePanePanels_[i].add(tabSet1ModuleList_); else if (StringUtil.equals(value, UserPrefsAccessor.Panes.QUADRANTS_TABSET2)) visiblePanePanels_[i].add(tabSet2ModuleList_); + else if (StringUtil.equals(value, "Sidebar")) + visiblePanePanels_[i].add(sidebarModuleList_); } } @@ -572,7 +607,9 @@ private void updateTabSetLabels() String itemText1 = tabSet1ModuleList_.getValue().isEmpty() ? "TabSet" : StringUtil.join(tabSet1ModuleList_.getValue(), ", "); String itemText2 = tabSet2ModuleList_.getValue().isEmpty() ? - "TabSet" : StringUtil.join(tabSet2ModuleList_.getValue(), ", "); + "TabSet" : StringUtil.join(tabSet2ModuleList_.getValue(), ", "); + String itemTextSidebar = sidebarModuleList_.getValue().isEmpty() ? + "Sidebar" : StringUtil.join(sidebarModuleList_.getValue(), ", "); if (StringUtil.equals(itemText1, "Presentation") && !tabSet1ModuleList_.presentationVisible()) itemText1 = "TabSet"; @@ -580,6 +617,7 @@ private void updateTabSetLabels() { pane.setItemText(2, itemText1); pane.setItemText(3, itemText2); + pane.setItemText(4, itemTextSidebar); } } @@ -601,6 +639,7 @@ private ArrayList toArrayList(JsArrayString strings) private final VerticalPanel[] visiblePanePanels_; private final ModuleList tabSet1ModuleList_; private final ModuleList tabSet2ModuleList_; + private final ModuleList sidebarModuleList_; private final ModuleList hiddenTabSetModuleList_; private final PaneManager paneManager_; private boolean dirty_ = false;