/** * Copyright (c) 2014-2017 by the respective copyright holders. * 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 */ package org.eclipse.smarthome.ui.basic.internal.render; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.eclipse.smarthome.core.types.State; import org.eclipse.smarthome.model.sitemap.Widget; import org.eclipse.smarthome.ui.basic.internal.WebAppActivator; import org.eclipse.smarthome.ui.basic.internal.WebAppConfig; import org.eclipse.smarthome.ui.basic.render.RenderException; import org.eclipse.smarthome.ui.basic.render.WidgetRenderer; import org.eclipse.smarthome.ui.items.ItemUIRegistry; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This is an abstract implementation of a widget renderer. It provides * methods that are very useful for any widget renderer implementation, * so it should be subclassed by most concrete implementations. * * @author Kai Kreuzer - Initial contribution and API * @author Vlad Ivanov - BasicUI changes * */ abstract public class AbstractWidgetRenderer implements WidgetRenderer { private final Logger logger = LoggerFactory.getLogger(AbstractWidgetRenderer.class); protected ItemUIRegistry itemUIRegistry; protected WebAppConfig config; /* the file extension of the snippets */ protected static final String SNIPPET_EXT = ".html"; /* the snippet location inside this bundle */ protected static final String SNIPPET_LOCATION = "snippets/"; /* a local cache so we do not have to read the snippets over and over again from the bundle */ protected static final Map<String, String> snippetCache = new HashMap<String, String>(); public void setItemUIRegistry(ItemUIRegistry itemUIRegistry) { this.itemUIRegistry = itemUIRegistry; } public void unsetItemUIRegistry(ItemUIRegistry itemUIRegistry) { this.itemUIRegistry = null; } public ItemUIRegistry getItemUIRegistry() { return itemUIRegistry; } protected void activate(ComponentContext context) { } protected void deactivate(ComponentContext context) { } /** * Replace some common values in the widget template * * @param snippet snippet html code * @param w corresponding widget * @return */ protected String preprocessSnippet(String snippet, Widget w) { snippet = StringUtils.replace(snippet, "%widget_id%", itemUIRegistry.getWidgetId(w)); snippet = StringUtils.replace(snippet, "%icon_type%", config.getIconType()); snippet = StringUtils.replace(snippet, "%item%", w.getItem() != null ? w.getItem() : ""); snippet = StringUtils.replace(snippet, "%label%", getLabel(w)); snippet = StringUtils.replace(snippet, "%value%", getValue(w)); snippet = StringUtils.replace(snippet, "%has_value%", new Boolean(hasValue(w)).toString()); snippet = StringUtils.replace(snippet, "%visibility_class%", itemUIRegistry.getVisiblity(w) ? "" : "mdl-form__row--hidden"); String state = getState(w); snippet = StringUtils.replace(snippet, "%state%", state == null ? "" : escapeURL(state)); String category = getCategory(w); snippet = StringUtils.replace(snippet, "%category%", escapeURL(category)); return snippet; } /** * This method provides the html snippet for a given elementType of the sitemap model. * * @param elementType the name of the model type (e.g. "Group" or "Switch") * @return the html snippet to be used in the UI (including placeholders for variables) * @throws RenderException if snippet could not be read */ protected synchronized String getSnippet(String elementType) throws RenderException { elementType = elementType.toLowerCase(); String snippet = snippetCache.get(elementType); if (snippet == null) { String snippetLocation = SNIPPET_LOCATION + elementType + SNIPPET_EXT; URL entry = WebAppActivator.getContext().getBundle().getEntry(snippetLocation); if (entry != null) { try { snippet = IOUtils.toString(entry.openStream()); snippetCache.put(elementType, snippet); } catch (IOException e) { logger.warn("Cannot load snippet for element type '{}'", elementType, e); } } else { throw new RenderException("Cannot find a snippet for element type '" + elementType + "'"); } } return snippet; } /** * Retrieves the label for a widget * * @param w the widget to retrieve the label for * @return the label to use for the widget */ public String getLabel(Widget w) { String label = itemUIRegistry.getLabel(w); int index = label.indexOf('['); if (index != -1) { label = label.substring(0, index); } return escapeHtml(label); } /** * Returns formatted value of the item associated to widget * * @param w widget to get value for * @return value to use for the widget */ public String getValue(Widget w) { String label = itemUIRegistry.getLabel(w); int index = label.indexOf('['); if (index != -1) { return escapeHtml(label.substring(index + 1, label.length() - 1)); } else { return ""; } } /** * Returns whether the item associated to widget has a value or not * * @param w widget * @return true if the item associated to widget has a value */ public boolean hasValue(Widget w) { String label = itemUIRegistry.getLabel(w); return (label.indexOf('[') != -1); } /** * Escapes parts of a URL. This means, that for example the * path "/hello world" gets escaped to "/hello+world". * * @param string The string that has to be escaped * @return The escaped string */ protected String escapeURL(String string) { if (string == null) { return null; } try { return URLEncoder.encode(string, "UTF-8"); } catch (UnsupportedEncodingException use) { logger.warn("Cannot escape string '{}'. Returning unmodified string.", string); return string; } } /** * Process the color tags - labelcolor and valuecolor * * @param w * The widget to process * @param snippet * The snippet to translate * @return The updated snippet */ protected String processColor(Widget w, String snippet) { String style = ""; String color = ""; color = itemUIRegistry.getLabelColor(w); if (color != null) { style = "style=\"color:" + color + "\""; } snippet = StringUtils.replace(snippet, "%labelstyle%", style); style = ""; color = itemUIRegistry.getValueColor(w); if (color != null) { style = "style=\"color:" + color + "\""; } snippet = StringUtils.replace(snippet, "%valuestyle%", style); return snippet; } protected String getCategory(Widget w) { return itemUIRegistry.getCategory(w); } protected String getState(Widget w) { State state = itemUIRegistry.getState(w); if (state != null) { return state.toString(); } else { return "NULL"; } } protected String escapeHtml(String s) { return StringEscapeUtils.escapeHtml(s); } @Override public void setConfig(WebAppConfig config) { this.config = config; } }