Bug 388476 - [EditorMgmt] Editor tab management lost "working set" (MRU)
functionality

Introduced global switch to control if CSS (themes) or preferences
(user) are controlling the MRU functionality. Per default MRU behavior
is controlled by preferences now, independently what the CSS themes
says, so that switching CSS themes does not affect the actual MRU value.

3 preferences for the "org.eclipse.e4.ui.workbench.renderers.swt"
instance are added:

 - "mruControlledByCSS":  if the "most recently used" behavior should be
controlled via CSS or preferences. Default will be "false" now.

 - "enableMruDefault": what should be considered as default MRU value if
this is controlled by preferences. Default will be "true" now.

 - "enableMru": what should be considered as actual MRU value. This
preference can be changed by user if the "mruControlledByCSS" is
"false".

Only the last preference is exposed to users by new "Enable most
recently used order for tab placement" checkbox on the
"General->Appearance" page. The default value is "true" and corresponds
to the "enableMruDefault" preference above. If "mruControlledByCSS" is
"true", this checkbox is not visible to user.

Important: if product owners want to keep on current behavior, they can
revert the effect of all proposed changes by specifying
"mruControlledByCSS=true" in the  plugin_customization.ini.

For details on proposed solution see bug 388476 comment 120.

Change-Id: Ie1b08df20aa60f52ef500ff7bda49b9b18c1ddbb
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.e4.ui.css.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.css.swt/META-INF/MANIFEST.MF
index efcfccf..a85d293 100644
--- a/bundles/org.eclipse.e4.ui.css.swt/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.css.swt/META-INF/MANIFEST.MF
@@ -16,7 +16,7 @@
  org.eclipse.e4.ui.css.swt.properties;x-friends:="org.eclipse.ui.workbench",
  org.eclipse.e4.ui.css.swt.properties.converters;x-internal:=true,
  org.eclipse.e4.ui.css.swt.properties.css2;x-internal:=true,
- org.eclipse.e4.ui.css.swt.properties.custom;x-internal:=true,
+ org.eclipse.e4.ui.css.swt.properties.custom;x-friends:="org.eclipse.e4.ui.workbench.renderers.swt",
  org.eclipse.e4.ui.css.swt.properties.definition;x-internal:=true,
  org.eclipse.e4.ui.css.swt.properties.preference;x-internal:=true,
  org.eclipse.e4.ui.css.swt.resources;x-internal:=true,
diff --git a/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/properties/custom/CSSPropertyMruVisibleSWTHandler.java b/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/properties/custom/CSSPropertyMruVisibleSWTHandler.java
index c1fa0f9..902c19b 100644
--- a/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/properties/custom/CSSPropertyMruVisibleSWTHandler.java
+++ b/bundles/org.eclipse.e4.ui.css.swt/src/org/eclipse/e4/ui/css/swt/properties/custom/CSSPropertyMruVisibleSWTHandler.java
@@ -1,10 +1,12 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2012 IBM Corporation and others. All rights reserved. This
+ * Copyright (c) 2009, 2015 IBM Corporation and others. All rights reserved. This
  * program and the accompanying materials are made available under the terms of
  * the Eclipse Public License v1.0 which accompanies this distribution, and is
  * available at http://www.eclipse.org/legal/epl-v10.html
- * 
- * Contributors: IBM Corporation - initial API and implementation
+ *
+ * Contributors:
+ * 		IBM Corporation - initial API and implementation
+ * 		Andrey Loskutov <loskutov@gmx.de> - Bug 388476
  *******************************************************************************/
 package org.eclipse.e4.ui.css.swt.properties.custom;
 
