Committed Deepak's patch to fix bug 257313: [preferences][painting] More options to configure "Show Whitespace Characters"
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java
index f59ef41..4cf7b5c 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2009 Wind River Systems, Inc., IBM Corporation and others.
+ * Copyright (c) 2006, 2010 Wind River Systems, Inc., 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
@@ -46,6 +46,28 @@
 	private StyledText fTextWidget;
 	/** Tells whether the advanced graphics sub system is available. */
 	private final boolean fIsAdvancedGraphicsPresent;
+	/** @since 3.7 */
+	private boolean fShowLeadingSpaces= true;
+	/** @since 3.7 */
+	private boolean fShowEnclosedSpace= true;
+	/** @since 3.7 */
+	private boolean fShowTrailingSpaces= true;
+	/** @since 3.7 */
+	private boolean fShowLeadingIdeographicSpaces= true;
+	/** @since 3.7 */
+	private boolean fShowEnclosedIdeographicSpaces= true;
+	/** @since 3.7 */
+	private boolean fShowTrailingIdeographicSpaces= true;
+	/** @since 3.7 */
+	private boolean fShowLeadingTabs= true;
+	/** @since 3.7 */
+	private boolean fShowEnclosedTabs= true;
+	/** @since 3.7 */
+	private boolean fShowTrailingTabs= true;
+	/** @since 3.7 */
+	private boolean fShowCarriageReturn= true;
+	/** @since 3.7 */
+	private boolean fShowLineFeed= true;
 
 	/**
 	 * Creates a new painter for the given text viewer.
@@ -62,6 +84,40 @@
 		gc.dispose();
 	}
 
+	/**
+	 * Creates a new painter for the given text viewer and the painter options.
+	 * 
+	 * @param viewer the text viewer the painter should be attached to
+	 * @param showLeadingSpaces if <code>true</code>, show leading Spaces
+	 * @param showEnclosedSpaces if <code>true</code>, show enclosed Spaces
+	 * @param showTrailingSpaces if <code>true</code>, show trailing Spaces
+	 * @param showLeadingIdeographicSpaces if <code>true</code>, show leading Ideographic Spaces
+	 * @param showEnclosedIdeographicSpaces if <code>true</code>, show enclosed Ideographic Spaces
+	 * @param showTrailingIdeographicSpace if <code>true</code>, show trailing Ideographic Spaces
+	 * @param showLeadingTabs if <code>true</code>, show leading Tabs
+	 * @param showEnclosedTabs if <code>true</code>, show enclosed Tabs
+	 * @param showTrailingTabs if <code>true</code>, show trailing Tabs
+	 * @param showCarriageReturn if <code>true</code>, show Carriage Returns
+	 * @param showLineFeed if <code>true</code>, show Line Feeds
+	 * @since 3.7
+	 */
+	public WhitespaceCharacterPainter(ITextViewer viewer, boolean showLeadingSpaces, boolean showEnclosedSpaces, boolean showTrailingSpaces, boolean showLeadingIdeographicSpaces,
+			boolean showEnclosedIdeographicSpaces, boolean showTrailingIdeographicSpace, boolean showLeadingTabs,
+			boolean showEnclosedTabs, boolean showTrailingTabs, boolean showCarriageReturn, boolean showLineFeed) {
+		this(viewer);
+		fShowLeadingSpaces= showLeadingSpaces;
+		fShowEnclosedSpace= showEnclosedSpaces;
+		fShowTrailingSpaces= showTrailingSpaces;
+		fShowLeadingIdeographicSpaces= showLeadingIdeographicSpaces;
+		fShowEnclosedIdeographicSpaces= showEnclosedIdeographicSpaces;
+		fShowTrailingIdeographicSpaces= showTrailingIdeographicSpace;
+		fShowLeadingTabs= showLeadingTabs;
+		fShowEnclosedTabs= showEnclosedTabs;
+		fShowTrailingTabs= showTrailingTabs;
+		fShowCarriageReturn= showCarriageReturn;
+		fShowLineFeed= showLineFeed;
+	}
+
 	/*
 	 * @see org.eclipse.jface.text.IPainter#dispose()
 	 */
@@ -217,9 +273,13 @@
 		}
 	}
 
