/*
* (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*
* $Id: WidgetDescriptor.java 28478 2008-01-04 12:53:58Z sfermigier $
*/
package org.nuxeo.ecm.platform.forms.layout.descriptors;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.common.xmap.XMap;
import org.nuxeo.common.xmap.annotation.XContent;
import org.nuxeo.common.xmap.annotation.XNode;
import org.nuxeo.common.xmap.annotation.XNodeList;
import org.nuxeo.common.xmap.annotation.XNodeMap;
import org.nuxeo.common.xmap.annotation.XObject;
import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.RenderingInfo;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetSelectOption;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetDefinitionImpl;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetReferenceImpl;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Widget definition descriptor.
*
* @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*/
@XObject("widget")
public class WidgetDescriptor {
private static final Log log = LogFactory.getLog(WidgetDescriptor.class);
@XNode("@name")
String name;
@XNode("@type")
String type;
/**
* @since 5.7.3
*/
@XNode("@typeCategory")
String typeCategory;
@XNodeList(value = "fields/field", type = FieldDescriptor[].class, componentType = FieldDescriptor.class)
FieldDescriptor[] fields = new FieldDescriptor[0];
@XNodeMap(value = "widgetModes/mode", key = "@value", type = HashMap.class, componentType = String.class)
Map<String, String> modes = new HashMap<String, String>();
@XNodeMap(value = "labels/label", key = "@mode", type = HashMap.class, componentType = String.class)
Map<String, String> labels = new HashMap<String, String>();
@XNodeMap(value = "helpLabels/label", key = "@mode", type = HashMap.class, componentType = String.class)
Map<String, String> helpLabels = new HashMap<String, String>();
/**
* Defaults to true, contrary to {@link WidgetDefinition} interface, but kept as is for compatibility.
*/
@XNode("translated")
boolean translated = true;
/**
* @since 5.6
* @deprecated since 5.7: use {@link #controls} instead, with name "handleLabels".
*/
@Deprecated
@XNode("handlingLabels")
boolean handlingLabels = false;
@XNodeMap(value = "properties", key = "@mode", type = HashMap.class, componentType = PropertiesDescriptor.class)
Map<String, PropertiesDescriptor> properties = new HashMap<String, PropertiesDescriptor>();
@XNodeMap(value = "controls", key = "@mode", type = HashMap.class, componentType = ControlsDescriptor.class)
Map<String, ControlsDescriptor> controls = new HashMap<String, ControlsDescriptor>();
@XNodeMap(value = "properties", key = "@widgetMode", type = HashMap.class, componentType = PropertiesDescriptor.class)
Map<String, PropertiesDescriptor> widgetModeProperties = new HashMap<String, PropertiesDescriptor>();
@XNodeList(value = "subWidgets/widget", type = WidgetDescriptor[].class, componentType = WidgetDescriptor.class)
WidgetDescriptor[] subWidgets = new WidgetDescriptor[0];
/**
* @since 5.6
*/
@XNodeList(value = "subWidgetRefs/widget", type = WidgetReferenceDescriptor[].class, componentType = WidgetReferenceDescriptor.class)
WidgetReferenceDescriptor[] subWidgetRefs = new WidgetReferenceDescriptor[0];
// set in method to mix single and multiple options
WidgetSelectOption[] selectOptions = new WidgetSelectOption[0];
@XNodeMap(value = "renderingInfos", key = "@mode", type = HashMap.class, componentType = RenderingInfosDescriptor.class)
Map<String, RenderingInfosDescriptor> renderingInfos = new HashMap<String, RenderingInfosDescriptor>();
@XNodeList(value = "categories/category", type = String[].class, componentType = String.class)
String[] categories = new String[0];
/**
* @since 6.0
*/
@XNodeList(value = "aliases/alias", type = ArrayList.class, componentType = String.class)
List<String> aliases;
public String getName() {
return name;
}
public String getType() {
return type;
}
public FieldDefinition[] getFieldDefinitions() {
if (fields == null) {
return null;
}
FieldDefinition[] res = new FieldDefinition[fields.length];
for (int i = 0; i < fields.length; i++) {
res[i] = fields[i].getFieldDefinition();
}
return res;
}
public String getMode(String layoutMode) {
String mode = modes.get(layoutMode);
if (mode == null) {
mode = modes.get(BuiltinModes.ANY);
}
return mode;
}
public Map<String, String> getModes() {
return modes;
}
public String getRequired(String layoutMode, String mode) {
String res = "false";
Map<String, Serializable> props = getProperties(layoutMode, mode);
if (props != null && props.containsKey(WidgetDefinition.REQUIRED_PROPERTY_NAME)) {
Object value = props.get(WidgetDefinition.REQUIRED_PROPERTY_NAME);
if (value instanceof String) {
res = (String) value;
} else {
log.error(String.format("Invalid property \"%s\" on widget %s: %s",
WidgetDefinition.REQUIRED_PROPERTY_NAME, value, name));
}
}
return res;
}
public String getLabel(String mode) {
String label = labels.get(mode);
if (label == null) {
label = labels.get(BuiltinModes.ANY);
}
return label;
}
public Map<String, String> getLabels() {
return labels;
}
public String getHelpLabel(String mode) {
String label = helpLabels.get(mode);
if (label == null) {
label = helpLabels.get(BuiltinModes.ANY);
}
return label;
}
public Map<String, String> getHelpLabels() {
return helpLabels;
}
public boolean isTranslated() {
return translated;
}
public Map<String, Serializable> getProperties(String layoutMode, String mode) {
Map<String, Serializable> modeProps = getProperties(properties, layoutMode);
Map<String, Serializable> widgetModeProps = getProperties(widgetModeProperties, mode);
if (modeProps == null && widgetModeProps == null) {
return null;
} else if (widgetModeProps == null) {
return modeProps;
} else if (modeProps == null) {
return widgetModeProps;
} else {
// take mode values, and override with widget mode values
Map<String, Serializable> res = new HashMap<String, Serializable>(modeProps);
res.putAll(widgetModeProps);
return res;
}
}
public Map<String, Map<String, Serializable>> getProperties() {
return getProperties(properties);
}
public Map<String, Map<String, Serializable>> getWidgetModeProperties() {
return getProperties(widgetModeProperties);
}
/**
* @since 5.7
* @see WidgetDefinition#getControls()
*/
public Map<String, Map<String, Serializable>> getControls() {
if (controls == null) {
return null;
}
Map<String, Map<String, Serializable>> res = new HashMap<String, Map<String, Serializable>>();
for (Map.Entry<String, ControlsDescriptor> item : controls.entrySet()) {
Map<String, Serializable> props = new HashMap<String, Serializable>();
props.putAll(item.getValue().getControls());
res.put(item.getKey(), props);
}
return res;
}
public WidgetDefinition[] getSubWidgetDefinitions() {
WidgetDefinition[] csubWidgets = null;
if (subWidgets != null) {
csubWidgets = new WidgetDefinition[subWidgets.length];
for (int i = 0; i < subWidgets.length; i++) {
csubWidgets[i] = subWidgets[i].getWidgetDefinition();
}
}
return csubWidgets;
}
public WidgetReference[] getSubWidgetReferences() {
WidgetReference[] csubWidgets = null;
if (subWidgetRefs != null) {
csubWidgets = new WidgetReference[subWidgetRefs.length];
for (int i = 0; i < subWidgetRefs.length; i++) {
csubWidgets[i] = new WidgetReferenceImpl(subWidgetRefs[i].getCategory(), subWidgetRefs[i].getName());
}
}
return csubWidgets;
}
public static Map<String, Serializable> getProperties(Map<String, PropertiesDescriptor> map, String mode) {
if (map == null) {
return null;
}
PropertiesDescriptor defaultProps = map.get(BuiltinModes.ANY);
PropertiesDescriptor props = map.get(mode);
if (defaultProps == null && props == null) {
return null;
} else if (defaultProps == null) {
return props.getProperties();
} else if (props == null) {
return defaultProps.getProperties();
} else {
// take any mode values, and override with given mode values
Map<String, Serializable> res = new HashMap<String, Serializable>(defaultProps.getProperties());
res.putAll(props.getProperties());
return res;
}
}
public static Map<String, Map<String, Serializable>> getProperties(Map<String, PropertiesDescriptor> map) {
if (map == null) {
return null;
}
Map<String, Map<String, Serializable>> res = new HashMap<String, Map<String, Serializable>>();
for (Map.Entry<String, PropertiesDescriptor> item : map.entrySet()) {
Map<String, Serializable> props = new HashMap<String, Serializable>();
props.putAll(item.getValue().getProperties());
res.put(item.getKey(), props);
}
return res;
}
public WidgetSelectOption[] getSelectOptions() {
return selectOptions;
}
@XContent("selectOptions")
public void setSelectOptions(DocumentFragment selectOptionsDOM) {
XMap xmap = new XMap();
xmap.register(WidgetSelectOptionDescriptor.class);
xmap.register(WidgetSelectOptionsDescriptor.class);
Node p = selectOptionsDOM.getFirstChild();
List<WidgetSelectOption> options = new ArrayList<WidgetSelectOption>();
while (p != null) {
if (p.getNodeType() == Node.ELEMENT_NODE) {
Object desc = xmap.load((Element) p);
if (desc instanceof WidgetSelectOptionDescriptor) {
options.add(((WidgetSelectOptionDescriptor) desc).getWidgetSelectOption());
} else if (desc instanceof WidgetSelectOptionsDescriptor) {
options.add(((WidgetSelectOptionsDescriptor) desc).getWidgetSelectOption());
} else {
log.error("Unknown resolution of select option");
}
}
p = p.getNextSibling();
}
selectOptions = options.toArray(new WidgetSelectOption[0]);
}
/**
* Returns the categories for this widget type, so that it can be stored in the corresponding registry.
*
* @since 5.5
*/
public String[] getCategories() {
return categories;
}
/**
* @since 6.0
*/
public List<String> getAliases() {
return aliases;
}
public WidgetDefinition getWidgetDefinition() {
Map<String, String> clabels = null;
if (labels != null) {
clabels = new HashMap<String, String>();
clabels.putAll(labels);
}
Map<String, String> chelpLabels = null;
if (helpLabels != null) {
chelpLabels = new HashMap<String, String>();
chelpLabels.putAll(helpLabels);
}
Map<String, String> cmodes = null;
if (modes != null) {
cmodes = new HashMap<String, String>();
cmodes.putAll(modes);
}
FieldDefinition[] cfieldDefinitions = getFieldDefinitions();
WidgetDefinition[] csubWidgets = getSubWidgetDefinitions();
WidgetReference[] csubwidgetRefs = getSubWidgetReferences();
WidgetSelectOption[] cselectOptions = null;
if (selectOptions != null) {
cselectOptions = new WidgetSelectOption[selectOptions.length];
for (int i = 0; i < selectOptions.length; i++) {
cselectOptions[i] = selectOptions[i].clone();
}
}
Map<String, List<RenderingInfo>> crenderingInfos = null;
if (renderingInfos != null) {
crenderingInfos = new HashMap<String, List<RenderingInfo>>();
for (Map.Entry<String, RenderingInfosDescriptor> item : renderingInfos.entrySet()) {
RenderingInfosDescriptor infos = item.getValue();
List<RenderingInfo> clonedInfos = null;
if (infos != null) {
clonedInfos = new ArrayList<RenderingInfo>();
for (RenderingInfoDescriptor info : infos.getRenderingInfos()) {
clonedInfos.add(info.getRenderingInfo());
}
}
crenderingInfos.put(item.getKey(), clonedInfos);
}
}
WidgetDefinitionImpl clone = new WidgetDefinitionImpl(name, type, clabels, chelpLabels, translated, cmodes,
cfieldDefinitions, getProperties(), getWidgetModeProperties(), csubWidgets, cselectOptions);
clone.setRenderingInfos(crenderingInfos);
clone.setSubWidgetReferences(csubwidgetRefs);
clone.setHandlingLabels(handlingLabels);
clone.setControls(getControls());
clone.setTypeCategory(typeCategory);
if (aliases != null) {
clone.setAliases(new ArrayList<String>(aliases));
}
return clone;
}
}