@@ -18,10 +20,15 @@
 public class CSSPropertyMruVisibleSWTHandler extends AbstractCSSPropertySWTHandler{
 
 	public static final ICSSPropertyHandler INSTANCE = new CSSPropertyMruVisibleSWTHandler();
-	
+
+	private static boolean mruControlledByCSS = true;
+
 	@Override
 	public void applyCSSProperty(Control control, String property,
-		    CSSValue value, String pseudo, CSSEngine engine) throws Exception {
+			CSSValue value, String pseudo, CSSEngine engine) throws Exception {
+		if (!isMRUControlledByCSS()) {
+			return;
+		}
 		boolean isMruVisible = (Boolean)engine.convert(value, Boolean.class, null);
 		if (control instanceof CTabFolder) {
 			CTabFolder folder = (CTabFolder) control;
@@ -39,5 +46,11 @@
 		return null;
 	}
 
+	public static boolean isMRUControlledByCSS() {
+		return mruControlledByCSS;
+	}
 
+	public static void setMRUControlledByCSS(boolean controlledByCSS) {
+		mruControlledByCSS = controlledByCSS;
+	}
 }
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
index 8a9cb0e..a4648e9 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
@@ -25,7 +25,9 @@
  org.eclipse.osgi;bundle-version="[3.6.0,4.0.0)",
  org.eclipse.e4.ui.di;bundle-version="0.9.0",
  org.eclipse.emf.ecore;bundle-version="2.7.0",
- org.eclipse.e4.ui.css.swt;bundle-version="0.11.0"
+ org.eclipse.e4.ui.css.swt;bundle-version="0.11.0",
+ org.eclipse.e4.core.di.extensions;bundle-version="0.12.0",
+ org.eclipse.equinox.preferences;bundle-version="3.5.200"
 Export-Package: org.eclipse.e4.ui.internal.workbench.renderers.swt;x-friends:="org.eclipse.ui.workbench",
  org.eclipse.e4.ui.workbench.renderers.swt;x-friends:="org.eclipse.e4.ui.workbench.addons.swt,org.eclipse.ui.workbench"
 Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
index af7870f..14f8aba 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/StackRenderer.java
@@ -8,7 +8,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 429728, 430166, 441150, 442285
- *     Andrey Loskutov <loskutov@gmx.de> - Bug 337588
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 337588, 388476
  *******************************************************************************/
 package org.eclipse.e4.ui.workbench.renderers.swt;
 
@@ -21,10 +21,15 @@
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Named;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.di.extensions.Preference;
 import org.eclipse.e4.core.services.events.IEventBroker;
 import org.eclipse.e4.ui.css.swt.dom.WidgetElement;
+import org.eclipse.e4.ui.css.swt.properties.custom.CSSPropertyMruVisibleSWTHandler;
 import org.eclipse.e4.ui.di.UIEventTopic;
 import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
 import org.eclipse.e4.ui.internal.workbench.renderers.swt.BasicPartList;
@@ -64,6 +69,8 @@
 import org.eclipse.swt.custom.CTabFolder2Adapter;
 import org.eclipse.swt.custom.CTabFolderEvent;
 import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.MenuDetectEvent;
@@ -106,12 +113,44 @@
  * IPresentation.STYLE_OVERRIDE_KEY key
  *
  */
-public class StackRenderer extends LazyStackRenderer {
+public class StackRenderer extends LazyStackRenderer implements IPreferenceChangeListener {
 	/**
 	 *
 	 */
 	private static final String THE_PART_KEY = "thePart"; //$NON-NLS-1$
 
+	/**
+	 * Key to control the default default value of the "most recently used"
+	 * order enablement
+	 */
+	public static final String MRU_KEY_DEFAULT = "enableMRUDefault"; //$NON-NLS-1$
+
+	/**
+	 * Key to control the actual boolean preference of the "most recently used"
+	 * order enablement
+	 */
+	public static final String MRU_KEY = "enableMRU"; //$NON-NLS-1$
+
+	/**
+	 * Key to switch if the "most recently used" behavior controlled via CSS or
+	 * preferences
+	 */
+	public static final String MRU_CONTROLLED_BY_CSS_KEY = "MRUControlledByCSS"; //$NON-NLS-1$
+
+	/*
+	 * org.eclipse.ui.internal.dialogs.ViewsPreferencePage controls currently
+	 * the MRU behavior via IEclipsePreferences, so that CSS values from the
+	 * themes aren't used.
+	 *
+	 * TODO once we can use preferences from CSS (and update the value on the
+	 * fly) we can switch this default to true, see discussion on bug 388476.
+	 */
+	private static final boolean MRU_CONTROLLED_BY_CSS_DEFAULT = false;
+
+	@Inject
+	@Preference(nodePath = "org.eclipse.e4.ui.workbench.renderers.swt")
+	private IEclipsePreferences preferences;
+
 	@Inject
 	@Named(WorkbenchRendererFactory.SHARED_ELEMENTS_STORE)
 	Map<MUIElement, Set<MPlaceholder>> renderedMap;
@@ -162,7 +201,7 @@
 	// Manages CSS styling based on active part changes
 	private EventHandler stylingHandler;
 
-	private boolean ignoreTabSelChanges = false;
+	private boolean ignoreTabSelChanges;
 
 	List<CTabItem> getItemsToSet(MPart part) {
 		List<CTabItem> itemsToSet = new ArrayList<CTabItem>();
@@ -305,6 +344,9 @@
 	public void init() {
 		super.init(eventBroker);
 
+		preferences.addPreferenceChangeListener(this);
+		preferenceChange(null);
+
 		// TODO: Refactor using findItemForPart(MPart) method
 		itemUpdater = new EventHandler() {
 			@Override
@@ -583,7 +625,7 @@
 		int styleOverride = getStyleOverride(pStack);
 		int style = styleOverride == -1 ? SWT.BORDER : styleOverride;
 		final CTabFolder ctf = new CTabFolder(parentComposite, style);
-		ctf.setMRUVisible(getInitialMRUValue(ctf));
+		ctf.setMRUVisible(getMRUValue(ctf));
 
 		// Adjust the minimum chars based on the location
 		int location = modelService.getElementLocation(element);
@@ -604,10 +646,10 @@
 	}
 
 	private boolean getInitialMRUValue(Control control) {
-		boolean result = false;
 		CSSRenderingUtils util = context.get(CSSRenderingUtils.class);
-		if (util == null)
-			return result;
+		if (util == null) {
+			return getMRUValueFromPreferences();
+		}
 
 		CSSValue value = util.getCSSValue(control,
 				"MPartStack", "swt-mru-visible"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -615,12 +657,36 @@
 		if (value == null) {
 			value = util.getCSSValue(control, "MPartStack", "mru-visible"); //$NON-NLS-1$ //$NON-NLS-2$
 		}
-		if (value == null)
-			return result;
-
+		if (value == null) {
+			return getMRUValueFromPreferences();
+		}
 		return Boolean.parseBoolean(value.getCssText());
 	}
 
+	private boolean getMRUValue(Control control) {
+		if (CSSPropertyMruVisibleSWTHandler.isMRUControlledByCSS()) {
+			return getInitialMRUValue(control);
+		}
+		return getMRUValueFromPreferences();
+	}
+
+	private boolean getMRUValueFromPreferences() {
+		boolean initialMRUValue = preferences.getBoolean(MRU_KEY_DEFAULT, true);
+		boolean actualValue = preferences.getBoolean(MRU_KEY, initialMRUValue);
+		return actualValue;
+	}
+
+	private void updateMRUValue(CTabFolder ctf) {
+		boolean actualMRUValue = getMRUValue(ctf);
+		ctf.setMRUVisible(actualMRUValue);
+	}
+
+	@Override
+	public void preferenceChange(PreferenceChangeEvent event) {
+		boolean mruControlledByCSS = preferences.getBoolean(MRU_CONTROLLED_BY_CSS_KEY, MRU_CONTROLLED_BY_CSS_DEFAULT);
+		CSSPropertyMruVisibleSWTHandler.setMRUControlledByCSS(mruControlledByCSS);
+	}
+
 	/**
 	 * @param ctf
 	 */
@@ -765,6 +831,7 @@
 		} finally {
 			adjusting = false;
 		}
+		updateMRUValue(ctf);
 	}
 
 	@Override
@@ -787,7 +854,7 @@
 				cti.setControl((Control) element.getWidget());
 			return;
 		}
-
+		updateMRUValue(ctf);
 		int createFlags = SWT.NONE;
 		if (part != null && isClosable(part)) {
 			createFlags |= SWT.CLOSE;
@@ -1104,6 +1171,13 @@
 				}
 			}
 		});