+	private boolean isWhitespaceCharacter(char c) {
+		return c == ' ' || c == '\u3000' || c == '\t' || c == '\r' || c == '\n';
+	}
+
 	/**
 	 * Draw characters of content range.
-	 *
+	 * 
 	 * @param gc the GC
 	 * @param startOffset inclusive start index
 	 * @param endOffset exclusive end index
@@ -228,6 +288,24 @@
 		StyledTextContent content= fTextWidget.getContent();
 		int length= endOffset - startOffset;
 		String text= content.getTextRange(startOffset, length);
+		int textBegin= -1;
+		for (int i= 0; i < text.length(); ++i) {
+			if (!isWhitespaceCharacter(text.charAt(i))) {
+				textBegin= i;
+				break;
+			}
+		}
+		boolean isEmptyLine= textBegin == -1;
+		int textEnd= text.length() - 1;
+		if (!isEmptyLine) {
+			for (int i= text.length() - 1; i >= 0; --i) {
+				if (!isWhitespaceCharacter(text.charAt(i))) {
+					textEnd= i;
+					break;
+				}
+			}
+		}
+
 		StyleRange styleRange= null;
 		Color fg= null;
 		StringBuffer visibleChar= new StringBuffer(10);
@@ -238,39 +316,91 @@
 				delta= 1;
 				char c= text.charAt(textOffset);
 				switch (c) {
-				case ' ' :
-					visibleChar.append(SPACE_SIGN);
-					// 'continue' would improve performance but may produce drawing errors
-					// for long runs of space if width of space and dot differ
-					break;
-				case '\u3000' : // ideographic whitespace
-					visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
-					// 'continue' would improve performance but may produce drawing errors
-					// for long runs of space if width of space and dot differ
-					break;
-				case '\t' :
-					visibleChar.append(TAB_SIGN);
-					break;
-				case '\r' :
-					visibleChar.append(CARRIAGE_RETURN_SIGN);
-					if (textOffset >= length - 1 || text.charAt(textOffset + 1) != '\n') {
+					case ' ':
+						if (isEmptyLine) {
+							if (fShowLeadingSpaces || fShowEnclosedSpace || fShowTrailingSpaces) {
+								visibleChar.append(SPACE_SIGN);
+							}
+						} else if (textOffset < textBegin) {
+							if (fShowLeadingSpaces) {
+								visibleChar.append(SPACE_SIGN);
+							}
+						} else if (textOffset < textEnd) {
+							if (fShowEnclosedSpace) {
+								visibleChar.append(SPACE_SIGN);
+							}
+						} else {
+							if (fShowTrailingSpaces) {
+								visibleChar.append(SPACE_SIGN);
+							}
+						}
+						// 'continue' would improve performance but may produce drawing errors
+						// for long runs of space if width of space and dot differ
+						break;
+					case '\u3000': // ideographic whitespace
+						if (isEmptyLine) {
+							if (fShowLeadingIdeographicSpaces || fShowEnclosedIdeographicSpaces || fShowTrailingIdeographicSpaces) {
+								visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
+							}
+						} else if (textOffset < textBegin) {
+							if (fShowLeadingIdeographicSpaces) {
+								visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
+							}
+						} else if (textOffset < textEnd) {
+							if (fShowEnclosedIdeographicSpaces) {
+								visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
+							}
+						} else {
+							if (fShowTrailingIdeographicSpaces) {
+								visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
+							}
+						}
+						// 'continue' would improve performance but may produce drawing errors
+						// for long runs of space if width of space and dot differ
+						break;
+					case '\t':
+						if (isEmptyLine) {
+							if (fShowLeadingTabs || fShowEnclosedTabs || fShowTrailingTabs) {
+								visibleChar.append(TAB_SIGN);
+							}
+						} else if (textOffset < textBegin) {
+							if (fShowLeadingTabs) {
+								visibleChar.append(TAB_SIGN);
+							}
+						} else if (textOffset < textEnd) {
+							if (fShowEnclosedTabs) {
+								visibleChar.append(TAB_SIGN);
+							}
+						} else {
+							if (fShowTrailingTabs) {
+								visibleChar.append(TAB_SIGN);
+							}
+						}
+						break;
+					case '\r':
+						if (fShowCarriageReturn) {
+							visibleChar.append(CARRIAGE_RETURN_SIGN);
+						}
+						if (textOffset >= length - 1 || text.charAt(textOffset + 1) != '\n') {
+							eol= true;
+							break;
+						}
+						continue;
+					case '\n':
+						if (fShowLineFeed) {
+							visibleChar.append(LINE_FEED_SIGN);
+						}
 						eol= true;
 						break;
-					}
-					continue;
-				case '\n' :
-					visibleChar.append(LINE_FEED_SIGN);
-					eol= true;
-					break;
-				default :
-					delta= 0;
-					break;
+					default:
+						delta= 0;
+						break;
 				}
 			}
 			if (visibleChar.length() > 0) {
 				int widgetOffset= startOffset + textOffset - visibleChar.length() + delta;
 				if (!eol || !isFoldedLine(content.getLineAtOffset(widgetOffset))) {
-					/* 
+					/*
 					 * Block selection is drawn using alpha and no selection-inverting
 					 * takes place, we always draw as 'unselected' in block selection mode.
 					 */
diff --git a/org.eclipse.ui.editors/META-INF/MANIFEST.MF b/org.eclipse.ui.editors/META-INF/MANIFEST.MF
index 72e49b0..1799bdd 100644
--- a/org.eclipse.ui.editors/META-INF/MANIFEST.MF
+++ b/org.eclipse.ui.editors/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ui.editors; singleton:=true
-Bundle-Version: 3.6.100.qualifier
+Bundle-Version: 3.7.0.qualifier
 Bundle-Activator: org.eclipse.ui.internal.editors.text.EditorsPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
