/***************************************************************************** * Copyright (c) 2015, 2017 CEA LIST and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation * *****************************************************************************/ package org.eclipse.nebula.widgets.nattable.extension.e4.css; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.e4.ui.css.core.css2.CSS2ColorHelper; import org.eclipse.e4.ui.css.core.css2.CSS2FontHelper; import org.eclipse.e4.ui.css.core.dom.properties.css2.CSS2FontProperties; import org.eclipse.e4.ui.css.core.engine.CSSElementContext; import org.eclipse.e4.ui.css.core.engine.CSSEngine; import org.eclipse.e4.ui.css.swt.helpers.CSSSWTFontHelper; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBigDecimalDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBigIntegerDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBooleanDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultByteDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultCharacterDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDateDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDoubleDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultFloatDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultIntegerDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultLongDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.DefaultShortDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter; import org.eclipse.nebula.widgets.nattable.data.convert.PercentageDisplayConverter; import org.eclipse.nebula.widgets.nattable.style.BorderStyle; import org.eclipse.nebula.widgets.nattable.style.BorderStyle.BorderModeEnum; import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum; import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; import org.eclipse.nebula.widgets.nattable.style.CellStyleProxy; import org.eclipse.nebula.widgets.nattable.style.ConfigAttribute; import org.eclipse.nebula.widgets.nattable.style.DefaultDisplayModeOrdering; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.nebula.widgets.nattable.style.IDisplayModeOrdering; import org.eclipse.nebula.widgets.nattable.style.IStyle; import org.eclipse.nebula.widgets.nattable.style.Style; import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.widgets.Display; import org.w3c.dom.css.CSSPrimitiveValue; import org.w3c.dom.css.CSSValue; import org.w3c.dom.css.CSSValueList; /** * Helper class for converting and applying CSS styles. */ @SuppressWarnings("restriction") public class NatTableCSSHelper { private static final IDisplayModeOrdering displayModeOrdering = new DefaultDisplayModeOrdering(); /** * Return the <code>boolean</code> value that represents the given * {@link CSSValue}. * * @param value * The value for which the boolean value should be returned. * @param defaultValue * The default value to return if the given value can not be * converted to a boolean. * @return The boolean representation of the given value or the default * value if it can not be converted. */ public static boolean getBoolean(CSSValue value, boolean defaultValue) { String stringValue = value.getCssText().toLowerCase(); Boolean result = defaultValue; if ("true".equals(stringValue)) { result = true; } else if ("false".equals(stringValue)) { result = false; } return result; } /** * Returns the NatTable {@link DisplayMode} for the given pseudo class. * * @param pseudo * The pseudo class. * @return The {@link DisplayMode} value for the given pseudo class. */ public static String getDisplayMode(String pseudo) { if (pseudo != null) { if ("select".equals(pseudo)) { return DisplayMode.SELECT; } else if ("edit".equals(pseudo)) { return DisplayMode.EDIT; } else if ("hover".equals(pseudo)) { return DisplayMode.HOVER; } else if ("select-hover".equals(pseudo)) { return DisplayMode.SELECT_HOVER; } } return DisplayMode.NORMAL; } /** * Returns the NatTable {@link CellEdgeEnum} for the given string * representation. * * @param value * The string representation of the {@link CellEdgeEnum} * @return The {@link CellEdgeEnum} for the string representation. */ public static CellEdgeEnum getCellEdgeEnum(String value) { if ("top".equalsIgnoreCase(value)) { return CellEdgeEnum.TOP; } else if ("bottom".equalsIgnoreCase(value)) { return CellEdgeEnum.BOTTOM; } else if ("right".equalsIgnoreCase(value)) { return CellEdgeEnum.RIGHT; } else if ("left".equalsIgnoreCase(value)) { return CellEdgeEnum.LEFT; } else if ("top-right".equalsIgnoreCase(value)) { return CellEdgeEnum.TOP_RIGHT; } else if ("top-left".equalsIgnoreCase(value)) { return CellEdgeEnum.TOP_LEFT; } else if ("bottom-right".equalsIgnoreCase(value)) { return CellEdgeEnum.BOTTOM_RIGHT; } else if ("bottom-left".equalsIgnoreCase(value)) { return CellEdgeEnum.BOTTOM_LEFT; } return CellEdgeEnum.NONE; } /** * Returns the NatTable {@link IDisplayConverter} for the given string * representation. * * @param value * The string representation of the {@link IDisplayConverter} * @param format * flag for number display converters to specify whether * {@link NumberFormat} should be used to format or not. * @param minFractionDigits * number of minimum fraction digits to use in case a * {@link NumberFormat} is used for formatting a number value * @param maxFractionDigits * number of maximum fraction digits to use in case a * {@link NumberFormat} is used for formatting a number value * @param datePattern * The pattern to use for formatting a date value when a date * display converter requested * @return The {@link IDisplayConverter} for the string representation. */ public static IDisplayConverter getDisplayConverter( String value, boolean format, Integer minFractionDigits, Integer maxFractionDigits, String datePattern) { if ("boolean".equalsIgnoreCase(value)) { return new DefaultBooleanDisplayConverter(); } else if ("character".equalsIgnoreCase(value)) { return new DefaultCharacterDisplayConverter(); } else if ("date".equalsIgnoreCase(value)) { return new DefaultDateDisplayConverter(datePattern); } else if ("default".equalsIgnoreCase(value)) { return new DefaultDisplayConverter(); } else if ("percentage".equalsIgnoreCase(value)) { return new PercentageDisplayConverter(); } else if ("byte".equalsIgnoreCase(value)) { return new DefaultByteDisplayConverter(); } else if ("short".equalsIgnoreCase(value)) { return new DefaultShortDisplayConverter(format); } else if ("int".equalsIgnoreCase(value)) { return new DefaultIntegerDisplayConverter(format); } else if ("long".equalsIgnoreCase(value)) { return new DefaultLongDisplayConverter(format); } else if ("big-int".equalsIgnoreCase(value)) { return new DefaultBigIntegerDisplayConverter(); } else if ("float".equalsIgnoreCase(value)) { DefaultFloatDisplayConverter result = new DefaultFloatDisplayConverter(format); if (minFractionDigits != null) { result.getNumberFormat().setMinimumFractionDigits(minFractionDigits); } if (maxFractionDigits != null) { result.getNumberFormat().setMaximumFractionDigits(maxFractionDigits); } return result; } else if ("double".equalsIgnoreCase(value)) { DefaultDoubleDisplayConverter result = new DefaultDoubleDisplayConverter(format); if (minFractionDigits != null) { result.getNumberFormat().setMinimumFractionDigits(minFractionDigits); } if (maxFractionDigits != null) { result.getNumberFormat().setMaximumFractionDigits(maxFractionDigits); } return result; } else if ("big-decimal".equalsIgnoreCase(value)) { DefaultBigDecimalDisplayConverter result = new DefaultBigDecimalDisplayConverter(); if (minFractionDigits != null) { result.getNumberFormat().setMinimumFractionDigits(minFractionDigits); } if (maxFractionDigits != null) { result.getNumberFormat().setMaximumFractionDigits(maxFractionDigits); } return result; } return new DefaultDateDisplayConverter(); } /** * * @param converter * The {@link IDisplayConverter} for which the String * representation is requested. * @return The String representation for the given * {@link IDisplayConverter}. */ public static String getDisplayConverterString(IDisplayConverter converter) { if (converter instanceof DefaultBooleanDisplayConverter) { return "boolean"; } else if (converter instanceof DefaultCharacterDisplayConverter) { return "character"; } else if (converter instanceof DefaultDateDisplayConverter) { return "date"; } else if (converter instanceof PercentageDisplayConverter) { return "percentage"; } else if (converter instanceof DefaultByteDisplayConverter) { return "byte"; } else if (converter instanceof DefaultShortDisplayConverter) { return "short"; } else if (converter instanceof DefaultIntegerDisplayConverter) { return "int"; } else if (converter instanceof DefaultLongDisplayConverter) { return "long"; } else if (converter instanceof DefaultBigIntegerDisplayConverter) { return "big-int"; } else if (converter instanceof DefaultFloatDisplayConverter) { return "float"; } else if (converter instanceof DefaultDoubleDisplayConverter) { return "double"; } else if (converter instanceof DefaultBigDecimalDisplayConverter) { return "big-decimal"; } return "default"; } /** * * @param value * The value to check. * @return <code>true</code> if the given value represents a valid converter * key, <code>false</code> if not. */ public static boolean isConverterString(String value) { return ("boolean".equalsIgnoreCase(value) || "character".equalsIgnoreCase(value) || "date".equalsIgnoreCase(value) || "default".equalsIgnoreCase(value) || "percentage".equalsIgnoreCase(value) || "byte".equalsIgnoreCase(value) || "short".equalsIgnoreCase(value) || "int".equalsIgnoreCase(value) || "long".equalsIgnoreCase(value) || "big-int".equalsIgnoreCase(value) || "float".equalsIgnoreCase(value) || "double".equalsIgnoreCase(value) || "big-decimal".equalsIgnoreCase(value)); } /** * Retrieves the style attribute for the given display mode and config * labels out of the NatTable configuration. Uses the NatTable internal * inheritance model to always retrieve a style configuration attribute if * there is one configured at any level. * * @param natTable * The NatTable whose {@link ConfigRegistry} should be checked * for the style configuration. * @param styleConfig * The style {@link ConfigAttribute} that is requested. * @param displayMode * The {@link DisplayMode} for which the configuration is * requested. * @param configLabels * The config labels for which the configuration is requested. * @return The style attribute for the given display mode and config labels * out of the NatTable configuration. */ public static <T> T getNatTableStyle(NatTable natTable, ConfigAttribute<T> styleConfig, String displayMode, String... configLabels) { IConfigRegistry configRegistry = natTable.getConfigRegistry(); IStyle style = new CellStyleProxy(configRegistry, displayMode, Arrays.asList(configLabels)); return style.getAttributeValue(styleConfig); } /** * Apply a style attribute value for the {@link IStyle} registered for * {@link CellConfigAttributes#CELL_STYLE}. * * @param natTable * The NatTable to apply the style configuration to. * @param styleConfig * The style {@link ConfigAttribute} that should be applied. * @param value * The value to apply. * @param displayMode * The {@link DisplayMode} for which the configuration should be * applied. * @param configLabel * The label for which the configuration should be applied. */ public static <T> void applyNatTableStyle( NatTable natTable, ConfigAttribute<T> styleConfig, T value, String displayMode, String configLabel) { applyNatTableStyle(natTable, CellConfigAttributes.CELL_STYLE, styleConfig, value, displayMode, configLabel); } /** * Apply a style attribute value for the {@link IStyle} registered for the * given styleAttribute. * * @param natTable * The NatTable to apply the style configuration to. * @param styleAttribute * The {@link ConfigAttribute} that points to the {@link IStyle} * that should be configured. * @param styleConfig * The style {@link ConfigAttribute} that should be applied. * @param value * The value to apply. * @param displayMode * The {@link DisplayMode} for which the configuration should be * applied. * @param configLabel * The label for which the configuration should be applied. */ public static <T> void applyNatTableStyle( NatTable natTable, ConfigAttribute<IStyle> styleAttribute, ConfigAttribute<T> styleConfig, T value, String displayMode, String configLabel) { IConfigRegistry configRegistry = natTable.getConfigRegistry(); // retrieve the style object for the given selector IStyle style = configRegistry.getSpecificConfigAttribute( styleAttribute, displayMode, configLabel); if (style == null) { style = new Style(); if (configLabel != null) { configRegistry.registerConfigAttribute( styleAttribute, style, displayMode, configLabel); } else { configRegistry.registerConfigAttribute( styleAttribute, style, displayMode); } } // set the value to the style object style.setAttributeValue( styleConfig, value); } /** * Returns the {@link CSS2FontProperties} out of the given * {@link CSSElementContext} for the given parameters. If no * {@link CSS2FontProperties} exist, a new instance will be created and * pre-filled with font values based on inheritance. * * @param context * The {@link CSSElementContext} to search for the context value. * @param contextKey * The context key under which the font properties are stored. * @param natTable * The NatTable instance to apply the styles to * @param displayMode * The target {@link DisplayMode} to check for the value. * @param label * The label for which the font properties are requested. * @return The {@link CSS2FontProperties} for the given attributes. */ public static CSS2FontProperties getFontProperties( CSSElementContext context, String contextKey, NatTable natTable, String displayMode, String label) { // check if there are font properties already registered CSS2FontProperties fontProperties = (CSS2FontProperties) getContextValue(context, displayMode, contextKey); if (fontProperties == null) { // check if there is a font registered in the hierarchy Font font = getNatTableStyle(natTable, CellStyleAttributes.FONT, displayMode, label); if (font == null) { // if there are no font properties already and no font, use the // default font font = GUIHelper.DEFAULT_FONT; } fontProperties = CSSSWTFontHelper.getCSS2FontProperties(font); // store the font properties for further use storeContextValue(context, displayMode, contextKey, fontProperties); } return fontProperties; } /** * Sets the values from the given {@link CSSValueList} to the given * {@link CSS2FontProperties}CSS2FontProperties. * * @param valueList * The value list containing the css property values * @param font * The font properties to set the values to */ public static void setFontProperties(CSSValueList valueList, CSS2FontProperties font) { int length = valueList.getLength(); for (int i = 0; i < length; i++) { CSSValue value2 = valueList.item(i); if (value2.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { String fontProperty = CSS2FontHelper.getCSSFontPropertyName((CSSPrimitiveValue) value2); if (fontProperty != null) { if (NatTableCSSConstants.FONT_FAMILY.equalsIgnoreCase(fontProperty)) { font.setFamily((CSSPrimitiveValue) value2); } else if (NatTableCSSConstants.FONT_SIZE.equalsIgnoreCase(fontProperty)) { font.setSize((CSSPrimitiveValue) value2); } else if (NatTableCSSConstants.FONT_STYLE.equalsIgnoreCase(fontProperty)) { font.setStyle((CSSPrimitiveValue) value2); } else if (NatTableCSSConstants.FONT_WEIGHT.equalsIgnoreCase(fontProperty)) { font.setWeight((CSSPrimitiveValue) value2); } } } } } /** * Returns the {@link BorderStyle} out of the given * {@link CSSElementContext} for the given {@link DisplayMode}. * * @param context * The {@link CSSElementContext} to search for the context value. * @param displayMode * The {@link DisplayMode} for which the value should be stored. * @return The {@link BorderStyle} */ public static BorderStyle getBorderStyle(CSSElementContext context, String displayMode) { BorderStyle borderStyle = (BorderStyle) getContextValue(context, displayMode, NatTableCSSConstants.CV_BORDER_CONFIGURATION); if (borderStyle == null) { borderStyle = new BorderStyle(); storeContextValue(context, displayMode, NatTableCSSConstants.CV_BORDER_CONFIGURATION, borderStyle); } return borderStyle; } /** * Convert and store the values of the given {@link CSSValueList} to the * given {@link BorderStyle}. * * @param valueList * The {@link CSSValueList} with the values to convert. * @param borderStyle * The {@link BorderStyle} to store the converted values to. * @param engine * The {@link CSSEngine} needed for conversion. * @param display * The display needed for color conversion. * @throws Exception * if the value conversion fails */ public static void storeBorderStyle( CSSValueList valueList, BorderStyle borderStyle, CSSEngine engine, Display display) throws Exception { int length = valueList.getLength(); for (int i = 0; i < length; i++) { CSSValue value2 = valueList.item(i); if (value2.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { CSSPrimitiveValue primitiveValue = (CSSPrimitiveValue) value2; short type = primitiveValue.getPrimitiveType(); switch (type) { case CSSPrimitiveValue.CSS_IDENT: if (CSS2ColorHelper.isColorName(primitiveValue.getStringValue())) { borderStyle.setColor( (Color) engine.convert(value2, Color.class, display)); } else if (isLineStyle(primitiveValue.getStringValue().toUpperCase())) { borderStyle.setLineStyle( LineStyleEnum.valueOf(primitiveValue.getStringValue().toUpperCase())); } else { borderStyle.setBorderMode( BorderModeEnum.valueOf(primitiveValue.getStringValue().toUpperCase())); } break; case CSSPrimitiveValue.CSS_RGBCOLOR: borderStyle.setColor( (Color) engine.convert(value2, Color.class, display)); break; case CSSPrimitiveValue.CSS_PT: case CSSPrimitiveValue.CSS_NUMBER: case CSSPrimitiveValue.CSS_PX: borderStyle.setThickness( (int) ((CSSPrimitiveValue) value2).getFloatValue(CSSPrimitiveValue.CSS_PT)); break; } } } } /** * * @param style * The String value that should be checked if it is a * {@link LineStyleEnum} value. * @return <code>true</code> if the given String is a {@link LineStyleEnum}, * <code>false</code> if not. */ private static boolean isLineStyle(String style) { try { LineStyleEnum.valueOf(style); } catch (IllegalArgumentException e) { return false; } return true; } /** * Convert and store the padding value for the given key in the painter * properties map. * * @param paddingKey * The key of the padding property. * @param value * The {@link CSSValue} of the padding that should be converted * and stored. * @param context * The {@link CSSElementContext} to search for the configuration * value. * @param displayMode * The target {@link DisplayMode} to check for the value. */ public static void storePadding( String paddingKey, CSSValue value, CSSElementContext context, String displayMode) { if (value.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { CSSPrimitiveValue primitiveValue = (CSSPrimitiveValue) value; short type = primitiveValue.getPrimitiveType(); if (type == CSSPrimitiveValue.CSS_PT || type == CSSPrimitiveValue.CSS_NUMBER || type == CSSPrimitiveValue.CSS_PX) { int padding = (int) primitiveValue.getFloatValue(CSSPrimitiveValue.CSS_PT); getPainterProperties(context, displayMode) .put(paddingKey, padding); } } } /** * Check if the automatic painter resolution is enabled or disabled via CSS * property. * * @param context * The {@link CSSElementContext} to search for the configuration * value. * @param natTableContext * The {@link CSSElementContext} of the parent NatTable or * <code>null</code> in case the context parameter is already * from the NatTable itself. * @param displayMode * The target {@link DisplayMode} to check for the value. * @return <code>true</code> if the painter to use should be automatically * resolved, <code>false</code> if the painter is configured * elsewhere and therefore no automatic resolution should be * performed. Default is <code>true</code>. */ public static boolean resolvePainter( CSSElementContext context, CSSElementContext natTableContext, String displayMode) { Object cv = getContextValueInherited( context, natTableContext, displayMode, NatTableCSSConstants.PAINTER_RESOLUTION); return (cv != null) ? (Boolean) cv : Boolean.TRUE; } /** * Returns the string representation list of cell painter decorators that * should be used to build up the cell painter for rendering. * * @param context * The {@link CSSElementContext} to search for the context value. * @param displayMode * The {@link DisplayMode} for which the value should be stored. * @return The string representation of decorator painter that should be * used for rendering. */ public static List<String> getDecoratorPainter(CSSElementContext context, String displayMode) { @SuppressWarnings("unchecked") List<String> decorator = (List<String>) getContextValue(context, displayMode, NatTableCSSConstants.CV_DECORATOR_PAINTER); if (decorator == null) { decorator = new ArrayList<>(); storeContextValue(context, displayMode, NatTableCSSConstants.CV_DECORATOR_PAINTER, decorator); } return decorator; } /** * Returns the painter properties out of the given {@link CSSElementContext} * for the given {@link DisplayMode}. * * @param context * The {@link CSSElementContext} to search for the context value. * @param displayMode * The {@link DisplayMode} for which the value should be stored. * @return The properties that should be used to create content painter. */ public static Map<String, Object> getPainterProperties(CSSElementContext context, String displayMode) { @SuppressWarnings("unchecked") Map<String, Object> painterProperties = (Map<String, Object>) getContextValue(context, displayMode, NatTableCSSConstants.CV_PAINTER_CONFIGURATION); if (painterProperties == null) { painterProperties = new HashMap<>(); storeContextValue(context, displayMode, NatTableCSSConstants.CV_PAINTER_CONFIGURATION, painterProperties); } return painterProperties; } /** * Returns the painter properties out of the given {@link CSSElementContext} * for the given {@link DisplayMode} enriched with the painter property * values out of inheritance. * * @param context * The {@link CSSElementContext} to search for the context value. * @param natTableContext * The {@link CSSElementContext} of the parent NatTable or * <code>null</code> in case the context parameter is already * from the NatTable itself. * @param targetDisplayMode * The target {@link DisplayMode} to check for the value. * @return The painter properties with values out of inheritance */ public static Map<String, Object> getPainterPropertiesInherited( CSSElementContext context, CSSElementContext natTableContext, String targetDisplayMode) { Map<String, Object> painterProperties = new HashMap<>(); List<String> displayModes = displayModeOrdering.getDisplayModeOrdering(targetDisplayMode); String displayMode = null; if (natTableContext != null) { // first get the painter properties from tbe NatTable in reverse // displaymode ordering for (int i = displayModes.size() - 1; i >= 0; i--) { displayMode = displayModes.get(i); painterProperties.putAll( getPainterProperties(natTableContext, displayMode)); } } // then do the same for the element context for (int i = displayModes.size() - 1; i >= 0; i--) { displayMode = displayModes.get(i); painterProperties.putAll( getPainterProperties(context, displayMode)); } return painterProperties; } /** * Resolves the painter representations out of the given {@link CSSValue}. * * @param value * The {@link CSSValue} to resolve. * @return The list of string representations for painters. */ public static List<String> resolvePainterRepresentation(CSSValue value) { List<String> painterValues = new ArrayList<>(); if (value.getCssValueType() == CSSValue.CSS_VALUE_LIST) { CSSValueList valueList = (CSSValueList) value; int length = valueList.getLength(); for (int i = 0; i < length; i++) { CSSValue value2 = valueList.item(i); if (value2.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { painterValues.add(value2.getCssText().toLowerCase()); } } } else if (value.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { painterValues.add(value.getCssText().toLowerCase()); } return painterValues; } /** * Put a value for the given key and {@link DisplayMode} to the given * {@link CSSElementContext}. * * @param context * The {@link CSSElementContext} to put the value to. * @param displayMode * The {@link DisplayMode} for which the value should be stored. * @param key * The key for which the value should be stored. * @param value * The value to store. */ public static void storeContextValue(CSSElementContext context, String displayMode, Object key, Object value) { Object subContext = context.getData(displayMode); if (subContext == null) { subContext = new HashMap<>(); context.setData(displayMode, subContext); } @SuppressWarnings("unchecked") Map<Object, Object> displayModeContext = (Map<Object, Object>) subContext; displayModeContext.put(key, value); } /** * Search the value for the given key and {@link DisplayMode} out of the * given {@link CSSElementContext}. * * @param context * The {@link CSSElementContext} out of which the value should be * retrieved. * @param displayMode * The {@link DisplayMode} for which the value is requested. * @param key * The key for which the value is requested. * @return The value for the given {@link DisplayMode} and key out of the * given {@link CSSElementContext}. If no value is found for the * given {@link DisplayMode}, the value out of the given * {@link CSSElementContext} directly is returned. Can be * <code>null</code>. */ public static Object getContextValue(CSSElementContext context, String displayMode, Object key) { Object subContext = context.getData(displayMode); if (subContext != null) { @SuppressWarnings("unchecked") Map<Object, Object> displayModeContext = (Map<Object, Object>) subContext; return displayModeContext.get(key); } return context.getData(key); } /** * Search the value for the given key and {@link DisplayMode} out of the * given {@link CSSElementContext}. Will search for the value also via * inheritance, that means first it will check the * {@link IDisplayModeOrdering} and if there is no value found, it searches * in the parent NatTable context. * * @param context * The {@link CSSElementContext} to search for the context value. * @param natTableContext * The {@link CSSElementContext} of the parent NatTable or * <code>null</code> in case the context parameter is already * from the NatTable itself. * @param targetDisplayMode * The target {@link DisplayMode} to check for the value. * @param key * The key of the context value to search for. * @return The context value for the given key. */ public static Object getContextValueInherited( CSSElementContext context, CSSElementContext natTableContext, String targetDisplayMode, Object key) { Object cv = null; for (String displayMode : displayModeOrdering.getDisplayModeOrdering(targetDisplayMode)) { cv = getContextValue(context, displayMode, key); if (cv != null) { break; } } // not found for any displaymode in context // search in parent context if (cv == null && natTableContext != null) { cv = getContextValueInherited(natTableContext, null, targetDisplayMode, key); } return cv; } }