+
+		ctf.addControlListener(new ControlAdapter() {
+			@Override
+			public void controlResized(ControlEvent e) {
+				updateMRUValue(ctf);
+			}
+		});
 	}
 
 	public void showAvailableItems(MElementContainer<?> stack, CTabFolder ctf) {
@@ -1111,7 +1185,7 @@
 		final BasicPartList editorList = new BasicPartList(ctf.getShell(),
 				SWT.ON_TOP, SWT.V_SCROLL | SWT.H_SCROLL,
 				ctxt.get(EPartService.class), stack, this,
-				getInitialMRUValue(ctf));
+                getMRUValueFromPreferences());
 		editorList.setInput();
 
 		Point size = editorList.computeSizeHint();
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchMessages.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchMessages.java
index e397c27..1f1bcac 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchMessages.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * Copyright (c) 2005, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
  * Tristan Hume - <trishume@gmail.com> -
  * 		Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
  * 		Implemented workbench auto-save to correctly restore state in case of crash.
+ * Andrey Loskutov <loskutov@gmx.de> - Bug 388476
  *******************************************************************************/
 package org.eclipse.ui.internal;
 
@@ -480,6 +481,7 @@
 	public static String ViewsPreference_currentThemeDescription;
 	public static String ViewsPreference_currentThemeFormat;
 	public static String ViewsPreference_enableAnimations;
