/******************************************************************************* * Copyright (c) 2007, 2009 compeople AG 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: * compeople AG - initial API and implementation * Florian Pirchner - FontDescriptor *******************************************************************************/ package org.eclipse.riena.ui.swt.lnf.rienadefault; import java.beans.Beans; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.osgi.service.log.LogService; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.log.Logger; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Resource; import org.eclipse.riena.core.Log4r; import org.eclipse.riena.core.util.StringUtils; import org.eclipse.riena.core.wire.InjectExtension; import org.eclipse.riena.ui.core.resource.IconSize; import org.eclipse.riena.ui.ridgets.AbstractMarkerSupport; import org.eclipse.riena.ui.ridgets.IRidget; import org.eclipse.riena.ui.swt.lnf.ColorLnfResource; import org.eclipse.riena.ui.swt.lnf.FontDescriptor; import org.eclipse.riena.ui.swt.lnf.ILnfCustomizer; import org.eclipse.riena.ui.swt.lnf.ILnfMarkerSupportExtension; import org.eclipse.riena.ui.swt.lnf.ILnfRenderer; import org.eclipse.riena.ui.swt.lnf.ILnfRendererExtension; import org.eclipse.riena.ui.swt.lnf.ILnfResource; import org.eclipse.riena.ui.swt.lnf.ILnfTheme; import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants; /** * Default Look and Feel of Riena. */ public class RienaDefaultLnf implements ILnfCustomizer { private static final Logger LOGGER = Log4r.getLogger(RienaDefaultLnf.class); private static final String SYSTEM_PROPERTY_LNF_SETTING_PREFIX = "riena.lnf.setting."; //$NON-NLS-1$ private final Map<String, ILnfResource<?>> resourceTable = new HashMap<String, ILnfResource<?>>(); private final Set<String> resourcePrefixes = new HashSet<String>(); private final Map<String, Object> settingTable = new ConcurrentHashMap<String, Object>(); private final Map<String, ILnfRenderer> rendererTable = new HashMap<String, ILnfRenderer>(); private final Map<IconSize, String> iconSizeGroupIdentifier = new HashMap<IconSize, String>(); private ILnfMarkerSupportExtension[] markerSupportList = new ILnfMarkerSupportExtension[0]; private ILnfTheme theme; private boolean initialized; /** * Create a look and feel with the given theme. * * @param theme * the theme this look and feel will use */ public RienaDefaultLnf(final ILnfTheme theme) { setTheme(theme); } /** * Create a look and feel with no theme. */ public RienaDefaultLnf() { this(null); } public ILnfResource<?> getLnfResource(final String key) { return resourceTable.get(key); } public ILnfResource<?> putLnfResource(final String key, final ILnfResource<?> resource) { final int dot = key.indexOf('.'); if (dot != -1) { resourcePrefixes.add(key.substring(0, dot)); } return resourceTable.put(key, resource); } public boolean containsLnfResourcePrefix(final String prefix) { return resourcePrefixes.contains(prefix); } public Object getLnfSetting(final String key) { return settingTable.get(key); } public Object putLnfSetting(final String key, final Object setting) { return settingTable.put(key, setting); } /** * Returns the String value of the iconsize group identifier for the given Iconsize. * * @param iconSize * the desired iconSize * @return the Group identifier of the mapped iconsize, returns the given iconsize.defaultMapping if no group identifier exists. * @since 6.2 */ public String getIconSizeGroupIdentifier(final IconSize iconSize) { Assert.isNotNull(iconSize, "iconSize must not be null"); //$NON-NLS-1$ final String value = iconSizeGroupIdentifier.get(iconSize); if (value != null) { return value; } return iconSize.getDefaultMapping(); } /** * Maps the the given icon size to the given group. * * @since 6.2 */ public String putIconSizeGroupIdentifier(final IconSize iconSize, final String group) { return iconSizeGroupIdentifier.put(iconSize, group); } /** * Initializes the Look and Feel. Fills the tables of resources and renderers. */ public void initialize() { if (!isInitialized()) { uninitialize(); setInitialized(true); initializeTheme(); readSystemProperties(); } } /** * Reads system properties to overwrite Look&Feel settings. */ private void readSystemProperties() { final Properties sysProps = (Properties) System.getProperties().clone(); final Set<Object> sysPropKeys = sysProps.keySet(); for (final Object propKey : sysPropKeys) { final String propKeyName = propKey.toString(); if (propKeyName.startsWith(SYSTEM_PROPERTY_LNF_SETTING_PREFIX)) { final String lnfKey = propKeyName.substring(SYSTEM_PROPERTY_LNF_SETTING_PREFIX.length()); final Object lnfValue = sysProps.get(propKeyName); putLnfSetting(lnfKey, lnfValue); } } } /** * Uninitializes the Look and Feel. Disposes resources and clears the tables of resources and renderers. */ public void uninitialize() { resourceTable.clear(); resourcePrefixes.clear(); settingTable.clear(); setInitialized(false); } /** * Puts the given renderers into the table of renderer. * * @param rendererExtensions * descriptors of renderer * @since 1.2 */ @InjectExtension public void update(final ILnfRendererExtension[] rendererExtensions) { rendererTable.clear(); for (final ILnfRendererExtension rendererExtension : rendererExtensions) { final String id = rendererExtension.getLnfId(); if (StringUtils.isEmpty(id) || id.equals(getLnfId())) { if (StringUtils.isEmpty(id)) { if (rendererTable.get(rendererExtension.getLnfKey()) != null) { continue; } } rendererTable.put(rendererExtension.getLnfKey(), rendererExtension.createRenderer()); } } } /** * Stores the given marker supports in a list. * * @param markerSupportExtensions * array of marker supports * @since 2.0 */ @InjectExtension public void update(final ILnfMarkerSupportExtension[] markerSupportExtensions) { markerSupportList = markerSupportExtensions; } /** * Returns the marker support that will be used according to the Look&Feel setting ({@code LnfKeyConstants.MARKER_SUPPORT_ID}) and for the given Ridget * class. * * @param ridgetClass * class of the Ridget * @return marker support or {@code null} if no appropriate marker support was found * @since 2.0 */ public AbstractMarkerSupport getMarkerSupport(final Class<? extends IRidget> ridgetClass) { final String markerSupportID = getStringSetting(LnfKeyConstants.MARKER_SUPPORT_ID); for (final ILnfMarkerSupportExtension lnfMarkerSupportExtension : markerSupportList) { if (StringUtils.isEmpty(lnfMarkerSupportExtension.getId())) { continue; } if (lnfMarkerSupportExtension.getId().equals(markerSupportID)) { return lnfMarkerSupportExtension.createMarkerSupport(); } } // only log this when running in an bundle environment if (Platform.getBundle("org.eclipse.swt") != null) { //$NON-NLS-1$ LOGGER.log(LogService.LOG_INFO, "No MarkerSupport with the ID \"" + markerSupportID + "\" exists."); //$NON-NLS-1$ //$NON-NLS-2$ } return null; } /** * Initializes the theme. */ protected void initializeTheme() { putLnfResource("black", new ColorLnfResource(0, 0, 0)); //$NON-NLS-1$ putLnfResource("white", new ColorLnfResource(255, 255, 255)); //$NON-NLS-1$ if (getTheme() != null) { getTheme().customizeLnf(this); } } /** * Returns the resource for the given key. * * @param key * key whose associated resource is to be returned. * @return the resource to which this map maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Resource getResource(final String key) { final ILnfResource<?> value = resourceTable.get(key); if (value != null) { return value.getResource(); } else { return null; } } /** * Returns the color for the given key. * * @param key * key whose associated color is to be returned. * @return the color to which this map maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Color getColor(final String key) { return getColor(key, null); } /** * Returns the color for the given key. * * @param key * key whose associated color is to be returned. * @return the color to which this map maps the specified key, or the {@code defaultValue} if the map contains no mapping for this key. * * @since 2.0 */ public Color getColor(final String key, final Color defaultValue) { final Resource value = getResource(key); if (value instanceof Color) { return (Color) value; } return defaultValue; } /** * Returns the font for the given key. * * @param key * key whose associated font is to be returned. * @return the font to which this map maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Font getFont(final String key) { final Resource value = getResource(key); if (value instanceof Font) { return (Font) value; } else { return null; } } /** * Returns the font for the given key. The passed properties height and style will be applied to the font. <br> * * @param key * key whose associated font is to be returned. * @param height * the font height to use. If it is < 0, the <code>LnfKeyConstants.FONTDESCRIPTOR_DEFAULT_HEIGHT</code> will be used. See also * {@link FontData#setHeight(int)}. * @param style * the font style to use. See also {@link FontData#setStyle(int)} . * * @return the font to which this map maps the specified key with differing height and style, or <code>null</code> if the map contains no mapping for this * lnfKeyConstants key. * @since 1.2 */ public Font getFont(final String key, final int height, final int style) { final FontDescriptor fontDescriptor = new FontDescriptor(key, height, style, this); return fontDescriptor.getFont(); } /** * Returns the image for the given key. * * @param key * key whose associated image is to be returned. * @return the image to which this map maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Image getImage(final String key) { final Resource value = getResource(key); if (value instanceof Image) { return (Image) value; } else { return null; } } /** * Returns the renderer for the given key. * * @param key * key whose associated renderer is to be returned. * @return the renderer to which this renderer maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public ILnfRenderer getRenderer(final String key) { return rendererTable.get(key); } /** * Returns the setting for the given key * * @param key * key whose associated setting is to be returned. * @return the setting to which this setting maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Object getSetting(final String key) { return settingTable.get(key); } /** * Returns the integer value of the setting for the given key * * @param key * key whose associated setting is to be returned. * @return the setting to which this setting maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public Integer getIntegerSetting(final String key) { final Object value = getSetting(key); if (value == null) { if (Beans.isDesignTime()) { // in case of design time we return a "0" so that dependent code does not fail return new Integer(0); } else { return null; } } if (value instanceof Integer) { return (Integer) value; } else { final String strgValue = value.toString(); try { return new Integer(strgValue); } catch (final NumberFormatException e) { if (Beans.isDesignTime()) { // in case of design time we return a "0" so that dependent code does not fail return Integer.valueOf(0); } else { return null; } } } } /** * Returns the integer value of the setting for the given key. If no value is set, the given default value is returned. * * @param key * key whose associated setting is to be returned. * @param defaultValue * value to return, if no value is set * @return the setting to which this setting maps the specified key, or the default value if the map contains no mapping for this key. * @since 1.2 */ public Integer getIntegerSetting(final String key, final Integer defaultValue) { Integer value = getIntegerSetting(key); if (value == null) { value = defaultValue; } return value; } /** * Returns the boolean value of the setting for the given key * * @param key * key whose associated setting is to be returned. * @return the setting to which this setting maps the specified key, or <code>false</code> if the map contains no mapping for this key. */ public Boolean getBooleanSetting(final String key) { final Object value = getSetting(key); if (value == null) { return null; } if (value instanceof Boolean) { return (Boolean) value; } else { return Boolean.valueOf(value.toString()); } } /** * Returns the boolean value of the setting for the given key * * @param key * key whose associated setting is to be returned. * @param defaultValue * value to return, if no value is set * @return the setting to which this setting maps the specified key, or the {@code defaultValue} if the map contains no mapping for this key. * @since 1.2 */ public Boolean getBooleanSetting(final String key, final boolean defaultValue) { Boolean value = getBooleanSetting(key); if (value == null) { value = defaultValue; } return value; } /** * Returns the String value of the setting for the given key * * @param key * key whose associated setting is to be returned. * @return the setting to which this setting maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public String getStringSetting(final String key) { final Object value = getSetting(key); if (value == null) { return null; } if (value instanceof String) { return (String) value; } else { return null; } } /** * Returns the String value of the setting for the given key * * @param key * key whose associated setting is to be returned. * @param defaultValue * value to return, if no value is set * @return the setting to which this setting maps the specified key, or <code>null</code> if the map contains no mapping for this key. */ public String getStringSetting(final String key, final String defaultValue) { final Object value = getSetting(key); if (value == null) { return defaultValue; } if (value instanceof String) { return (String) value; } else { return defaultValue; } } /** * Returns the current theme of the Look and Feel. * * @return theme */ public ILnfTheme getTheme() { if (theme == null) { theme = new RienaDefaultTheme(); initialize(); } return theme; } /** * Sets the theme to be used by the Look and Feel. * <p> * <b>Note:</b> Setting (changing) a new theme might result in system resources such as colors, fonts and images which will not be disposed. * * @param newTheme * the theme to be used */ public void setTheme(final ILnfTheme newTheme) { if (theme != newTheme) { theme = newTheme; setInitialized(false); initialize(); } } /** * @return the initialize */ private boolean isInitialized() { return initialized; } /** * @param initialize * the initialize to set */ private void setInitialized(final boolean initialized) { this.initialized = initialized; } /** * The ID of this Look and Feel.<br> * The ID of the default LnF is empty. * * @return look'n'feel ID */ protected String getLnfId() { return ""; //$NON-NLS-1$ } /** * {@inheritDoc} * <p> * This default implementation always returns zero factors. So the default, the calculated factors are used. * </p> * * @see org.eclipse.riena.ui.swt.lnf.ILnfCustomizer#getDpiFactors(org.eclipse.swt.graphics.Point) * @since 6.0 */ public float[] getDpiFactors(final Point dpi) { return new float[] { 0.0f, 0.0f }; } /** * {@inheritDoc} * * @see org.eclipse.riena.ui.swt.lnf.ILnfCustomizer#getIconScaleSuffix(float[]) * @since 6.0 */ public String getIconScaleSuffix(final Point dpi) { return null; } /** * {@inheritDoc} * * @see org.eclipse.riena.ui.swt.lnf.ILnfCustomizer#useDpiGridLayout() * * @since 6.1 */ public boolean useDpiGridLayout() { return true; } }