@@ -18,8 +18,8 @@
  org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.ui.ide;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.ui;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.jface.text;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.ui.workbench.texteditor;bundle-version="[3.6.0,4.0.0)",
+ org.eclipse.jface.text;bundle-version="[3.7.0,4.0.0)",
+ org.eclipse.ui.workbench.texteditor;bundle-version="[3.7.0,4.0.0)",
  org.eclipse.core.filebuffers;visibility:=reexport;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)"
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorDefaultsPreferencePage.java b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorDefaultsPreferencePage.java
index 02cecbd..feced74 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorDefaultsPreferencePage.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorDefaultsPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 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
@@ -19,11 +19,19 @@
 import java.util.Set;
 
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
@@ -31,20 +39,24 @@
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Link;
 import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Spinner;
 import org.eclipse.swt.widgets.Text;
 
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IStatus;
 
+import org.eclipse.jface.action.LegacyActionTools;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.DialogPage;
 import org.eclipse.jface.dialogs.IMessageProvider;
 import org.eclipse.jface.layout.PixelConverter;
 import org.eclipse.jface.preference.ColorSelector;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferenceConverter;
 import org.eclipse.jface.preference.PreferencePage;
 
@@ -81,7 +93,14 @@
 	}
 
 
-	public final class InitializerFactory {
+	public static final class InitializerFactory {
+
+		private final IPreferenceStore fPreferenceStore;
+
+		public InitializerFactory(IPreferenceStore preferenceStore) {
+			fPreferenceStore= preferenceStore;
+		}
+
 		private class TextInitializer extends Initializer {
 			private final Text fText;
 
@@ -90,7 +109,7 @@
 				fText= control;
 			}
 			public void initialize() {
-				String value= fOverlayStore.getString(fPreference.getKey());
+				String value= fPreferenceStore.getString(fPreference.getKey());
 				fText.setText(value);
 			}
 		}
@@ -103,7 +122,7 @@
 				fControl= control;
 			}
 			public void initialize() {
-				boolean value= fOverlayStore.getBoolean(fPreference.getKey());
+				boolean value= fPreferenceStore.getBoolean(fPreference.getKey());
 				fControl.setSelection(value);
 			}
 		}
