Bug 552438: [NiConsole] Use solid color for prompt highlighting
  - current line highlighting (text editors) color as foreground color
  - prompt (console output) color as foreground color

Change-Id: Ifdfd035ed3cb4927ed8d83aa844e3c7d90b39b78
diff --git a/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/internal/nico/ui/console/PromptHighlighter.java b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/internal/nico/ui/console/PromptHighlighter.java
new file mode 100644
index 0000000..6c28f1f
--- /dev/null
+++ b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/internal/nico/ui/console/PromptHighlighter.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2019 Stephan Wahlbrink <sw@wahlbrink.eu> and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.nico.ui.console;
+
+import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.text.source.ISharedTextColors;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.editors.text.EditorsUI;
+
+import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.nico.ui.console.NIConsoleColorAdapter;
+import org.eclipse.statet.nico.ui.console.NIConsoleOutputStream;
+
+
+public class PromptHighlighter implements IPropertyChangeListener {
+	
+	
+	private Control control;
+	
+	private final IPreferenceStore preferenceStore;
+	private final PreferenceAccess prefAccess;
+	private final ISharedTextColors sharedColors;
+	
+	private Color foregroundColor;
+	private Color backgroundColor;
+	
+	private boolean isHighlightEnabled;
+	
+	
+	public PromptHighlighter(final Control control,
+			final PreferenceAccess prefAccess, final IPreferenceStore preferenceStore) {
+		this.control= control;
+		this.prefAccess= prefAccess;
+		this.preferenceStore= preferenceStore;
+		this.sharedColors= EditorsUI.getSharedTextColors();
+		
+		this.preferenceStore.addPropertyChangeListener(this);
+		
+		updateControl();
+	}
+	
+	public void dispose() {
+		this.control= null;
+		this.preferenceStore.removePropertyChangeListener(this);
+	}
+	
+	
+	@Override
+	public void propertyChange(final PropertyChangeEvent event) {
+		if (event.getProperty().equals(EDITOR_CURRENT_LINE_COLOR)) {
+			Display.getDefault().asyncExec(() -> {
+				updateSettings();
+				updateControl();
+			});
+		}
+	}
+	
+	public void setHighlight(final boolean enable) {
+		if (enable == this.isHighlightEnabled) {
+			return;
+		}
+		this.isHighlightEnabled= enable;
+		updateControl();
+	}
+	
+	public void updateSettings() {
+		this.foregroundColor= null;
+		this.backgroundColor= null;
+	}
+	
+	public void updateControl() {
+		final Control control= this.control;
+		if (!UIAccess.isOkToUse(control)) {
+			return;
+		}
+		
+		Color foregroundColor;
+		Color backgroundColor;
+		if (this.isHighlightEnabled) {
+			foregroundColor= this.foregroundColor;
+			if (foregroundColor == null) {
+				final RGB rgb= this.prefAccess.getPreferenceValue(
+						NIConsoleColorAdapter.getForegroundColorPref(NIConsoleOutputStream.INFO_STREAM_ID) );
+				foregroundColor= this.sharedColors.getColor(rgb);
+				this.foregroundColor= foregroundColor;
+			}
+			backgroundColor= this.backgroundColor;
+			if (backgroundColor == null) {
+				final RGB rgb= PreferenceConverter.getColor(
+						this.preferenceStore, EDITOR_CURRENT_LINE_COLOR );
+				backgroundColor= this.sharedColors.getColor(rgb);
+				this.backgroundColor= backgroundColor;
+			}
+			
+		}
+		else {
+			foregroundColor= control.getDisplay().getSystemColor(
+					SWT.COLOR_WIDGET_DISABLED_FOREGROUND );
+			backgroundColor= null;
+		}
+		control.setForeground(foregroundColor);
+		control.setBackground(backgroundColor);
+	}
+	
+}
diff --git a/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/ConsolePageEditor.java b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/ConsolePageEditor.java
index 79e097c..feb58e6 100644
--- a/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/ConsolePageEditor.java
+++ b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/ConsolePageEditor.java
@@ -44,13 +44,9 @@
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.events.VerifyEvent;
-import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.PaletteData;
 import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