+	public static String ViewsPreference_enableMRU;
 	public static String ViewsPreference_useColoredLabels;
 	// public static String ViewsPreference_override;
 	// public static String ViewsPreference_restartRequestJobName;
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java
index e3e2e40..484d41e 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/dialogs/ViewsPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
  *     IBM Corporation - initial API and implementation
  *     Erik Chou <ekchou@ymail.com> - Bug 425962
  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 445664, 442278
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 388476
  *******************************************************************************/
 
 package org.eclipse.ui.internal.dialogs;
@@ -27,11 +28,14 @@
 import org.eclipse.core.runtime.IExtensionPoint;
 import org.eclipse.core.runtime.IExtensionRegistry;
 import org.eclipse.core.runtime.RegistryFactory;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.ui.css.swt.theme.ITheme;
 import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
 import org.eclipse.e4.ui.internal.workbench.swt.E4Application;
 import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.fieldassist.ControlDecoration;
 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
@@ -68,6 +72,7 @@
 import org.eclipse.ui.internal.tweaklets.Tweaklets;
 import org.eclipse.ui.internal.util.PrefUtil;
 import org.eclipse.ui.themes.IThemeManager;
+import org.osgi.service.prefs.BackingStoreException;
 
 /**
  * The ViewsPreferencePage is the page used to set preferences for the
@@ -85,8 +90,9 @@
 	private ITheme currentTheme;
 	private String defaultTheme;
 	private Button enableAnimations;
+	private Button enableMru;
 	private Button useColoredLabels;
-	
+
 	private Text colorsAndFontsThemeDescriptionText;
 	private ComboViewer colorsAndFontsThemeCombo;
 	private ControlDecoration colorFontsDecorator;
@@ -99,13 +105,26 @@
 		initializeDialogUnits(parent);
 
 		Composite comp = new Composite(parent, SWT.NONE);
+
+		// if started with "-cssTheme none", CSS settings should be disabled
+		// but other appearance settings should be *not* disabled
+		if (engine == null) {
+			GridLayout layout = new GridLayout(1, false);
+			layout.horizontalSpacing = 10;
+			comp.setLayout(layout);
+			new Label(comp, SWT.NONE).setText(WorkbenchMessages.ThemingDisabled);
+			Label separator = new Label(comp, SWT.SEPARATOR | SWT.HORIZONTAL);
+			GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+			layoutData.verticalIndent = 20;
+			separator.setLayoutData(layoutData);
+			createThemeIndependentComposits(comp);
+			return comp;
+		}
+
 		GridLayout layout = new GridLayout(2, false);
 		layout.horizontalSpacing = 10;
 		comp.setLayout(layout);
-		if (engine == null) {
-			new Label(comp, SWT.NONE).setText(WorkbenchMessages.ThemingDisabled);
-			return comp;
-		}
+
 		new Label(comp, SWT.NONE).setText(WorkbenchMessages.ViewsPreferencePage_Theme);
 		highContrastMode = parent.getDisplay().getHighContrast();
 
@@ -152,8 +171,8 @@
 		currentColorsAndFontsTheme = getCurrentColorsAndFontsTheme();
 		createColorsAndFontsThemeCombo(comp);
 		createColorsAndFontsThemeDescriptionText(comp);
-		createEnableAnimationsPref(comp);
-		createColoredLabelsPref(comp);
+
+		createThemeIndependentComposits(comp);
 
 		((PreferencePageEnhancer) Tweaklets.get(PreferencePageEnhancer.KEY))
 				.setSelection(currentTheme);
@@ -172,6 +191,12 @@
 		return comp;
 	}
 
+	private void createThemeIndependentComposits(Composite comp) {
+		createEnableAnimationsPref(comp);
+		createColoredLabelsPref(comp);
+		createEnableMruPref(comp);
+	}
+
 	private List<ITheme> getCSSThemes(boolean highContrastMode) {
 		List<ITheme> themes = new ArrayList<ITheme>();
 		for (ITheme theme : engine.getThemes()) {
@@ -180,7 +205,7 @@
 			 * the platform, we display the 'high-contrast' special theme only.
 			 * If not, we don't want to mess the themes combo with the theme
 			 * since it is the special variation of the 'classic' one
-			 * 
+			 *
 			 * When we have GTK - we have to display the entire list of the
 			 * themes since we are not able to figure out if the high contrast
 			 * mode is enabled on the platform. The user has to manually select
@@ -212,6 +237,19 @@
 		return button;
 	}
 
+	protected void createEnableMruPref(Composite composite) {
+		IEclipsePreferences prefs = getSwtRendererPreferences();
+		if (engine != null) {
+			boolean mruControlledByCSS = prefs.getBoolean(StackRenderer.MRU_CONTROLLED_BY_CSS_KEY, false);
+			if (mruControlledByCSS) {
+				return;
+			}
+		}
+		boolean defaultValue = getDefaultMRUValue();
+		boolean actualValue = prefs.getBoolean(StackRenderer.MRU_KEY, defaultValue);
+		enableMru = createCheckButton(composite, WorkbenchMessages.ViewsPreference_enableMRU, actualValue);
+	}
+
 	protected void createEnableAnimationsPref(Composite composite) {
 		IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
 
@@ -240,17 +278,32 @@
 			if (theme != null) {
 				engine.setTheme(getSelectedTheme(), !highContrastMode);
 			}
+		}
+		IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
+		apiStore.setValue(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS, enableAnimations.getSelection());
+		apiStore.setValue(IWorkbenchPreferenceConstants.USE_COLORED_LABELS, useColoredLabels.getSelection());
+		((PreferencePageEnhancer) Tweaklets.get(PreferencePageEnhancer.KEY)).performOK();
 
-			IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
-			apiStore.setValue(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS,
-					enableAnimations.getSelection());
-			apiStore.setValue(IWorkbenchPreferenceConstants.USE_COLORED_LABELS,
-					useColoredLabels.getSelection());
-			((PreferencePageEnhancer) Tweaklets.get(PreferencePageEnhancer.KEY)).performOK();
+		if (enableMru != null) {
+			IEclipsePreferences prefs = getSwtRendererPreferences();
+			prefs.putBoolean(StackRenderer.MRU_KEY, enableMru.getSelection());
+			try {
+				prefs.flush();
+			} catch (BackingStoreException e) {
+				WorkbenchPlugin.log("Failed to set SWT renderer preferences", e); //$NON-NLS-1$
+			}
 		}
 		return super.performOk();
 	}
 
+	private IEclipsePreferences getSwtRendererPreferences() {
+		return InstanceScope.INSTANCE.getNode("org.eclipse.e4.ui.workbench.renderers.swt"); //$NON-NLS-1$
+	}
+
+	private boolean getDefaultMRUValue() {
+		return getSwtRendererPreferences().getBoolean(StackRenderer.MRU_KEY_DEFAULT, true);
+	}
+
 	private void setColorsAndFontsTheme(ColorsAndFontsTheme theme) {
 		org.eclipse.ui.themes.ITheme currentTheme = PlatformUI.getWorkbench().getThemeManager()
 				.getCurrentTheme();
@@ -269,11 +322,12 @@
 			if (engine.getActiveTheme() != null) {
 				themeIdCombo.setSelection(new StructuredSelection(engine.getActiveTheme()));
 			}
-			IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
-			enableAnimations.setSelection(apiStore
-					.getDefaultBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS));
-			useColoredLabels.setSelection(apiStore
-					.getDefaultBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS));
+		}
+		IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
+		enableAnimations.setSelection(apiStore.getDefaultBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS));
+		useColoredLabels.setSelection(apiStore.getDefaultBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS));
+		if (enableMru != null) {
+			enableMru.setSelection(getDefaultMRUValue());
 		}
 		super.performDefaults();
 	}
@@ -342,13 +396,13 @@
 				refreshColorsAndFontsThemeDescriptionText(colorsAndFontsTheme);
 				setColorsAndFontsTheme(colorsAndFontsTheme);
 			}
-		});		
+		});
 	}
 
 	/**
 	 * Create the text box that will contain the current theme description text
 	 * (if any).
-	 * 
+	 *
 	 * @param parent
 	 *            the parent <code>Composite</code>.
 	 */