@@ -118,7 +137,7 @@
 				fDomain= domain;
 			}
 			public void initialize() {
-				int value= fOverlayStore.getInt(fPreference.getKey());
+				int value= fPreferenceStore.getInt(fPreference.getKey());
 				EnumValue enumValue= fDomain.getValueByInteger(value);
 				if (enumValue != null) {
 					int index= fDomain.getIndex(enumValue);
@@ -138,7 +157,7 @@
 				fDomain= domain;
 			}
 			public void initialize() {
-				int value= fOverlayStore.getInt(fPreference.getKey());
+				int value= fPreferenceStore.getInt(fPreference.getKey());
 				EnumValue enumValue= fDomain.getValueByInteger(value);
 				if (enumValue != null) {
 					fControl.setSelection(value);
@@ -368,6 +387,181 @@
 		}
 	}
 
+	private static class WhitespaceCharacterPainterOptionsDialog extends Dialog {
+
+		private java.util.List fDialogInitializers= new ArrayList();
+
+		private OverlayPreferenceStore fDialogOverlayStore;
+
+		private final IPreferenceStore fParentPreferenceStore;
+
+		private InitializerFactory fDialogInitializerFactory;
+
+		protected WhitespaceCharacterPainterOptionsDialog(Shell parentShell, IPreferenceStore parent) {
+			super(parentShell);
+			fParentPreferenceStore= parent;
+			fDialogOverlayStore= createDialogOverlayStore();
+			fDialogInitializerFactory= new InitializerFactory(fDialogOverlayStore);
+		}
+
+		private OverlayPreferenceStore createDialogOverlayStore() {
+			ArrayList overlayKeys= new ArrayList();
+
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_TABS));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_TABS));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_TABS));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_CARRIAGE_RETURN));
+			overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LINE_FEED));
+
+			OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
+			overlayKeys.toArray(keys);
+			return new OverlayPreferenceStore(fParentPreferenceStore, keys);
+		}
+
+		protected void configureShell(Shell newShell) {
+			super.configureShell(newShell);
+			newShell.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_showWhitespaceCharactersDialogTitle);
+		}
+
+		protected Control createContents(Composite parent) {
+			Control contents= super.createContents(parent);
+			Dialog.applyDialogFont(contents);
+			fDialogOverlayStore.load();
+			fDialogOverlayStore.start();
+			initializeShowWhitespaceCharactersPreferences();
+			return contents;
+		}
+
+		private void initializeShowWhitespaceCharactersPreferences() {
+			for (Iterator it= fDialogInitializers.iterator(); it.hasNext();) {
+				Initializer initializer= (Initializer)it.next();
+				initializer.initialize();
+			}
+		}
+
+		protected Control createDialogArea(Composite parent) {
+			Composite composite= (Composite)super.createDialogArea(parent);
+
+			Label description= new Label(composite, SWT.NONE);
+			description.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_configureWhitespaceCharacterPainterProperties);
+			description.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
+
+			Composite tabularComposite= new Composite(composite, SWT.NONE);
+			GridLayout layout= new GridLayout();
+			layout.numColumns= 4;
+			layout.marginHeight= 0;
+			layout.marginWidth= 0;
+			layout.makeColumnsEqualWidth= true;
+			tabularComposite.setLayout(layout);
+
+			Label label;
+			Button checkbox;
+			Preference preference;
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(""); //$NON-NLS-1$
+			label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_leading);
+			label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_enclosed);
+			label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_trailing);
+			label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_space);
+			label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_ideographicSpace);
+			label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_tab);
+			label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_TABS, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_TABS, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_TABS, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_carriageReturn);
+			label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			checkbox= new Button(tabularComposite, SWT.CHECK);
+			checkbox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+			checkbox.setEnabled(false);
+			checkbox= new Button(tabularComposite, SWT.CHECK);
+			checkbox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+			checkbox.setEnabled(false);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_CARRIAGE_RETURN, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+
+			label= new Label(tabularComposite, SWT.NONE);
+			label.setText(TextEditorMessages.TextEditorDefaultsPreferencePage_lineFeed);
+			label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			checkbox= new Button(tabularComposite, SWT.CHECK);
+			checkbox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+			checkbox.setEnabled(false);
+			checkbox= new Button(tabularComposite, SWT.CHECK);
+			checkbox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+			checkbox.setEnabled(false);
+			preference= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LINE_FEED, "", null); //$NON-NLS-1$
+			addCheckBox(tabularComposite, preference, new BooleanDomain(), 0);
+
+			return composite;
+		}
+
+		private Button addCheckBox(Composite composite, final Preference preference, final Domain domain, int indentation) {
+			final Button checkBox= new Button(composite, SWT.CHECK);
+			checkBox.setToolTipText(preference.getDescription());
+
+			GridData gd= new GridData(SWT.CENTER, SWT.CENTER, false, false);
+			gd.horizontalIndent= indentation;
+			checkBox.setLayoutData(gd);
+			checkBox.addSelectionListener(new SelectionAdapter() {
+				public void widgetSelected(SelectionEvent e) {
+					boolean value= checkBox.getSelection();
+					IStatus status= domain.validate(Boolean.valueOf(value));
+					if (!status.matches(IStatus.ERROR))
+						fDialogOverlayStore.setValue(preference.getKey(), value);
+				}
+			});
+
+			fDialogInitializers.add(fDialogInitializerFactory.create(preference, checkBox));
+			return checkBox;
+		}
+
+		protected void okPressed() {
+			super.okPressed();
+			fDialogOverlayStore.propagate();
+		}
+	}
 
 	private final String[][] fAppearanceColorListModel= new String[][] {
 		{TextEditorMessages.TextEditorPreferencePage_lineNumberForegroundColor, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER_COLOR, null},
@@ -396,7 +590,7 @@
 
 	private java.util.List fInitializers= new ArrayList();
 
-	private InitializerFactory fInitializerFactory= new InitializerFactory();
+	private InitializerFactory fInitializerFactory;
 
 	private Map fDomains= new HashMap();
 
@@ -405,6 +599,7 @@
 		setPreferenceStore(EditorsPlugin.getDefault().getPreferenceStore());
 
 		fOverlayStore= createOverlayStore();
+		fInitializerFactory= new InitializerFactory(fOverlayStore);
 	}
 
 	private OverlayPreferenceStore createOverlayStore() {
@@ -452,6 +647,18 @@
 		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE));
 		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_HOVER_ENRICH_MODE));
 
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_TABS));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_TABS));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TRAILING_TABS));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_CARRIAGE_RETURN));
+		overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LINE_FEED));
+
 		OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
 		overlayKeys.toArray(keys);
 		return new OverlayPreferenceStore(getPreferenceStore(), keys);
@@ -551,7 +758,12 @@
 
 		label= TextEditorMessages.TextEditorDefaultsPreferencePage_showWhitespaceCharacters;
 		Preference showWhitespaceCharacters= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_WHITESPACE_CHARACTERS, label, null);
-		addCheckBox(appearanceComposite, showWhitespaceCharacters, new BooleanDomain(), 0);
+		addCheckBoxWithLink(appearanceComposite, showWhitespaceCharacters, new BooleanDomain(), 0, new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				Dialog dialog= new WhitespaceCharacterPainterOptionsDialog(Display.getDefault().getActiveShell(), fOverlayStore);
+				dialog.open();
+			}
+		});
 
 		label= TextEditorMessages.TextEditorPreferencePage_showAffordance;
 		Preference showAffordance= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE, label, null);
@@ -814,6 +1026,14 @@
 		filler.setLayoutData(gd);
 	}
 
