Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ public class WorkbenchWindow implements IWorkbenchWindow {

private boolean shellActivated = false;

private boolean destroyed;

ProgressRegion progressRegion = null;

private final List<MTrimElement> workbenchTrimElements = new ArrayList<>();
Expand Down Expand Up @@ -467,26 +469,9 @@ public void setup() {
final IEclipseContext windowContext = model.getContext();
HandlerServiceImpl.push(windowContext.getParent(), null);

// Initialize a previous 'saved' state if applicable. We no longer
// update the preference store.
if (getModel().getPersistedState().containsKey(IPreferenceConstants.COOLBAR_VISIBLE)) {
this.coolBarVisible = Boolean
.parseBoolean(getModel().getPersistedState().get(IPreferenceConstants.COOLBAR_VISIBLE));
} else {
this.coolBarVisible = PrefUtil.getInternalPreferenceStore()
.getBoolean(IPreferenceConstants.COOLBAR_VISIBLE);
getModel().getPersistedState().put(IPreferenceConstants.COOLBAR_VISIBLE,
Boolean.toString(this.coolBarVisible));
}
if (getModel().getPersistedState().containsKey(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE)) {
this.perspectiveBarVisible = Boolean
.parseBoolean(getModel().getPersistedState().get(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE));
} else {
this.perspectiveBarVisible = PrefUtil.getInternalPreferenceStore()
.getBoolean(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE);
getModel().getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE,
Boolean.toString(this.perspectiveBarVisible));
}
this.coolBarVisible = resolveTrimVisibility(IPreferenceConstants.COOLBAR_VISIBLE);
this.perspectiveBarVisible = resolveTrimVisibility(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE);
PrefUtil.getInternalPreferenceStore().addPropertyChangeListener(trimVisibilityListener);

IServiceLocatorCreator slc = workbench.getService(IServiceLocatorCreator.class);
this.serviceLocator = (ServiceLocator) slc.createServiceLocator(workbench, null, () -> {
Expand Down Expand Up @@ -972,6 +957,8 @@ private void addZoomChangeListenerToPromptForRestart() {

@PreDestroy
void preDestroy() {
destroyed = true;
PrefUtil.getInternalPreferenceStore().removePropertyChangeListener(trimVisibilityListener);
if (mainMenu != null) {
renderer.clearModelToManager(mainMenu, menuManager);
mainMenu = null;
Expand Down Expand Up @@ -1516,6 +1503,10 @@ protected int perspectiveBarStyle() {

private boolean statusLineVisible = true;

private static final String TRIM_OVERRIDE_SUFFIX = ".override"; //$NON-NLS-1$

private final IPropertyChangeListener trimVisibilityListener = this::preferredTrimVisibilityChanged;

/**
* The handlers for global actions that were last submitted to the workbench
* command support. This is a map of command identifiers to
Expand Down Expand Up @@ -2783,14 +2774,21 @@ public void fillActionBars(IActionBarConfigurer2 proxyBars, int flags) {
* @since 3.0
*/
public void setCoolBarVisible(boolean visible) {
if (applyCoolBarVisible(visible)) {
recordTrimOverride(IPreferenceConstants.COOLBAR_VISIBLE, visible);
}
}

private boolean applyCoolBarVisible(boolean visible) {
boolean oldValue = coolBarVisible;
coolBarVisible = visible;
if (oldValue != coolBarVisible) {
getModel().getPersistedState().put(IPreferenceConstants.COOLBAR_VISIBLE, Boolean.toString(visible));
updateLayoutDataForContents();
firePropertyChanged(PROP_COOLBAR_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
coolBarVisible ? Boolean.TRUE : Boolean.FALSE);
if (oldValue == coolBarVisible) {
return false;
}
updateLayoutDataForContents();
firePropertyChanged(PROP_COOLBAR_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
coolBarVisible ? Boolean.TRUE : Boolean.FALSE);
return true;
}

/**
Expand Down Expand Up @@ -2821,14 +2819,21 @@ public ActionPresentation getActionPresentation() {
* @since 3.0
*/
public void setPerspectiveBarVisible(boolean visible) {
if (applyPerspectiveBarVisible(visible)) {
recordTrimOverride(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE, visible);
}
}

private boolean applyPerspectiveBarVisible(boolean visible) {
boolean oldValue = perspectiveBarVisible;
perspectiveBarVisible = visible;
if (oldValue != perspectiveBarVisible) {
getModel().getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE, Boolean.toString(visible));
updateLayoutDataForContents();
firePropertyChanged(PROP_PERSPECTIVEBAR_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
perspectiveBarVisible ? Boolean.TRUE : Boolean.FALSE);
if (oldValue == perspectiveBarVisible) {
return false;
}
updateLayoutDataForContents();
firePropertyChanged(PROP_PERSPECTIVEBAR_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
perspectiveBarVisible ? Boolean.TRUE : Boolean.FALSE);
return true;
}

/**
Expand Down Expand Up @@ -2959,6 +2964,10 @@ public void toggleToolbarVisibility() {
if (getWindowConfigurer().getShowPerspectiveBar()) {
setPerspectiveBarVisible(!perspectivebarVisible);
}
refreshToggleToolbarElements();
}

private void refreshToggleToolbarElements() {
ICommandService commandService = getService(ICommandService.class);
Map<String, WorkbenchWindow> filter = new HashMap<>();
filter.put(IServiceScopes.WINDOW_SCOPE, this);
Expand All @@ -2977,6 +2986,64 @@ public boolean isToolbarVisible() {
|| (getPerspectiveBarVisible() && getWindowConfigurer().getShowPerspectiveBar());
}

/**
* Returns the per-window override of a trim element, or the workspace
* preference, after migrating a value persisted by older versions.
*/
private boolean resolveTrimVisibility(String key) {
Map<String, String> state = getModel().getPersistedState();
String overrideKey = key + TRIM_OVERRIDE_SUFFIX;
// older versions copied the preference here, so only a hidden bar was a user choice
String legacy = state.remove(key);
if (legacy != null && !Boolean.parseBoolean(legacy)) {
state.putIfAbsent(overrideKey, legacy);
}
String override = state.get(overrideKey);
if (override == null) {
return PrefUtil.getInternalPreferenceStore().getBoolean(key);
}
return Boolean.parseBoolean(override);
}

/**
* Stores a per-window choice, or removes it when it equals the preference.
*/
private void recordTrimOverride(String key, boolean visible) {
String overrideKey = key + TRIM_OVERRIDE_SUFFIX;
if (visible == PrefUtil.getInternalPreferenceStore().getBoolean(key)) {
getModel().getPersistedState().remove(overrideKey);
} else {
getModel().getPersistedState().put(overrideKey, Boolean.toString(visible));
}
}

/**
* Follows preference changes, for example from a theme.
*/
private void preferredTrimVisibilityChanged(PropertyChangeEvent event) {
String key = event.getProperty();
if (!IPreferenceConstants.COOLBAR_VISIBLE.equals(key)
&& !IPreferenceConstants.PERSPECTIVEBAR_VISIBLE.equals(key)) {
return;
}
Display display = workbench.getDisplay();
if (display == null || display.isDisposed()) {
return;
}
display.asyncExec(() -> {
Shell shell = getShell();
if (destroyed || closing || (shell != null && shell.isDisposed())) {
return;
}
boolean visible = resolveTrimVisibility(key);
boolean changed = IPreferenceConstants.COOLBAR_VISIBLE.equals(key) ? applyCoolBarVisible(visible)
: applyPerspectiveBarVisible(visible);
if (changed) {
refreshToggleToolbarElements();
}
});
}

private void updateLayoutDataForContents() {
MTrimBar topTrim = getTopTrim();
if (topTrim != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
MarkerQueryTest.class,
Bug99858Test.class,
WorkbenchWindowSubordinateSourcesTests.class,
TrimVisibilityPreferenceTest.class,
ReopenMenuTest.class,
UtilTest.class,
MarkerTesterTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*******************************************************************************
* Copyright (c) 2026 Vogella GmbH and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lars Vogel <Lars.Vogel@vogella.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.tests.internal;

import static org.eclipse.ui.tests.harness.util.UITestUtil.openTestWindow;
import static org.eclipse.ui.tests.harness.util.UITestUtil.processEvents;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.internal.IPreferenceConstants;
import org.eclipse.ui.internal.WorkbenchWindow;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.tests.harness.util.CloseTestWindowsExtension;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

/**
* Tests that the toolbar and perspective bar follow their workspace preferences
* unless a window carries an override.
*/
@ExtendWith(CloseTestWindowsExtension.class)
public class TrimVisibilityPreferenceTest {

private static final String KEY = IPreferenceConstants.COOLBAR_VISIBLE;

private static final String OVERRIDE_KEY = KEY + ".override";

private static final String PERSPECTIVE_BAR_KEY = IPreferenceConstants.PERSPECTIVEBAR_VISIBLE;

private static final String PERSPECTIVE_BAR_OVERRIDE_KEY = PERSPECTIVE_BAR_KEY + ".override";

private WorkbenchWindow window;

private IPreferenceStore preferences;

@BeforeEach
public void setUp() throws Exception {
preferences = PrefUtil.getInternalPreferenceStore();
preferences.setToDefault(KEY);
preferences.setToDefault(PERSPECTIVE_BAR_KEY);
window = (WorkbenchWindow) openTestWindow();
processEvents();
}

@AfterEach
public void tearDown() {
preferences.setToDefault(KEY);
preferences.setToDefault(PERSPECTIVE_BAR_KEY);
processEvents();
}

@Test
public void testWindowWithoutOverrideFollowsPreference() {
assertFalse(persistedState().containsKey(OVERRIDE_KEY), "a fresh window must not pin the value");
assertTrue(window.getCoolBarVisible());
List<String> events = new ArrayList<>();
window.addPropertyChangeListener(event -> events.add(event.getProperty()));

preferences.setValue(KEY, false);
processEvents();

assertFalse(window.getCoolBarVisible());
assertEquals(List.of(WorkbenchWindow.PROP_COOLBAR_VISIBLE), events);
assertFalse(persistedState().containsKey(OVERRIDE_KEY), "following the preference must not create an override");
}

@Test
public void testTogglingAwayFromPreferenceStoresOverride() {
window.setCoolBarVisible(false);

assertEquals(Boolean.FALSE.toString(), persistedState().get(OVERRIDE_KEY));
assertFalse(window.getCoolBarVisible());
}

@Test
public void testTogglingBackToPreferenceDropsOverride() {
window.setCoolBarVisible(false);
assertEquals(Boolean.FALSE.toString(), persistedState().get(OVERRIDE_KEY));

window.setCoolBarVisible(true);

assertFalse(persistedState().containsKey(OVERRIDE_KEY), "an override equal to the preference must be dropped");
}

@Test
public void testOverrideSurvivesPreferenceRoundTrip() {
window.setCoolBarVisible(false);

preferences.setValue(KEY, false);
processEvents();
preferences.setValue(KEY, true);
processEvents();

assertFalse(window.getCoolBarVisible(), "a per-window choice must outlive preference changes");
assertEquals(Boolean.FALSE.toString(), persistedState().get(OVERRIDE_KEY));
}

@Test
public void testPerspectiveBarFollowsPreference() {
assertTrue(window.getPerspectiveBarVisible());

preferences.setValue(PERSPECTIVE_BAR_KEY, false);
processEvents();

assertFalse(window.getPerspectiveBarVisible());
assertFalse(persistedState().containsKey(PERSPECTIVE_BAR_OVERRIDE_KEY));

window.setPerspectiveBarVisible(true);

assertEquals(Boolean.TRUE.toString(), persistedState().get(PERSPECTIVE_BAR_OVERRIDE_KEY));
}

@Test
public void testLegacyVisibleSnapshotDoesNotPinWindow() {
persistedState().put(KEY, Boolean.TRUE.toString());

preferences.setValue(KEY, false);
processEvents();

assertFalse(window.getCoolBarVisible(), "a copied preference must not act as an override");
assertFalse(persistedState().containsKey(KEY));
assertFalse(persistedState().containsKey(OVERRIDE_KEY));
}

@Test
public void testLegacyHiddenSnapshotBecomesOverride() {
persistedState().put(KEY, Boolean.FALSE.toString());

// an unchanged value, only to make the window read its persisted state again
preferences.firePropertyChangeEvent(KEY, Boolean.TRUE, Boolean.TRUE);
processEvents();

assertFalse(window.getCoolBarVisible(), "a hidden bar was a user choice and must stay hidden");
assertFalse(persistedState().containsKey(KEY));
assertEquals(Boolean.FALSE.toString(), persistedState().get(OVERRIDE_KEY));
}

private Map<String, String> persistedState() {
return window.getModel().getPersistedState();
}
}
Loading