@@ -452,7 +506,7 @@
 	private void refreshColorsAndFontsThemeDescriptionText(ColorsAndFontsTheme theme) {
 		String description = ""; //$NON-NLS-1$
 		IThemeDescriptor[] descs = WorkbenchPlugin.getDefault().getThemeRegistry().getThemes();
-		
+
 		for (int i = 0; theme != null && description == null && i < descs.length; i++) {
 			if (descs[i].getId().equals(theme.getId())) {
 				description = descs[i].getDescription();
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/messages.properties b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/messages.properties
index 65ed323..2aecbec 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/messages.properties
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/messages.properties
@@ -433,6 +433,7 @@
 ViewsPreference_currentThemeFormat = {0} (current)
 ViewsPreference_enableAnimations = &Enable animations
 ViewsPreference_useColoredLabels = Use mixe&d fonts and colors for labels
+ViewsPreference_enableMRU = Enable &most recently used order for tab placement
 #ViewsPreference_restartRequestJobName = Restart Request
 
 # --- File Editors ---
diff --git a/tests/org.eclipse.e4.ui.tests.css.swt/src/org/eclipse/e4/ui/tests/css/swt/CTabFolderTest.java b/tests/org.eclipse.e4.ui.tests.css.swt/src/org/eclipse/e4/ui/tests/css/swt/CTabFolderTest.java
index 357b4c9..d7e5c0b 100644
--- a/tests/org.eclipse.e4.ui.tests.css.swt/src/org/eclipse/e4/ui/tests/css/swt/CTabFolderTest.java
+++ b/tests/org.eclipse.e4.ui.tests.css.swt/src/org/eclipse/e4/ui/tests/css/swt/CTabFolderTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2014 IBM Corporation and others. All rights reserved. This
+ * Copyright (c) 2008, 2015 IBM Corporation and others. All rights reserved. This
  * program and the accompanying materials are made available under the terms of
  * the Eclipse Public License v1.0 which accompanies this distribution, and is
  * available at http://www.eclipse.org/legal/epl-v10.html
@@ -7,6 +7,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Thibault Le Ouay <thibaultleouay@gmail.com> - Bug 443094
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 388476
  *******************************************************************************/
 package org.eclipse.e4.ui.tests.css.swt;
 
@@ -14,6 +15,7 @@
 import static org.junit.Assert.assertNotSame;
 
 import org.eclipse.e4.ui.css.swt.dom.CTabFolderElement;
+import org.eclipse.e4.ui.css.swt.properties.custom.CSSPropertyMruVisibleSWTHandler;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.CTabFolder;
 import org.eclipse.swt.custom.CTabItem;
@@ -185,15 +187,40 @@
 		assertEquals("false", engine.retrieveCSSProperty(folderToTest, "minimize-visible", null));
 	}
 
+	@SuppressWarnings("restriction")
 	@Test
 	public void testMRUVisible() {
-		CTabFolder folderToTest = createTestCTabFolder("CTabFolder { mru-visible: true}");
-		assertEquals(true, folderToTest.getMRUVisible());
-		assertEquals("true", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
-		folderToTest.getShell().close();
-		folderToTest = createTestCTabFolder("CTabFolder { mru-visible: false}");
-		assertEquals("false", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
-		assertEquals(false, folderToTest.getMRUVisible());
+		final boolean mruControlledByCSSDefault = CSSPropertyMruVisibleSWTHandler.isMRUControlledByCSS();
+		try {
+			CSSPropertyMruVisibleSWTHandler.setMRUControlledByCSS(true);
+			CTabFolder folderToTest = createTestCTabFolder("CTabFolder { mru-visible: true}");
+			assertEquals(true, folderToTest.getMRUVisible());
+			assertEquals("true", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
+			folderToTest.getShell().close();
+			folderToTest = createTestCTabFolder("CTabFolder { mru-visible: false}");
+			assertEquals("false", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
+			assertEquals(false, folderToTest.getMRUVisible());
+		} finally {
+			CSSPropertyMruVisibleSWTHandler.setMRUControlledByCSS(mruControlledByCSSDefault);
+		}
+	}
+
+	@SuppressWarnings("restriction")
+	@Test
+	public void testMRUVisibleCSSControlOff() {
+		final boolean mruControlledByCSSDefault = CSSPropertyMruVisibleSWTHandler.isMRUControlledByCSS();
+		try {
+			CSSPropertyMruVisibleSWTHandler.setMRUControlledByCSS(false);
+			CTabFolder folderToTest = createTestCTabFolder("CTabFolder { mru-visible: true}");
+			assertEquals(false, folderToTest.getMRUVisible());
+			assertEquals("false", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
+			folderToTest.getShell().close();
+			folderToTest = createTestCTabFolder("CTabFolder { mru-visible: false}");
+			assertEquals("false", engine.retrieveCSSProperty(folderToTest, "mru-visible", null));
+			assertEquals(false, folderToTest.getMRUVisible());
+		} finally {
+			CSSPropertyMruVisibleSWTHandler.setMRUControlledByCSS(mruControlledByCSSDefault);
+		}
 	}
 
 	@Test