| /******************************************************************************* |
| * Copyright (c) 2008, 2016 Angelo Zerr and others. |
| * |
| * 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: |
| * Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.e4.ui.css.swt.dom; |
| |
| import java.util.Objects; |
| import java.util.function.Supplier; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.e4.ui.css.core.dom.CSSStylableElement; |
| import org.eclipse.e4.ui.css.core.dom.ElementAdapter; |
| import org.eclipse.e4.ui.css.core.engine.CSSEngine; |
| import org.eclipse.e4.ui.css.core.utils.ClassUtils; |
| import org.eclipse.e4.ui.css.swt.CSSSWTConstants; |
| import org.eclipse.e4.ui.css.swt.helpers.SWTStyleHelpers; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Widget; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| /** |
| * {@link CSSStylableElement} implementation which wrap SWT {@link Widget}. |
| * |
| */ |
| public class WidgetElement extends ElementAdapter implements NodeList { |
| |
| boolean dynamicEnabled = Boolean.getBoolean("org.eclipse.e4.ui.css.dynamic"); |
| |
| /** |
| * Convenience method for getting the CSS class of a widget. |
| * |
| * @param widget |
| * SWT widget with associated CSS class name |
| * @return CSS class name |
| */ |
| public static String getCSSClass(Widget widget) { |
| return (String) widget.getData(CSSSWTConstants.CSS_CLASS_NAME_KEY); |
| } |
| |
| /** |
| * Convenience method for getting the CSS ID of a widget. |
| * |
| * @param widget |
| * SWT widget with associated CSS id |
| * @return CSS ID |
| */ |
| public static String getID(Widget widget) { |
| return (String) widget.getData(CSSSWTConstants.CSS_ID_KEY); |
| } |
| |
| /** |
| * Convenience method for setting the CSS class of a widget. |
| * |
| * @param widget |
| * SWT widget with associated CSS class name |
| * @param className |
| * class name to set |
| */ |
| public static void setCSSClass(Widget widget, String className) { |
| widget.setData(CSSSWTConstants.CSS_CLASS_NAME_KEY, className); |
| } |
| |
| /** |
| * Convenience method for setting the CSS ID of a widget. |
| * |
| * @param widget |
| * SWT widget with associated CSS id |
| * @param id |
| * CSS id to set |
| */ |
| public static void setID(Widget widget, String id) { |
| widget.setData(CSSSWTConstants.CSS_ID_KEY, id); |
| } |
| |
| /** |
| * Convenience method for getting the CSS engine responsible for a widget. |
| * @param widget SWT widget which is styled by an engine |
| */ |
| public static CSSEngine getEngine(Widget widget) { |
| return getEngine(widget.getDisplay()); |
| } |
| |
| /** |
| * Convenience method for getting the CSS engine responsible for a widget. |
| * |
| * @param display |
| * SWT display which is styled by an engine |
| */ |
| public static CSSEngine getEngine(Display display) { |
| return (CSSEngine) display.getData(CSSSWTConstants.CSS_ENGINE_KEY); |
| } |
| |
| /** |
| * Convenience method for requesting the CSS engine to re-apply styles to a |
| * widget. |
| * |
| * @param widget |
| * widget to be restyled |
| * @param applyStylesToChildNodes |
| * if true, apply styles to the child nodes |
| */ |
| public static void applyStyles(Widget widget, |
| boolean applyStylesToChildNodes) { |
| CSSEngine engine = getEngine(widget); |
| if (engine != null) { |
| engine.applyStyles(widget, applyStylesToChildNodes); |
| } |
| } |
| |
| /** |
| * Convenience method for setting the CSS engine responsible for a display. |
| * |
| * @param widget |
| * SWT display which is styled by an engine |
| * @param engine |
| * Engine to be associated with the display |
| */ |
| public static void setEngine(Display display, CSSEngine engine) { |
| display.setData(CSSSWTConstants.CSS_ENGINE_KEY, engine); |
| } |
| |
| protected String localName; |
| |
| protected String namespaceURI; |
| |
| protected String swtStyles; |
| |
| public WidgetElement(Widget widget, CSSEngine engine) { |
| super(widget, engine); |
| this.localName = computeLocalName(); |
| this.namespaceURI = computeNamespaceURI(); |
| this.computeStaticPseudoInstances(); |
| this.swtStyles = this.computeAttributeSWTStyle(); |
| } |
| |
| /** |
| * Compute local name. |
| * |
| * @return |
| */ |
| protected String computeLocalName() { |
| // The localName is simple class name |
| // of the SWT widget. For instance |
| // for the org.eclipse.swt.widgets.Label |
| // localName is Label |
| // CSS selector will use this localName |
| // ex : Label {background-color:red;} |
| |
| // for inner classes, the hyphen is used, e.g., for Outer$Inner, |
| // the selector is Outer-Inner {background-color:red;} |
| Widget widget = getWidget(); |
| Class<?> clazz = widget.getClass(); |
| return ClassUtils.getSimpleName(clazz); |
| } |
| |
| /** |
| * Compute namespaceURI. |
| * |
| * @return |
| */ |
| protected String computeNamespaceURI() { |
| // The NamespaceURI is package name |
| // of the SWT widget. For instance |
| // for the org.eclipse.swt.widgets.Label |
| // namespaceURI is org.eclipse.swt.widgets.Label |
| // CSS selector will use this localName |
| // @namespace eclipse org.eclipse.swt.widgets.Label |
| // ex : eclipse|Label {background-color:red;} |
| Widget widget = getWidget(); |
| Class<?> clazz = widget.getClass(); |
| return ClassUtils.getPackageName(clazz); |
| } |
| |
| /** |
| * Compute static pseudo instances. |
| * |
| */ |
| protected void computeStaticPseudoInstances() { |
| |
| } |
| |
| /** |
| * Compute attribute SWT style. |
| * |
| * @return |
| */ |
| protected String computeAttributeSWTStyle() { |
| return SWTStyleHelpers.getSWTWidgetStyleAsString(getWidget()); |
| } |
| |
| @Override |
| public final String getAttribute(String attr) { |
| Supplier<String> attribute = internalGetAttribute(attr); |
| if (attribute != null) { |
| String attributeValue = attribute.get(); |
| Assert.isNotNull(attributeValue); |
| return attributeValue; |
| } |
| return ""; |
| } |
| |
| @Override |
| public final boolean hasAttribute(String attr) { |
| return internalGetAttribute(attr) != null; |
| } |
| |
| /** |
| * |
| * The goal for {@link #internalGetAttribute(String)} is to share the code |
| * of {@link #hasAttribute(String)} and {@link #getAttribute(String)} and to |
| * keep the performance footprint for {@link #hasAttribute(String)} small. |
| * This shall be accomplished by: |
| * <ul> |
| * <li>The method shall only be a lookup for a supplier, no actual |
| * computation shall be made. |
| * <li>The result of the supplier must hold the requirements of the result |
| * of {@link #getAttribute(String)}. Especially it <strong>must not</strong> |
| * return {@code null}. |
| * <li>If the attribute isn't set on the widget, the method must return |
| * {@code null}. |
| * </ul> |
| * |
| * |
| * @param attr |
| * the name of the attribute to look for. |
| * @return a supplier which will return the actual attribute value or |
| * {@code null} if the attribute isn't set for the widget. |
| */ |
| protected Supplier<String> internalGetAttribute(String attr) { |
| Widget widget = getWidget(); |
| switch(attr){ |
| case "style": |
| return () -> swtStyles != null ? swtStyles : ""; |
| case "class": |
| return () -> Objects.toString(getCSSClass(widget), ""); |
| case "swt-data-class": |
| return () -> { |
| Object data = widget.getData(); |
| if (data == null) { |
| return ""; |
| } |
| StringBuilder sb = new StringBuilder(); |
| for (Class<?> clazz = data.getClass(); clazz != Object.class; sb.append(' ')) { |
| sb.append(clazz.getName()); |
| clazz = clazz.getSuperclass(); |
| } |
| return sb.toString(); |
| }; |
| default: |
| Object o = widget.getData(attr.toLowerCase()); |
| if (o != null) { |
| return o::toString; |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public String getLocalName() { |
| return localName; |
| } |
| |
| @Override |
| public String getNamespaceURI() { |
| return namespaceURI; |
| } |
| |
| @Override |
| public Node getParentNode() { |
| return null; |
| } |
| |
| @Override |
| public NodeList getChildNodes() { |
| return this; |
| } |
| |
| @Override |
| public int getLength() { |
| return 0; |
| } |
| |
| @Override |
| public Node item(int index) { |
| return null; |
| } |
| |
| protected Widget getWidget() { |
| return (Widget) getNativeWidget(); |
| } |
| |
| @Override |
| public String getCSSId() { |
| Widget widget = getWidget(); |
| Object id = getID(widget); |
| if (id != null) { |
| return id.toString(); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getCSSClass() { |
| Widget widget = getWidget(); |
| Object id = getCSSClass(widget); |
| if (id != null) { |
| return id.toString(); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getCSSStyle() { |
| Widget widget = getWidget(); |
| // TODO should have key in CSSSWT |
| Object id = widget.getData("style"); |
| if (id != null) { |
| return id.toString(); |
| } |
| return null; |
| } |
| |
| /** |
| * Called by the CSS engine upon a CSS theme switch. Implementations |
| * should restore the default value so that the new theme can be applied to |
| * the application without restart |
| */ |
| |
| public void reset() { |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + ": " + getWidget(); |
| } |
| } |