diff --git a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF index 23023cb5a81..58e89a789d3 100644 --- a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF @@ -10,6 +10,7 @@ Export-Package: org.eclipse.jface.contentassist.images, org.eclipse.jface.internal.text;x-internal:=true, org.eclipse.jface.internal.text.codemining;x-internal:=true, + org.eclipse.jface.internal.text.contentassist;x-internal:=true, org.eclipse.jface.internal.text.html;x-friends:="org.eclipse.ant.ui, org.eclipse.jdt.ui, org.eclipse.ltk.ui.refactoring, org.eclipse.pde.ui, org.eclipse.ui.editors, org.eclipse.xtext.ui", org.eclipse.jface.internal.text.link.contentassist;x-internal:=true, org.eclipse.jface.internal.text.revisions;x-internal:=true, diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java index a3052c84d42..7a180c7824b 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java @@ -25,6 +25,9 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; + /** * Adds owner draw support for tables. @@ -42,6 +45,10 @@ public class TableOwnerDrawSupport implements Listener { public static void install(Table table) { TableOwnerDrawSupport listener= new TableOwnerDrawSupport(table); + installListener(table, listener); + } + + protected static void installListener(Table table, Listener listener) { table.addListener(SWT.Dispose, listener); table.addListener(SWT.MeasureItem, listener); table.addListener(SWT.EraseItem, listener); @@ -70,7 +77,7 @@ private static StyleRange[] getStyledRanges(TableItem item, int column) { return (StyleRange[])item.getData(STYLED_RANGES_KEY + column); } - private TableOwnerDrawSupport(Table table) { + protected TableOwnerDrawSupport(Table table) { int orientation= table.getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); fSharedLayout= new TextLayout(table.getDisplay()); fSharedLayout.setOrientation(orientation); @@ -147,7 +154,28 @@ private void performPaint(Event event) { Color oldForeground= gc.getForeground(); Color oldBackground= gc.getBackground(); - if (!isSelected) { + if (isSelected) { + Color background= item.getParent().isFocusControl() + ? getSelectedRowBackgroundColor() + : getSelectedRowBackgroundColorNoFocus(); + Color foreground= item.getParent().isFocusControl() + ? getSelectedRowForegroundColor() + : getSelectedRowForegroundColorNoFocus(); + + if (background == null) { + background= item.getDisplay().getSystemColor( + SWT.COLOR_LIST_SELECTION); + } + + if (foreground == null) { + foreground= item.getDisplay().getSystemColor( + SWT.COLOR_LIST_SELECTION_TEXT); + } + + gc.setBackground(background); + gc.setForeground(foreground); + gc.fillRectangle(0, event.y, item.getParent().getBounds().width, event.height); + } else { Color foreground= item.getForeground(index); gc.setForeground(foreground); @@ -178,10 +206,54 @@ private void performPaint(Event event) { gc.drawFocus(focusBounds.x, focusBounds.y, focusBounds.width + fDeltaOfLastMeasure, focusBounds.height); } - if (!isSelected) { - gc.setForeground(oldForeground); - gc.setBackground(oldBackground); - } + gc.setForeground(oldForeground); + gc.setBackground(oldBackground); + } + + /** + * The color to use when rendering the background of the selected row when the control has the + * input focus + * + * @return the color or null to use the default + */ + protected Color getSelectedRowBackgroundColor() { + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND"); //$NON-NLS-1$ + } + + /** + * The color to use when rendering the foreground (=text) of the selected row when the control + * has the input focus + * + * @return the color or null to use the default + */ + protected Color getSelectedRowForegroundColor() { + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND"); //$NON-NLS-1$ + } + + /** + * The color to use when rendering the foreground (=text) of the selected row when the control + * has no input focus + * + * @return the color or null to use the same used when control has focus + * @since 3.4 + */ + protected Color getSelectedRowForegroundColorNoFocus() { + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS"); //$NON-NLS-1$ + } + + /** + * The color to use when rendering the background of the selected row when the control has + * no input focus + * + * @return the color or null to use the same used when control has focus + * @since 3.4 + */ + protected Color getSelectedRowBackgroundColorNoFocus() { + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS"); //$NON-NLS-1$ } private void widgetDisposed() { diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupport.java new file mode 100644 index 00000000000..611397a4723 --- /dev/null +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupport.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2024 SAP SE. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.jface.internal.text.contentassist; + +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import org.eclipse.jface.internal.text.TableOwnerDrawSupport; + +/** + * When a completion table (for example for code completion) is requested by the user, the user + * needs to be able to continue typing in the linked text control. In such cases, the focus is not + * on the completion table. To ensure the selected code completion proposal always displays in the + * correct color, even if the completion table is not focused, the non-focused colors are overridden + * with the focus colors. + */ +public class CompletionTableDrawSupport extends TableOwnerDrawSupport { + + public static void install(Table table) { + TableOwnerDrawSupport listener= new CompletionTableDrawSupport(table); + installListener(table, listener); + } + + /** + * Stores the styled ranges in the given table item. See {@link TableOwnerDrawSupport} + * + * @param item table item + * @param column the column index + * @param ranges the styled ranges or null to remove them + */ + public static void storeStyleRanges(TableItem item, int column, StyleRange[] ranges) { + TableOwnerDrawSupport.storeStyleRanges(item, column, ranges); + } + + + private CompletionTableDrawSupport(Table table) { + super(table); + } + + @Override + protected Color getSelectedRowBackgroundColorNoFocus() { + return super.getSelectedRowBackgroundColor(); + } + + @Override + protected Color getSelectedRowForegroundColorNoFocus() { + return super.getSelectedRowForegroundColor(); + } + +} diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/link/contentassist/CompletionProposalPopup2.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/link/contentassist/CompletionProposalPopup2.java index 6ca009a07d7..067e233936f 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/link/contentassist/CompletionProposalPopup2.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/link/contentassist/CompletionProposalPopup2.java @@ -39,7 +39,7 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; -import org.eclipse.jface.internal.text.TableOwnerDrawSupport; +import org.eclipse.jface.internal.text.contentassist.CompletionTableDrawSupport; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.JFaceColors; @@ -269,7 +269,7 @@ private void createProposalSelector() { fIsColoredLabelsSupportEnabled= fContentAssistant.isColoredLabelsSupportEnabled(); if (fIsColoredLabelsSupportEnabled) - TableOwnerDrawSupport.install(fProposalTable); + CompletionTableDrawSupport.install(fProposalTable); fProposalTable.setLocation(0, 0); if (fAdditionalInfoController != null) @@ -572,7 +572,7 @@ private void setProposals(ICompletionProposal[] proposals) { item.setText(displayString); if (fIsColoredLabelsSupportEnabled) - TableOwnerDrawSupport.storeStyleRanges(item, 0, styleRanges); + CompletionTableDrawSupport.storeStyleRanges(item, 0, styleRanges); item.setData(p); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java index f426f8b7ce8..7297722a77b 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java @@ -78,7 +78,7 @@ import org.eclipse.jface.bindings.keys.SWTKeySupport; import org.eclipse.jface.contentassist.IContentAssistSubjectControl; import org.eclipse.jface.internal.text.InformationControlReplacer; -import org.eclipse.jface.internal.text.TableOwnerDrawSupport; +import org.eclipse.jface.internal.text.contentassist.CompletionTableDrawSupport; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.JFaceColors; import org.eclipse.jface.resource.JFaceResources; @@ -613,7 +613,7 @@ void createProposalSelector() { fIsColoredLabelsSupportEnabled= fContentAssistant.isColoredLabelsSupportEnabled(); if (fIsColoredLabelsSupportEnabled) - TableOwnerDrawSupport.install(fProposalTable); + CompletionTableDrawSupport.install(fProposalTable); fProposalTable.setLocation(0, 0); if (fAdditionalInfoController != null) @@ -904,7 +904,7 @@ private void handleSetData(Event event) { item.setText(displayString); if (fIsColoredLabelsSupportEnabled) - TableOwnerDrawSupport.storeStyleRanges(item, 0, styleRanges); + CompletionTableDrawSupport.storeStyleRanges(item, 0, styleRanges); item.setImage(image); item.setData(current); diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/FocusCellOwnerDrawHighlighter.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/FocusCellOwnerDrawHighlighter.java index 99925bdc6f9..5455e92aac3 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/FocusCellOwnerDrawHighlighter.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/FocusCellOwnerDrawHighlighter.java @@ -18,6 +18,8 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.jface.util.Util; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; @@ -151,8 +153,8 @@ private void hookListener(final ColumnViewer viewer) { * @return the color or null to use the default */ protected Color getSelectedCellBackgroundColor(ViewerCell cell) { - return removeNonFocusedSelectionInformation ? null - : cell.getItem().getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION); + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND"); //$NON-NLS-1$ } /** @@ -164,7 +166,8 @@ protected Color getSelectedCellBackgroundColor(ViewerCell cell) { * @return the color or null to use the default */ protected Color getSelectedCellForegroundColor(ViewerCell cell) { - return null; + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND"); //$NON-NLS-1$ } /** @@ -178,7 +181,8 @@ protected Color getSelectedCellForegroundColor(ViewerCell cell) { * @since 3.4 */ protected Color getSelectedCellForegroundColorNoFocus(ViewerCell cell) { - return null; + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS"); //$NON-NLS-1$ } /** @@ -192,7 +196,8 @@ protected Color getSelectedCellForegroundColorNoFocus(ViewerCell cell) { * @since 3.4 */ protected Color getSelectedCellBackgroundColorNoFocus(ViewerCell cell) { - return null; + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + return colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS"); //$NON-NLS-1$ } /** diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java index e1710179f94..2454eda1613 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java @@ -17,6 +17,8 @@ import java.util.HashSet; import java.util.Set; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Rectangle; @@ -166,20 +168,16 @@ public void update(ViewerCell cell) { } /** - * Handle the erase event. The default implementation colors the background - * of selected areas with {@link SWT#COLOR_LIST_SELECTION} and foregrounds - * with {@link SWT#COLOR_LIST_SELECTION_TEXT}. Note that this - * implementation causes non-native behavior on some platforms. Subclasses - * should override this method and not call the super + * Handle the erase event. The default implementation colors the background of + * selected areas with "org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND" and + * foregrounds with "org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND". Note + * that this implementation causes non-native behavior on some platforms. + * Subclasses should override this method and not call the super * implementation. * - * @param event - * the erase event - * @param element - * the model object + * @param event the erase event + * @param element the model object * @see SWT#EraseItem - * @see SWT#COLOR_LIST_SELECTION - * @see SWT#COLOR_LIST_SELECTION_TEXT */ protected void erase(Event event, Object element) { @@ -189,11 +187,16 @@ protected void erase(Event event, Object element) { Color oldForeground = event.gc.getForeground(); Color oldBackground = event.gc.getBackground(); - event.gc.setBackground(event.item.getDisplay().getSystemColor( - SWT.COLOR_LIST_SELECTION)); - event.gc.setForeground(event.item.getDisplay().getSystemColor( - SWT.COLOR_LIST_SELECTION_TEXT)); + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + if (event.widget instanceof Control control && control.isFocusControl()) { + event.gc.setBackground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND")); //$NON-NLS-1$ + event.gc.setForeground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND")); //$NON-NLS-1$ + } else { + event.gc.setBackground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS")); //$NON-NLS-1$ + event.gc.setForeground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS")); //$NON-NLS-1$ + } event.gc.fillRectangle(bounds); + /* restore the old GC colors */ event.gc.setForeground(oldForeground); event.gc.setBackground(oldBackground); diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StyledCellLabelProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StyledCellLabelProvider.java index 4d1872cf13b..1b29e15c69e 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StyledCellLabelProvider.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StyledCellLabelProvider.java @@ -263,6 +263,7 @@ protected void erase(Event event, Object element) { // info has been set by 'update': announce that we paint ourselves event.detail &= ~SWT.FOREGROUND; } + super.erase(event, element); } @Override diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TableViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TableViewer.java index 8966573b3f3..6baf6b0e07a 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TableViewer.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TableViewer.java @@ -20,6 +20,7 @@ package org.eclipse.jface.viewers; import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.viewers.internal.ColumnViewerSelectionColorListener; import org.eclipse.jface.viewers.internal.ExpandableNode; import org.eclipse.pde.api.tools.annotations.NoExtend; import org.eclipse.swt.SWT; @@ -119,6 +120,7 @@ public TableViewer(Composite parent, int style) { public TableViewer(Table table) { this.table = table; hookControl(table); + overwriteSelectionColor(); } @Override @@ -507,4 +509,13 @@ void handleExpandableNodeClicked(Widget w) { } } + /** + * The color of the selected item is drawn by the OS. On some OS the color might + * be not accessible. To fix this issue the background color for selected items + * is drawn in a custom method. + */ + private void overwriteSelectionColor() { + ColumnViewerSelectionColorListener.addListenerToViewer(this); + } + } diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java index 55eae5315c0..5f86b75e1ac 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/TreeViewer.java @@ -25,6 +25,7 @@ import java.util.List; import org.eclipse.jface.util.Policy; +import org.eclipse.jface.viewers.internal.ColumnViewerSelectionColorListener; import org.eclipse.jface.viewers.internal.ExpandableNode; import org.eclipse.pde.api.tools.annotations.NoExtend; import org.eclipse.swt.SWT; @@ -137,6 +138,7 @@ public TreeViewer(Tree tree) { super(); this.tree = tree; hookControl(tree); + overwriteSelectionColor(); } @Override @@ -1188,4 +1190,13 @@ Object getLastElement(Widget parent) { } return items[length - 1].getData(); } + + /** + * The color of the selected item is drawn by the OS. On some OS the color might + * be not accessible. To fix this issue the background color for selected items + * is drawn in a custom method. + */ + private void overwriteSelectionColor() { + ColumnViewerSelectionColorListener.addListenerToViewer(this); + } } diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/internal/ColumnViewerSelectionColorListener.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/internal/ColumnViewerSelectionColorListener.java new file mode 100644 index 00000000000..fbc6e7ea40a --- /dev/null +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/internal/ColumnViewerSelectionColorListener.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2024 SAP SE. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.jface.viewers.internal; + +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Scrollable; + +/** + * EraseItem event listener that takes care of coloring the selection color of + * column viewers. The coloring is only applied if no other erase item listener + * is registered for the viewer. If other erase item listeners are registers, + * most probably a other customer coloring is applied and should not be + * overwritten. + * + * @see FocusCellOwnerDrawHighlighter + */ +public class ColumnViewerSelectionColorListener implements Listener { + + /** + * Registers an erase item event listener that takes care of coloring the + * selection color of the given viewer. + * + * @param viewer The viewer that should be colored + */ + public static void addListenerToViewer(StructuredViewer viewer) { + viewer.getControl().addListener(SWT.EraseItem, new ColumnViewerSelectionColorListener()); + } + + @Override + public void handleEvent(Event event) { + if ((event.detail & SWT.SELECTED) == 0) { + return; /* item not selected */ + } + + if (event.widget instanceof Control control && !control.isEnabled()) { + return; /* item is disabled, no coloring required */ + } + + Listener[] eraseItemListeners = event.widget.getListeners(SWT.EraseItem); + if (eraseItemListeners.length != 1) { + return; /* other eraseItemListener exists, do not apply coloring */ + } + + GC gc = event.gc; + ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); + if (event.widget instanceof Control control && control.isFocusControl()) { + gc.setBackground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND")); //$NON-NLS-1$ + gc.setForeground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND")); //$NON-NLS-1$ + } else { + gc.setBackground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS")); //$NON-NLS-1$ + gc.setForeground(colorRegistry.get("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS")); //$NON-NLS-1$ + } + + int width = event.width; + if (event.widget instanceof Scrollable scrollable) { + width = scrollable.getClientArea().width; + } + + gc.fillRectangle(0, event.y, width, event.height); + + event.detail &= ~SWT.SELECTED; + } + +} diff --git a/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css b/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css index b9adbc6bbb2..4fda7024e51 100644 --- a/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css +++ b/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css @@ -65,6 +65,8 @@ IEclipsePreferences#org-eclipse-ui-workbench:org-eclipse-ui-themes { /* pseudo a 'org.eclipse.ui.workbench.FORM_HEADING_ERROR_COLOR=255,110,110' 'org.eclipse.ui.workbench.FORM_HEADING_WARNING_COLOR=255,200,0' 'org.eclipse.ui.workbench.FORM_HEADING_INFO_COLOR=170,170,170' + 'org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS=240,240,240' + 'org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS=95,95,95' 'ERROR_COLOR=247,68,117' 'HYPERLINK_COLOR=111,197,238' 'INCOMING_COLOR=31,179,235' diff --git a/bundles/org.eclipse.ui.themes/css/e4-dark_win.css b/bundles/org.eclipse.ui.themes/css/e4-dark_win.css index 0b0afa540d0..a61c5268db1 100644 --- a/bundles/org.eclipse.ui.themes/css/e4-dark_win.css +++ b/bundles/org.eclipse.ui.themes/css/e4-dark_win.css @@ -135,3 +135,9 @@ ImageBasedFrame, color: #DDDDDD; } +IEclipsePreferences#org-eclipse-ui-workbench:org-eclipse-ui-themes-win { /* pseudo attribute added to allow contributions without replacing this node, see Bug 466075 */ + preferences: + 'org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND=255,255,255' + 'org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND=0,100,255' +} + diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java new file mode 100644 index 00000000000..a2e852d3458 --- /dev/null +++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2024 SAP SE. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.themes; + +import java.util.Hashtable; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.themes.IColorFactory; + +/** + * The factory to provide the default colors for viewer selections. The default + * color is based on the system color for the title, which is the actual + * highlight color. The color can be overwritten via the color preferences. + * + * @since 3.5 + * + */ +public class ColumnViewerSelectionColorFactory implements IColorFactory, IExecutableExtension { + + private String color = null; + + @Override + public RGB createColor() { + if ("SELECTED_CELL_BACKGROUND".equals(color)) { //$NON-NLS-1$ + return Display.getDefault().getSystemColor(SWT.COLOR_TITLE_BACKGROUND).getRGB(); + + } else if ("SELECTED_CELL_FOREGROUND".equals(color)) { //$NON-NLS-1$ + // Selection foreground should be white if not changed by the user + return Display.getDefault().getSystemColor(SWT.COLOR_WHITE).getRGB(); + + } else if ("SELECTED_CELL_BACKGROUND_NO_FOCUS".equals(color)) { //$NON-NLS-1$ + return Display.getDefault().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND).getRGB(); + + } else if ("SELECTED_CELL_FOREGROUND_NO_FOCUS".equals(color)) { //$NON-NLS-1$ + return Display.getDefault().getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND).getRGB(); + + } else { + return null; + } + } + + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) { + if (data instanceof Hashtable table) { + this.color = (String) table.get("color"); //$NON-NLS-1$ + } + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.ui/plugin.properties b/bundles/org.eclipse.ui/plugin.properties index 525c2caece2..af2b0558d89 100644 --- a/bundles/org.eclipse.ui/plugin.properties +++ b/bundles/org.eclipse.ui/plugin.properties @@ -374,6 +374,15 @@ Color.showKeysForegroundDesc=Color for foreground of the control to visualize pr Color.showKeysBackground=Keys background color Color.showKeysBackgroundDesc=Color for background of the control to visualize pressed keys +Color.selectedCellForeground=Selection foreground color for cell viewer +Color.selectedCellForegroundDesc=The selection foreground color of a cell viewer +Color.selectedCellBackground=Selection background color for cell viewer +Color.selectedCellBackgroundDesc=The selection background color of a cell viewer +Color.selectedCellForegroundNoFocus=Selection foreground color for cell viewer without focus +Color.selectedCellForegroundNoFocusDesc=The selection foreground color of a cell viewer without focus +Color.selectedCellBackgroundNoFocus=Selection background color for cell viewer without focus +Color.selectedCellBackgroundNoFocusDesc=The selection background color of a cell viewer without focus + ThemeName.SystemDefault = Reduced Palette HighContrast.ThemeDescription = A theme that takes all of its values from the system settings. diff --git a/bundles/org.eclipse.ui/plugin.xml b/bundles/org.eclipse.ui/plugin.xml index f4523fefbd8..89153764ace 100644 --- a/bundles/org.eclipse.ui/plugin.xml +++ b/bundles/org.eclipse.ui/plugin.xml @@ -2054,6 +2054,74 @@ %Color.showKeysBackgroundDesc + + + %Color.selectedCellForegroundDesc + + + + + + + + + %Color.selectedCellBackgroundDesc + + + + + + + + + %Color.selectedCellForegroundNoFocusDesc + + + + + + + + + %Color.selectedCellBackgroundNoFocusDesc + + + + + + diff --git a/tests/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF index fca4c84b39c..51b2455467c 100644 --- a/tests/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF @@ -6,6 +6,8 @@ Bundle-Version: 3.13.500.qualifier Bundle-Vendor: %Plugin.providerName Bundle-Localization: plugin Export-Package: + org.eclipse.jface.internal.text, + org.eclipse.jface.internal.text.contentassist, org.eclipse.jface.text.tests, org.eclipse.jface.text.tests.codemining, org.eclipse.jface.text.tests.contentassist, @@ -22,7 +24,8 @@ Require-Bundle: org.eclipse.text.tests;bundle-version="[3.5.0,4.0.0)", org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", org.eclipse.ui.workbench.texteditor, - org.eclipse.test.performance;bundle-version="3.13.0" + org.eclipse.test.performance;bundle-version="3.13.0", + org.mockito.mockito-core;bundle-version="5.12.0" Bundle-RequiredExecutionEnvironment: JavaSE-17 Eclipse-BundleShape: dir Automatic-Module-Name: org.eclipse.jface.text.tests diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/TableOwnerDrawSupportTest.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/TableOwnerDrawSupportTest.java new file mode 100644 index 00000000000..558c5c9aaeb --- /dev/null +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/TableOwnerDrawSupportTest.java @@ -0,0 +1,93 @@ +package org.eclipse.jface.internal.text; + +import static org.mockito.Mockito.doReturn; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; + +public class TableOwnerDrawSupportTest { + + private static final int EVENT_Y= 2; + + private static final int EVENT_HEIGHT= 3; + + private Table table; + + private Event event; + + private RGB selectedRowBackgroundColor= new RGB(0, 0, 0); + + private RGB selectedRowForegroundColor= new RGB(1, 1, 1); + + private RGB selectedRowBackgroundColorNoFocus= new RGB(2, 2, 2); + + private RGB selectedRowForegroundColorNoFocus= new RGB(3, 3, 3); + + private GC gc; + + @Before + public void setup() { + Shell shell= new Shell(Display.getDefault()); + Table originalTable= new Table(shell, SWT.SINGLE); + //Spy in order to overwrite isFocusControl() + table= Mockito.spy(originalTable); + + TableItem tableItem= Mockito.mock(TableItem.class); + Mockito.when(tableItem.getParent()).thenReturn(table); + + gc= Mockito.mock(GC.class); + event= new Event(); + event.type= SWT.PaintItem; + event.gc= gc; + event.detail= SWT.SELECTED; + event.item= tableItem; + event.y= EVENT_Y; + event.height= EVENT_HEIGHT; + + Display.getDefault(); + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND", new RGB(0, 0, 0)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND", new RGB(1, 1, 1)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS", new RGB(2, 2, 2)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS", new RGB(3, 3, 3)); + + TableOwnerDrawSupport.install(table); + } + + @Test + public void testPaintSelectionFocus() { + doReturn(true).when(table).isFocusControl(); + + table.notifyListeners(SWT.PaintItem, event); + + Mockito.verify(gc).setBackground(new Color(selectedRowBackgroundColor)); + Mockito.verify(gc).setForeground(new Color(selectedRowForegroundColor)); + Mockito.verify(gc).fillRectangle(0, EVENT_Y, table.getBounds().width, EVENT_HEIGHT); + } + + @Test + public void testPaintSelectionNoFocus() { + doReturn(false).when(table).isFocusControl(); + + table.notifyListeners(SWT.PaintItem, event); + + Mockito.verify(gc).setBackground(new Color(selectedRowBackgroundColorNoFocus)); + Mockito.verify(gc).setForeground(new Color(selectedRowForegroundColorNoFocus)); + Mockito.verify(gc).fillRectangle(0, EVENT_Y, table.getBounds().width, EVENT_HEIGHT); + } + +} diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupportTest.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupportTest.java new file mode 100644 index 00000000000..b89a9833bfc --- /dev/null +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/internal/text/contentassist/CompletionTableDrawSupportTest.java @@ -0,0 +1,92 @@ +package org.eclipse.jface.internal.text.contentassist; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize; +import static org.hamcrest.collection.IsArrayWithSize.emptyArray; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.mockito.Mockito; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import org.eclipse.jface.internal.text.TableOwnerDrawSupport; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; + +public class CompletionTableDrawSupportTest { + + @Test + public void testInstall() { + Shell shell= new Shell(); + Table table= new Table(shell, SWT.NONE); + + assertThat(table.getListeners(SWT.MeasureItem), emptyArray()); + assertThat(table.getListeners(SWT.EraseItem), emptyArray()); + assertThat(table.getListeners(SWT.PaintItem), emptyArray()); + + CompletionTableDrawSupport.install(table); + + assertThat(table.getListeners(SWT.MeasureItem), arrayWithSize(1)); + assertThat(table.getListeners(SWT.MeasureItem)[0], instanceOf(TableOwnerDrawSupport.class)); + assertThat(table.getListeners(SWT.EraseItem), arrayWithSize(1)); + assertThat(table.getListeners(SWT.EraseItem)[0], instanceOf(TableOwnerDrawSupport.class)); + assertThat(table.getListeners(SWT.PaintItem), arrayWithSize(1)); + assertThat(table.getListeners(SWT.PaintItem)[0], instanceOf(TableOwnerDrawSupport.class)); + } + + @Test + public void testStoreStyleRanges() { + Shell shell= new Shell(); + Table table= new Table(shell, SWT.NONE); + TableItem tableItem= new TableItem(table, SWT.NONE); + StyleRange[] ranges= new StyleRange[] {}; + + CompletionTableDrawSupport.storeStyleRanges(tableItem, 2, ranges); + + assertEquals(ranges, tableItem.getData("styled_ranges2")); + } + + @Test + public void testPaintNonFocusSelectionInFocusColors() { + int EVENT_Y= 2; + int EVENT_HEIGHT= 3; + + Shell shell= new Shell(); + Table table= new Table(shell, SWT.NONE); + TableItem tableItem= new TableItem(table, SWT.NONE); + + ColorRegistry colorRegistry= JFaceResources.getColorRegistry(); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND", new RGB(0, 0, 0)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND", new RGB(1, 1, 1)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_BACKGROUND_NO_FOCUS", new RGB(2, 2, 2)); + colorRegistry.put("org.eclipse.ui.workbench.SELECTED_CELL_FOREGROUND_NO_FOCUS", new RGB(3, 3, 3)); + + GC gc= Mockito.mock(GC.class); + Event event= new Event(); + event.type= SWT.PaintItem; + event.gc= gc; + event.detail= SWT.SELECTED; + event.item= tableItem; + event.y= EVENT_Y; + event.height= EVENT_HEIGHT; + + CompletionTableDrawSupport.install(table); + + table.notifyListeners(SWT.PaintItem, event); + + Mockito.verify(gc).setBackground(new Color(new RGB(0, 0, 0))); + Mockito.verify(gc).setForeground(new Color(new RGB(1, 1, 1))); + Mockito.verify(gc).fillRectangle(0, EVENT_Y, table.getBounds().width, EVENT_HEIGHT); + } + +} diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java index 1b190e48845..cc939d99d56 100644 --- a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java @@ -17,6 +17,9 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; +import org.eclipse.jface.internal.text.TableOwnerDrawSupportTest; +import org.eclipse.jface.internal.text.contentassist.CompletionTableDrawSupportTest; + import org.eclipse.jface.text.tests.codemining.CodeMiningProjectionViewerTest; import org.eclipse.jface.text.tests.codemining.CodeMiningTest; import org.eclipse.jface.text.tests.contentassist.AsyncContentAssistTest; @@ -80,7 +83,10 @@ DefaultTextDoubleClickStrategyTest.class, MultiSelectionTest.class, FindReplaceDocumentAdapterContentProposalProviderTest.class, - ProjectionViewerTest.class + ProjectionViewerTest.class, + + TableOwnerDrawSupportTest.class, + CompletionTableDrawSupportTest.class }) public class JFaceTextTestSuite { // see @SuiteClasses