+	private void checkboxControlChanged(final Preference preference, final Domain domain, final Button checkBox) {
+		boolean value= checkBox.getSelection();
+		IStatus status= domain.validate(Boolean.valueOf(value));
+		if (!status.matches(IStatus.ERROR))
+			fOverlayStore.setValue(preference.getKey(), value);
+		updateStatus(status);
+	}
+
 	Button addCheckBox(Composite composite, final Preference preference, final Domain domain, int indentation) {
 		final Button checkBox= new Button(composite, SWT.CHECK);
 		checkBox.setText(preference.getName());
@@ -825,11 +1045,7 @@
 		checkBox.setLayoutData(gd);
 		checkBox.addSelectionListener(new SelectionAdapter() {
 			public void widgetSelected(SelectionEvent e) {
-				boolean value= checkBox.getSelection();
-				IStatus status= domain.validate(Boolean.valueOf(value));
-				if (!status.matches(IStatus.ERROR))
-					fOverlayStore.setValue(preference.getKey(), value);
-				updateStatus(status);
+				checkboxControlChanged(preference, domain, checkBox);
 			}
 		});
 
@@ -838,6 +1054,84 @@
 		return checkBox;
 	}
 
+	Button addCheckBoxWithLink(Composite parent, final Preference preference, final Domain domain, int indentation, SelectionListener listener) {
+		GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false);
+		gd.horizontalSpan= 3;
+		gd.horizontalIndent= indentation;
+
+		Composite composite= new Composite(parent, SWT.NONE);
+		GridLayout layout= new GridLayout();
+		layout.marginHeight= 0;
+		layout.marginWidth= 0;
+		layout.numColumns= 2;
+		composite.setLayout(layout);
+		composite.setLayoutData(gd);
+
+		final Button checkBox= new Button(composite, SWT.CHECK);
+		checkBox.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false));
+		checkBox.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				checkboxControlChanged(preference, domain, checkBox);
+			}
+		});
+		checkBox.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+			public void getName(AccessibleEvent e) {
+				e.result= LegacyActionTools.removeMnemonics(preference.getName().replaceAll("</?[aA][^>]*>", "")); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		});
+
+		gd= new GridData(GridData.FILL, GridData.CENTER, false, false);
+		gd.horizontalIndent= -2;
+
+		Link link= new Link(composite, SWT.NONE);
+		link.setText(preference.getName());
+		link.setLayoutData(gd);
+		if (listener != null) {
+			link.addSelectionListener(listener);
+		}
+
+		// toggle checkbox when user clicks unlinked text in link:
+		final boolean[] linkSelected= { false };
+		link.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				linkSelected[0]= true;
+			}
+		});
+		//Focus listener is required when the link opens a dialog
+		link.addFocusListener(new FocusAdapter() {
+			public void focusLost(FocusEvent e) {
+				linkSelected[0]= true;
+			}
+		});
+		link.addMouseListener(new MouseAdapter() {
+			public void mouseDown(MouseEvent e) {
+				linkSelected[0]= false;
+			}
+			public void mouseUp(MouseEvent e) {
+				if (!linkSelected[0]) {
+					checkBox.setSelection(!checkBox.getSelection());
+					checkBox.setFocus();
+					linkSelected[0]= false;
+					checkboxControlChanged(preference, domain, checkBox);
+				}
+			}
+		});
+		link.addTraverseListener(new TraverseListener() {
+			public void keyTraversed(TraverseEvent e) {
+				if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit == true) {
+					e.detail= SWT.TRAVERSE_NONE;
+					checkBox.setSelection(!checkBox.getSelection());
+					checkBox.setFocus();
+					linkSelected[0]= false;
+					checkboxControlChanged(preference, domain, checkBox);
+				}
+			}
+		});
+
+		fInitializers.add(fInitializerFactory.create(preference, checkBox));
+		return checkBox;
+	}
+
 	Control[] addCombo(Composite composite, final Preference preference, final EnumeratedDomain domain, int indentation) {
 		Label labelControl= new Label(composite, SWT.NONE);
 		labelControl.setText(preference.getName());
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.java b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.java
index 18d1328..a71f612 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 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
@@ -125,16 +125,26 @@
 		NLS.initializeMessages(BUNDLE_NAME, TextEditorMessages.class);
 	}
 
+	public static String TextEditorDefaultsPreferencePage_carriageReturn;
+	public static String TextEditorDefaultsPreferencePage_configureWhitespaceCharacterPainterProperties;
+	public static String TextEditorDefaultsPreferencePage_enclosed;
 	public static String TextEditorDefaultsPreferencePage_enrichHoverMode;
 	public static String TextEditorDefaultsPreferencePage_enrichHover_immediately;
 	public static String TextEditorDefaultsPreferencePage_enrichHover_afterDelay;
 	public static String TextEditorDefaultsPreferencePage_enrichHover_disabled;
 	public static String TextEditorDefaultsPreferencePage_enrichHover_onClick;