@@ -92,6 +88,7 @@
 import org.eclipse.statet.internal.nico.ui.Messages;
 import org.eclipse.statet.internal.nico.ui.NicoUIPlugin;
 import org.eclipse.statet.internal.nico.ui.console.InputDocument;
+import org.eclipse.statet.internal.nico.ui.console.PromptHighlighter;
 import org.eclipse.statet.internal.nico.ui.preferences.ConsolePreferences;
 import org.eclipse.statet.ltk.model.core.elements.ISourceUnit;
 import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
@@ -151,64 +148,6 @@
 	final static int KEY_OUTPUT_END= SWT.MOD1 | SWT.SHIFT | SWT.END;
 	
 	
-	/**
-	 * Creates and returns a new SWT image with the given size on
-	 * the given display which is used as this range indicator's image.
-	 * 
-	 * @see org.eclipse.ui.texteditor.DefaultRangeIndicator
-	 * 
-	 * @param display the display on which to create the image
-	 * @param size the image size
-	 * @return a new image
-	 */
-	private static Image createImage(final Display display) {
-		final Point size= new Point(8, 8);
-		final int width= size.x;
-		final int height= size.y;
-		
-		if (fgPaletteData == null) {
-			fgPaletteData= createPalette(display);
-		}
-		
-		final ImageData imageData= new ImageData(width, height, 1, fgPaletteData);
-		
-		for (int y= 0; y < height; y++) {
-			for (int x= 0; x < width; x++) {
-				imageData.setPixel(x, y, (x + y) % 2);
-			}
-		}
-		
-		return new Image(display, imageData);
-	}
-	
-	/**
-	 * Creates and returns a new color palette data.
-	 * 
-	 * @param display
-	 * @return the new color palette data
-	 */
-	private static PaletteData createPalette(final Display display) {
-		Color c1;
-		Color c2;
-		
-		if (true) {
-			// range lighter
-			c1= display.getSystemColor(SWT.COLOR_LIST_SELECTION);
-			c2= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
-		} else {
-			// range darker
-			c1= display.getSystemColor(SWT.COLOR_LIST_SELECTION);
-			c2= display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
-		}
-		
-		final RGB rgbs[]= new RGB[] {
-			new RGB(c1.getRed(), c1.getGreen(), c1.getBlue()),
-			new RGB(c2.getRed(), c2.getGreen(), c2.getBlue())};
-		
-		return new PaletteData(rgbs);
-	}
-	
-	
 	private final class ScrollControl implements Listener {
 		
 		private static final int MAX= 150;
@@ -273,14 +212,14 @@
 	
 	private class StatusLine implements IEditorStatusLine {
 		
-		private boolean fMessageSetted;
-		private String fMessage;
+		private boolean messageSetted;
+		private String message;
 		
 		@Override
 		public void setMessage(final boolean error, final String message, final Image image) {
 			final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
 			if (manager != null) {
-				this.fMessageSetted= true;
+				this.messageSetted= true;
 				if (error) {
 					manager.setErrorMessage(image, message);
 				}
@@ -291,10 +230,10 @@
 		}
 		
 		void cleanStatusLine() {
-			if (this.fMessageSetted) {
+			if (this.messageSetted) {
 				final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
 				if (manager != null) {
-					this.fMessageSetted= false;
+					this.messageSetted= false;
 					manager.setErrorMessage(null);
 					updateWD();
 				}
@@ -303,11 +242,11 @@
 		}
 		
 		void updateWD() {
-			if (!this.fMessageSetted) {
+			if (!this.messageSetted) {
 				final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
 				if (manager != null) {
 					final String path= FileUtil.toString(ConsolePageEditor.this.consolePage.getTool().getWorkspaceData().getWorkspaceDir());
-					this.fMessage= path;
+					this.message= path;
 					manager.setMessage(path);
 				}
 			}
@@ -316,7 +255,7 @@
 		void refresh() {
 			final IStatusLineManager manager= ConsolePageEditor.this.consolePage.getSite().getActionBars().getStatusLineManager();
 			if (manager != null) {
-				manager.setMessage(this.fMessage);
+				manager.setMessage(this.message);
 			}
 		}
 		
@@ -424,9 +363,6 @@
 		
 	}
 	
-	
-	private static PaletteData fgPaletteData;
-	
 	private NIConsolePage consolePage;
 	private ToolProcess process;
 	
@@ -435,9 +371,8 @@
 	private final ISourceUnit sourceUnit;
 	
 	private Composite composite;
-	private Label prefix;
-	private boolean isPrefixHighlighted;
-	private Image prefixBackground;
+	private Label prompt;
+	private PromptHighlighter promptHighlighter;
 	private InputSourceViewer sourceViewer;
 	private final InputDocument document;
 	private Button submitButton;
@@ -502,14 +437,12 @@
 		layout.verticalSpacing= 3;
 		this.composite.setLayout(layout);
 		
-		this.prefix= new Label(this.composite, SWT.LEFT);
+		this.prompt= new Label(this.composite, SWT.LEFT);
 		GridData gd= new GridData(SWT.LEFT, SWT.FILL, false, false);
 		gd.verticalIndent= 1;
-		this.prefix.setLayoutData(gd);
-		this.prefixBackground= createImage(Display.getCurrent());
-		this.isPrefixHighlighted= false;
-		this.prefix.setText("> "); //$NON-NLS-1$
-		this.prefix.addMouseListener(new MouseAdapter() {
+		this.prompt.setLayoutData(gd);
+		this.prompt.setText("> "); //$NON-NLS-1$
+		this.prompt.addMouseListener(new MouseAdapter() {
 			@Override
 			public void mouseDown(final MouseEvent e) {
 				if (UIAccess.isOkToUse(ConsolePageEditor.this.sourceViewer)) {
@@ -553,6 +486,10 @@
 			}
 		});
 		
+		this.promptHighlighter= new PromptHighlighter(this.prompt,
+				PreferenceUtils.getInstancePrefs(),
+				this.configurator.getSourceViewerConfiguration().getPreferences() );
+		
 		final Slider slider= new Slider(this.composite, SWT.HORIZONTAL);
 		slider.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
 		this.scroller= new ScrollControl(slider);
@@ -662,6 +599,11 @@
 		if (groupIds.contains(ConsolePreferences.GROUP_ID)) {
 			updateSettings();
 		}
+		if (groupIds.contains(ConsolePreferences.OUTPUT_TEXTSTYLE_GROUP_ID)
+				&& this.promptHighlighter != null) {
+			this.promptHighlighter.updateSettings();
+			this.promptHighlighter.updateControl();
+		}
 	}
 	
 	public void initActions(final IServiceLocator serviceLocator, final ContextHandlers handlers) {
@@ -799,18 +741,14 @@
 	
 	
 	void setFont(final Font font) {
-		this.prefix.setFont(font);
+		this.prompt.setFont(font);
 		this.sourceViewer.getControl().setFont(font);
 	}
 	
 	void updateBusy(final boolean isBusy) {
-		final boolean highlight= !isBusy;
-		if (highlight == this.isPrefixHighlighted) {
-			return;
-		}
-		if (UIAccess.isOkToUse(this.prefix)) {
-			this.isPrefixHighlighted= highlight;
-			this.prefix.setBackgroundImage(highlight ? this.prefixBackground : null);
+		final PromptHighlighter prefixRenderer= this.promptHighlighter;
+		if (prefixRenderer != null) {
+			prefixRenderer.setHighlight(!isBusy);
 		}
 	}
 	
@@ -819,7 +757,7 @@
 	 */
 	void updatePrompt(final Prompt prompt) {
 		final Prompt p= (prompt != null) ? prompt : this.process.getWorkspaceData().getPrompt();
-		if (UIAccess.isOkToUse(this.prefix)) {
+		if (UIAccess.isOkToUse(this.prompt)) {
 			int start= 0;
 			for (int i= 0; i < p.text.length(); i++) {
 				final char c= p.text.charAt(i);
@@ -831,11 +769,11 @@
 				}
 			}
 			final String newText= (start == 0) ? p.text : p.text.substring(start);
-			final String oldText= this.prefix.getText();
+			final String oldText= this.prompt.getText();
 			if (!oldText.equals(newText)) {
-				this.prefix.setText(newText);
+				this.prompt.setText(newText);
 				if (oldText.length() != newText.length()) { // assuming monospace font
-					getComposite().layout(new Control[] { this.prefix });
+					getComposite().layout(new Control[] { this.prompt });
 				}
 			}
 			onPromptUpdate(p);
@@ -1004,9 +942,9 @@
 		this.process= null;
 		this.consolePage= null;
 		
-		if (this.prefixBackground != null) {
-			this.prefixBackground.dispose();
-			this.prefixBackground= null;
+		if (this.promptHighlighter != null) {
+			this.promptHighlighter.dispose();
+			this.promptHighlighter= null;
 		}
 	}
 	
diff --git a/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/NIConsoleColorAdapter.java b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/NIConsoleColorAdapter.java
index 061bac7..9aa1100 100644
--- a/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/NIConsoleColorAdapter.java
+++ b/r/org.eclipse.statet.nico.ui/src/org/eclipse/statet/nico/ui/console/NIConsoleColorAdapter.java
@@ -21,7 +21,9 @@
 import org.eclipse.swt.graphics.RGB;
 
 import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.lang.Nullable;
 
+import org.eclipse.statet.ecommons.preferences.core.Preference;
 import org.eclipse.statet.ecommons.preferences.core.Preference.BooleanPref;
 import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess;
 import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils;
@@ -122,9 +124,9 @@
 					final NIConsoleOutputStream stream= console.getStream(streamId);
 					if (stream != null) {
 						stream.setColor(SharedUIResources.getColors().getColor(
-								getFontRGB(streamId) ));
+								getPrefValue(getForegroundColorPref(streamId)) ));
 						stream.setBackgroundColor(SharedUIResources.getColors().getColor(
-								getBackgroundRGB(streamId) ));
+								getPrefValue(getBackgroundColorPref(streamId)) ));
 						stream.setFontStyle(getFontStyle(streamId));
 					}
 				}
@@ -136,20 +138,9 @@
 		this.console= null;
 	}
 	
-	private RGB getFontRGB(final String streamId) {
-		final String rootKey= getPrefRootKey(streamId);
-		if (rootKey != null) {
-			return this.prefAccess.getPreferenceValue(
-					new RGBPref(NicoUIPreferences.OUTPUT_QUALIFIER,
-							rootKey + ITextPresentationConstants.TEXTSTYLE_COLOR_SUFFIX ));
-		}
-		return null;
-	}
-	
-	private RGB getBackgroundRGB(final String streamId) {
-		if (streamId.endsWith(NIConsoleOutputStream.OTHER_TASKS_STREAM_SUFFIX)) {
-			return this.prefAccess.getPreferenceValue(
-					NicoUIPreferences.OUTPUT_OTHER_TASKS_BACKGROUND_COLOR_PREF );
+	private <T> @Nullable T getPrefValue(final @Nullable Preference<T> preference) {
+		if (preference != null) {
+			return this.prefAccess.getPreferenceValue(preference);
 		}
 		return null;
 	}
@@ -171,7 +162,24 @@
 		return style;
 	}
 	
-	private String getPrefRootKey(final String streamId) {
+	
+	public static Preference<RGB> getForegroundColorPref(final String streamId) {
+		final String rootKey= getPrefRootKey(streamId);
+		if (rootKey != null) {
+			return new RGBPref(NicoUIPreferences.OUTPUT_QUALIFIER,
+					rootKey + ITextPresentationConstants.TEXTSTYLE_COLOR_SUFFIX );
+		}
+		return null;
+	}
+	
+	public static Preference<RGB> getBackgroundColorPref(final String streamId) {
+		if (streamId.endsWith(NIConsoleOutputStream.OTHER_TASKS_STREAM_SUFFIX)) {
+			return NicoUIPreferences.OUTPUT_OTHER_TASKS_BACKGROUND_COLOR_PREF;
+		}
+		return null;
+	}
+	
+	private static String getPrefRootKey(final String streamId) {
 		if (streamId == NIConsoleOutputStream.INFO_STREAM_ID
 				|| streamId == NIConsoleOutputStream.OTHER_TASKS_INFO_STREAM_ID) {
 			return NicoUIPreferences.OUTPUT_INFO_STREAM_ROOT_KEY;