+	public static String TextEditorDefaultsPreferencePage_ideographicSpace;
+	public static String TextEditorDefaultsPreferencePage_leading;
+	public static String TextEditorDefaultsPreferencePage_lineFeed;
 	public static String TextEditorDefaultsPreferencePage_range_indicator;
 	public static String TextEditorDefaultsPreferencePage_smartHomeEnd;
 	public static String TextEditorDefaultsPreferencePage_warn_if_derived;
 	public static String TextEditorDefaultsPreferencePage_showWhitespaceCharacters;
+	public static String TextEditorDefaultsPreferencePage_showWhitespaceCharactersDialogTitle;
+	public static String TextEditorDefaultsPreferencePage_space;
+	public static String TextEditorDefaultsPreferencePage_tab;
 	public static String TextEditorDefaultsPreferencePage_textDragAndDrop;
+	public static String TextEditorDefaultsPreferencePage_trailing;
 	public static String LinkedModeConfigurationBlock_annotationPresentationOptions;
 	public static String LinkedModeConfigurationBlock_SQUIGGLES;
 	public static String LinkedModeConfigurationBlock_UNDERLINE;
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.properties b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.properties
index fff3165..3235e88 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.properties
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/text/TextEditorMessages.properties
@@ -29,16 +29,26 @@
 TextEditorPreferencePage_findScopeColor=Find scope
 TextEditorPreferencePage_accessibility_disableCustomCarets= Use &custom caret
 TextEditorPreferencePage_accessibility_wideCaret= &Enable thick caret
+TextEditorDefaultsPreferencePage_carriageReturn=Carriage Return ( \u00a4 )
+TextEditorDefaultsPreferencePage_configureWhitespaceCharacterPainterProperties=Configure visibility of whitespace characters in different regions of a line of text:
+TextEditorDefaultsPreferencePage_enclosed=Enclosed
 TextEditorDefaultsPreferencePage_enrichHoverMode=When mouse mo&ved into hover:
 TextEditorDefaultsPreferencePage_enrichHover_afterDelay=Enrich after delay
 TextEditorDefaultsPreferencePage_enrichHover_disabled=Close hover
 TextEditorDefaultsPreferencePage_enrichHover_immediately=Enrich immediately
 TextEditorDefaultsPreferencePage_enrichHover_onClick=Enrich on click
+TextEditorDefaultsPreferencePage_ideographicSpace=Ideographic space ( \u00b0 )
+TextEditorDefaultsPreferencePage_leading=Leading
+TextEditorDefaultsPreferencePage_lineFeed=Line Feed ( \u00b6 )
 TextEditorDefaultsPreferencePage_range_indicator=Show &range indicator
 TextEditorDefaultsPreferencePage_warn_if_derived= War&n before editing a derived file
 TextEditorDefaultsPreferencePage_smartHomeEnd= &Smart caret positioning at line start and end
-TextEditorDefaultsPreferencePage_showWhitespaceCharacters= Sh&ow whitespace characters
+TextEditorDefaultsPreferencePage_showWhitespaceCharacters= Sh&ow <a>whitespace characters</a>
+TextEditorDefaultsPreferencePage_showWhitespaceCharactersDialogTitle=Show Whitespace Characters
+TextEditorDefaultsPreferencePage_space=Space ( \u00b7 )
+TextEditorDefaultsPreferencePage_tab=Tab ( \u00bb )
 TextEditorDefaultsPreferencePage_textDragAndDrop= Enable drag and dro&p of text
+TextEditorDefaultsPreferencePage_trailing=Trailing
 TextEditorPreferencePage_colorsAndFonts_link= More colors can be configured on the <a>Colors and Fonts</a> preference page.
 TextEditorPreferencePage_colorsAndFonts_link_tooltip= Show the Colors and Fonts preferences
 
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/texteditor/AbstractDecoratedTextEditorPreferenceConstants.java b/org.eclipse.ui.editors/src/org/eclipse/ui/texteditor/AbstractDecoratedTextEditorPreferenceConstants.java
index fd2b444..44b5959 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/texteditor/AbstractDecoratedTextEditorPreferenceConstants.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/texteditor/AbstractDecoratedTextEditorPreferenceConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 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
@@ -394,12 +394,154 @@
 	 * <p>
 	 * Value is of type <code>Boolean</code>.
 	 * </p>
-	 *
+	 * 
+	 * <p>
+	 * The following preferences can be used for fine-grained configuration when enabled.
+	 * <ul>
+	 * <li>{@link #EDITOR_SHOW_LEADING_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_ENCLOSED_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_TRAILING_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #EDITOR_SHOW_LEADING_TABS}</li>
+	 * <li>{@link #EDITOR_SHOW_ENCLOSED_TABS}</li>
+	 * <li>{@link #EDITOR_SHOW_TRAILING_TABS}</li>
+	 * <li>{@link #EDITOR_SHOW_CARRIAGE_RETURN}</li>
+	 * <li>{@link #EDITOR_SHOW_LINE_FEED}</li>
+	 * </ul>
+	 * </p>
+	 * 
 	 * @since 3.3
 	 */
 	public static final String EDITOR_SHOW_WHITESPACE_CHARACTERS= AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS;
 
 	/**
+	 * A named preference that controls the display of leading Space characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_LEADING_SPACES= AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES;
+
+	/**
+	 * A named preference that controls the display of enclosed Space characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_ENCLOSED_SPACES= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES;
+
+	/**
+	 * A named preference that controls the display of trailing Space characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_TRAILING_SPACES= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES;
+
+	/**
+	 * A named preference that controls the display of leading Ideographic Space characters. The
+	 * value is used only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES;
+
+	/**
+	 * A named preference that controls the display of enclosed Ideographic Space characters. The
+	 * value is used only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES;
+
+	/**
+	 * A named preference that controls the display of trailing Ideographic Space characters. The
+	 * value is used only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES;
+
+	/**
+	 * A named preference that controls the display of leading Tab characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_LEADING_TABS= AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS;
+
+	/**
+	 * A named preference that controls the display of enclosed Tab characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_ENCLOSED_TABS= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS;
+
+	/**
+	 * A named preference that controls the display of trailing Tab characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_TRAILING_TABS= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS;
+
+	/**
+	 * A named preference that controls the display of Carriage Return characters. The value is used
+	 * only if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_CARRIAGE_RETURN= AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN;
+
+	/**
+	 * A named preference that controls the display of Line Feed characters. The value is used only
+	 * if the value of {@link #EDITOR_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String EDITOR_SHOW_LINE_FEED= AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED;
+
+
+	/**
 	 * A named preference that controls the display of the range indicator.
 	 * <p>
 	 * Value is of type <code>Boolean</code>.
@@ -568,7 +710,20 @@
 
 		store.setDefault(EDITOR_WARN_IF_INPUT_DERIVED, true);
 		store.setDefault(EDITOR_SMART_HOME_END, true);
+
 		store.setDefault(EDITOR_SHOW_WHITESPACE_CHARACTERS, false);
+		store.setDefault(EDITOR_SHOW_LEADING_SPACES, true);
+		store.setDefault(EDITOR_SHOW_ENCLOSED_SPACES, true);
+		store.setDefault(EDITOR_SHOW_TRAILING_SPACES, true);
+		store.setDefault(EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES, true);
+		store.setDefault(EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES, true);
+		store.setDefault(EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES, true);
+		store.setDefault(EDITOR_SHOW_LEADING_TABS, true);
+		store.setDefault(EDITOR_SHOW_ENCLOSED_TABS, true);
+		store.setDefault(EDITOR_SHOW_TRAILING_TABS, true);
+		store.setDefault(EDITOR_SHOW_CARRIAGE_RETURN, true);
+		store.setDefault(EDITOR_SHOW_LINE_FEED, true);
+
 		store.setDefault(EDITOR_TEXT_DRAG_AND_DROP_ENABLED, true);
 		store.setDefault(EDITOR_SHOW_TEXT_HOVER_AFFORDANCE, true);
 		store.setDefault(EDITOR_HOVER_ENRICH_MODE, 0);
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
index b1baed1..8c2c809 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
@@ -2123,10 +2123,152 @@
 	 * <p>
 	 * Value is of type <code>Boolean</code>.
 	 * </p>
-	 *
+	 * 
+	 * <p>
+	 * The following preferences can be used for fine-grained configuration when enabled.
+	 * <ul>
+	 * <li>{@link #PREFERENCE_SHOW_LEADING_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_ENCLOSED_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_TRAILING_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES}</li>
+	 * <li>{@link #PREFERENCE_SHOW_LEADING_TABS}</li>
+	 * <li>{@link #PREFERENCE_SHOW_ENCLOSED_TABS}</li>
+	 * <li>{@link #PREFERENCE_SHOW_TRAILING_TABS}</li>
+	 * <li>{@link #PREFERENCE_SHOW_CARRIAGE_RETURN}</li>
+	 * <li>{@link #PREFERENCE_SHOW_LINE_FEED}</li>
+	 * </ul>
+	 * </p>
+	 * 
 	 * @since 3.3
 	 */
 	public static final String PREFERENCE_SHOW_WHITESPACE_CHARACTERS= "showWhitespaceCharacters"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of leading Space characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_LEADING_SPACES= "showLeadingSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of enclosed Space characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_ENCLOSED_SPACES= "showEnclosedSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of trailing Space characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_TRAILING_SPACES= "showTrailingSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of leading Ideographic Space characters. The
+	 * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES= "showLeadingIdeographicSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of enclosed Ideographic Space characters. The
+	 * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES= "showEnclosedIdeographicSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of trailing Ideographic Space characters. The
+	 * value is used only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is
+	 * <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES= "showTrailingIdeographicSpaces"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of leading Tab characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_LEADING_TABS= "showLeadingTabs"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of enclosed Tab characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_ENCLOSED_TABS= "showEnclosedTabs"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of trailing Tab characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_TRAILING_TABS= "showTrailingTabs"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of Carriage Return characters. The value is used
+	 * only if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_CARRIAGE_RETURN= "showCarriageReturn"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that controls the display of Line Feed characters. The value is used only
+	 * if the value of {@link #PREFERENCE_SHOW_WHITESPACE_CHARACTERS} is <code>true</code>.
+	 * <p>
+	 * Value is of type <code>Boolean</code>.
+	 * </p>
+	 * 
+	 * @since 3.7
+	 */
+	public static final String PREFERENCE_SHOW_LINE_FEED= "showLineFeed"; //$NON-NLS-1$
+
 	/**
 	 * A named preference that controls whether text drag and drop is enabled.
 	 * <p>
@@ -4484,7 +4626,18 @@
 			return;
 		}
 
-		if (PREFERENCE_SHOW_WHITESPACE_CHARACTERS.equals(property)) {
+		if (PREFERENCE_SHOW_WHITESPACE_CHARACTERS.equals(property) ||
+				PREFERENCE_SHOW_LEADING_SPACES.equals(property) ||
+				PREFERENCE_SHOW_ENCLOSED_SPACES.equals(property) ||
+				PREFERENCE_SHOW_TRAILING_SPACES.equals(property) ||
+				PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES.equals(property) ||
+				PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES.equals(property) ||
+				PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES.equals(property) ||
+				PREFERENCE_SHOW_LEADING_TABS.equals(property) ||
+				PREFERENCE_SHOW_ENCLOSED_TABS.equals(property) ||
+				PREFERENCE_SHOW_TRAILING_TABS.equals(property) ||
+				PREFERENCE_SHOW_CARRIAGE_RETURN.equals(property) ||
+				PREFERENCE_SHOW_LINE_FEED.equals(property)) {
 			IAction action= getAction(ITextEditorActionConstants.SHOW_WHITESPACE_CHARACTERS);
 			if (action instanceof IUpdate)
 				((IUpdate)action).update();
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShowWhitespaceCharactersAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShowWhitespaceCharactersAction.java
index 9a22c31..03ba3d5 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShowWhitespaceCharactersAction.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/ShowWhitespaceCharactersAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2008 Wind River Systems, Inc., IBM Corporation and others.
+ * Copyright (c) 2006, 2010 Wind River Systems, Inc., 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
@@ -40,6 +40,28 @@
 	private IPreferenceStore fStore;
 	/** The painter. */
 	private IPainter fWhitespaceCharPainter;
+	/** @since 3.7 */
+	private boolean fShowLeadingSpaces;
+	/** @since 3.7 */
+	private boolean fShowEnclosedSpaces;
+	/** @since 3.7 */
+	private boolean fShowTrailingSpaces;
+	/** @since 3.7 */
+	private boolean fShowLeadingIdeographicSpaces;
+	/** @since 3.7 */
+	private boolean fShowEnclosedIdeographicSpaces;
+	/** @since 3.7 */
+	private boolean fShowTrailingIdeographicSpace;
+	/** @since 3.7 */
+	private boolean fShowLeadingTabs;
+	/** @since 3.7 */
+	private boolean fShowEnclosedTabs;
+	/** @since 3.7 */
+	private boolean fShowTrailingTabs;
+	/** @since 3.7 */
+	private boolean fShowCarriageReturn;
+	/** @since 3.7 */
+	private boolean fShowLineFeed;
 
 	/**
 	 * Construct the action and initialize its state.
@@ -90,7 +112,8 @@
 
 		ITextViewer viewer= getTextViewer();
 		if (viewer instanceof ITextViewerExtension2) {
-			fWhitespaceCharPainter= new WhitespaceCharacterPainter(viewer);
+			fWhitespaceCharPainter= new WhitespaceCharacterPainter(viewer, fShowLeadingSpaces, fShowEnclosedSpaces, fShowTrailingSpaces, fShowLeadingIdeographicSpaces, fShowEnclosedIdeographicSpaces,
+					fShowTrailingIdeographicSpace, fShowLeadingTabs, fShowEnclosedTabs, fShowTrailingTabs, fShowCarriageReturn, fShowLineFeed);
 			((ITextViewerExtension2)viewer).addPainter(fWhitespaceCharPainter);
 		}
 	}
@@ -128,12 +151,27 @@
 	 */
 	private void synchronizeWithPreference() {
 		boolean checked= false;
-		if (fStore != null)
+		if (fStore != null) {
 			checked= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS);
+			fShowLeadingSpaces= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES);
+			fShowEnclosedSpaces= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES);
+			fShowTrailingSpaces= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES);
+			fShowLeadingIdeographicSpaces= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES);
+			fShowEnclosedIdeographicSpaces= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES);
+			fShowTrailingIdeographicSpace= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES);
+			fShowLeadingTabs= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS);
+			fShowEnclosedTabs= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS);
+			fShowTrailingTabs= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS);
+			fShowCarriageReturn= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN);
+			fShowLineFeed= fStore.getBoolean(AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED);
+		}
 
 		if (checked != isChecked()) {
 			setChecked(checked);
 			togglePainterState(checked);
+		} else if (checked) {
+			uninstallPainter();
+			installPainter();
 		}
 	}