001/*
002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.forms.layout.api.impl;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
028import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
029import org.nuxeo.ecm.platform.forms.layout.api.RenderingInfo;
030import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
031import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
032import org.nuxeo.ecm.platform.forms.layout.api.WidgetSelectOption;
033
034/**
035 * Default implementation for a widget definition.
036 * <p>
037 * Useful to compute widgets independently from the layout service.
038 *
039 * @author Anahide Tchertchian
040 * @since 5.4
041 */
042public class WidgetDefinitionImpl implements WidgetDefinition {
043
044    private static final long serialVersionUID = 1L;
045
046    protected String name;
047
048    protected String type;
049
050    protected String typeCategory;
051
052    protected Map<String, String> labels;
053
054    protected Map<String, String> helpLabels;
055
056    protected boolean translated = false;
057
058    /**
059     * @deprecated since 5.7: use {@link #controls} instead
060     */
061    @Deprecated
062    protected boolean handlingLabels = false;
063
064    protected Map<String, String> modes;
065
066    protected FieldDefinition[] fieldDefinitions;
067
068    protected Map<String, Map<String, Serializable>> properties;
069
070    protected Map<String, Map<String, Serializable>> widgetModeProperties;
071
072    protected Map<String, Map<String, Serializable>> controls;
073
074    protected WidgetDefinition[] subWidgets;
075
076    protected WidgetReference[] subWidgetReferences;
077
078    protected WidgetSelectOption[] selectOptions;
079
080    protected Map<String, List<RenderingInfo>> renderingInfos;
081
082    protected List<String> aliases;
083
084    protected boolean dynamic = false;
085
086    protected boolean global = false;
087
088    // needed by GWT serialization
089    protected WidgetDefinitionImpl() {
090        super();
091    }
092
093    public WidgetDefinitionImpl(String name, String type, String label, String helpLabel, boolean translated,
094            Map<String, String> modes, List<FieldDefinition> fieldDefinitions, Map<String, Serializable> properties,
095            List<WidgetDefinition> subWidgets) {
096        super();
097        this.name = name;
098        this.type = type;
099        this.labels = new HashMap<String, String>();
100        if (label != null) {
101            this.labels.put(BuiltinModes.ANY, label);
102        }
103        this.helpLabels = new HashMap<String, String>();
104        if (helpLabel != null) {
105            this.helpLabels.put(BuiltinModes.ANY, helpLabel);
106        }
107        this.translated = translated;
108        this.modes = modes;
109        if (fieldDefinitions == null) {
110            this.fieldDefinitions = new FieldDefinition[0];
111        } else {
112            this.fieldDefinitions = fieldDefinitions.toArray(new FieldDefinition[0]);
113        }
114        this.properties = new HashMap<String, Map<String, Serializable>>();
115        if (properties != null) {
116            this.properties.put(BuiltinModes.ANY, properties);
117        }
118        this.widgetModeProperties = null;
119        if (subWidgets == null) {
120            this.subWidgets = new WidgetDefinition[0];
121        } else {
122            this.subWidgets = subWidgets.toArray(new WidgetDefinition[0]);
123        }
124    }
125
126    public WidgetDefinitionImpl(String name, String type, Map<String, String> labels, Map<String, String> helpLabels,
127            boolean translated, Map<String, String> modes, List<FieldDefinition> fieldDefinitions,
128            Map<String, Map<String, Serializable>> properties,
129            Map<String, Map<String, Serializable>> widgetModeProperties, List<WidgetDefinition> subWidgets) {
130        super();
131        this.name = name;
132        this.type = type;
133        this.labels = labels;
134        this.helpLabels = helpLabels;
135        this.translated = translated;
136        this.modes = modes;
137        if (fieldDefinitions == null) {
138            this.fieldDefinitions = new FieldDefinition[0];
139        } else {
140            this.fieldDefinitions = fieldDefinitions.toArray(new FieldDefinition[0]);
141        }
142        this.properties = properties;
143        this.widgetModeProperties = widgetModeProperties;
144        if (subWidgets == null) {
145            this.subWidgets = new WidgetDefinition[0];
146        } else {
147            this.subWidgets = subWidgets.toArray(new WidgetDefinition[0]);
148        }
149    }
150
151    public WidgetDefinitionImpl(String name, String type, Map<String, String> labels, Map<String, String> helpLabels,
152            boolean translated, Map<String, String> modes, FieldDefinition[] fieldDefinitions,
153            Map<String, Map<String, Serializable>> properties,
154            Map<String, Map<String, Serializable>> widgetModeProperties, WidgetDefinition[] subWidgets) {
155        super();
156        this.name = name;
157        this.type = type;
158        this.labels = labels;
159        this.helpLabels = helpLabels;
160        this.translated = translated;
161        this.modes = modes;
162        this.fieldDefinitions = fieldDefinitions;
163        this.properties = properties;
164        this.widgetModeProperties = widgetModeProperties;
165        this.subWidgets = subWidgets;
166    }
167
168    /**
169     * @since 5.4.2
170     */
171    public WidgetDefinitionImpl(String name, String type, Map<String, String> labels, Map<String, String> helpLabels,
172            boolean translated, Map<String, String> modes, FieldDefinition[] fieldDefinitions,
173            Map<String, Map<String, Serializable>> properties,
174            Map<String, Map<String, Serializable>> widgetModeProperties, WidgetDefinition[] subWidgets,
175            WidgetSelectOption[] selectOptions) {
176        this(name, type, labels, helpLabels, translated, modes, fieldDefinitions, properties, widgetModeProperties,
177                subWidgets);
178        this.selectOptions = selectOptions;
179    }
180
181    @Override
182    public FieldDefinition[] getFieldDefinitions() {
183        return fieldDefinitions;
184    }
185
186    @Override
187    public void setFieldDefinitions(FieldDefinition[] fieldDefinitions) {
188        this.fieldDefinitions = fieldDefinitions;
189    }
190
191    @Override
192    public String getHelpLabel(String mode) {
193        String label = helpLabels.get(mode);
194        if (label == null) {
195            label = helpLabels.get(BuiltinModes.ANY);
196        }
197        return label;
198    }
199
200    @Override
201    public Map<String, String> getHelpLabels() {
202        return helpLabels;
203    }
204
205    public void setHelpLabels(Map<String, String> helpLabels) {
206        this.helpLabels = helpLabels;
207    }
208
209    @Override
210    public String getLabel(String mode) {
211        String label = labels.get(mode);
212        if (label == null) {
213            label = labels.get(BuiltinModes.ANY);
214        }
215        return label;
216    }
217
218    @Override
219    public Map<String, String> getLabels() {
220        return labels;
221    }
222
223    public void setLabels(Map<String, String> labels) {
224        this.labels = labels;
225    }
226
227    @Override
228    public String getMode(String layoutMode) {
229        if (modes != null) {
230            String mode = modes.get(layoutMode);
231            if (mode == null) {
232                mode = modes.get(BuiltinModes.ANY);
233            }
234            return mode;
235        }
236        return null;
237    }
238
239    @Override
240    public Map<String, String> getModes() {
241        return modes;
242    }
243
244    public void setModes(Map<String, String> modes) {
245        this.modes = modes;
246    }
247
248    @Override
249    public String getName() {
250        return name;
251    }
252
253    public void setName(String name) {
254        this.name = name;
255    }
256
257    @Override
258    public Map<String, Serializable> getProperties(String layoutMode, String mode) {
259        Map<String, Serializable> modeProps = getProperties(properties, layoutMode);
260        Map<String, Serializable> widgetModeProps = getProperties(widgetModeProperties, mode);
261        if (modeProps == null && widgetModeProps == null) {
262            return null;
263        } else if (widgetModeProps == null) {
264            return modeProps;
265        } else if (modeProps == null) {
266            return widgetModeProps;
267        } else {
268            // take mode values, and override with widget mode values
269            Map<String, Serializable> res = new HashMap<String, Serializable>(modeProps);
270            res.putAll(widgetModeProps);
271            return res;
272        }
273    }
274
275    @Override
276    public Map<String, Map<String, Serializable>> getProperties() {
277        return properties;
278    }
279
280    public void setProperties(Map<String, Map<String, Serializable>> properties) {
281        this.properties = properties;
282    }
283
284    @Override
285    public Map<String, Map<String, Serializable>> getWidgetModeProperties() {
286        return widgetModeProperties;
287    }
288
289    public void setWidgetModeProperties(Map<String, Map<String, Serializable>> widgetModeProperties) {
290        this.widgetModeProperties = widgetModeProperties;
291    }
292
293    @Override
294    public Map<String, Serializable> getControls(String layoutMode, String mode) {
295        return getProperties(controls, layoutMode);
296    }
297
298    @Override
299    public Map<String, Map<String, Serializable>> getControls() {
300        return controls;
301    }
302
303    @Override
304    public void setControls(Map<String, Map<String, Serializable>> controls) {
305        this.controls = controls;
306    }
307
308    @Override
309    public String getRequired(String layoutMode, String mode) {
310        String res = "false";
311        Map<String, Serializable> props = getProperties(layoutMode, mode);
312        if (props != null && props.containsKey(REQUIRED_PROPERTY_NAME)) {
313            Object value = props.get(REQUIRED_PROPERTY_NAME);
314            if (value instanceof Boolean) {
315                res = value.toString();
316            } else if (value instanceof String) {
317                res = (String) value;
318            }
319        }
320        return res;
321    }
322
323    @Override
324    public WidgetDefinition[] getSubWidgetDefinitions() {
325        return subWidgets;
326    }
327
328    public void setSubWidgetDefinitions(WidgetDefinition[] subWidgets) {
329        this.subWidgets = subWidgets;
330    }
331
332    public WidgetReference[] getSubWidgetReferences() {
333        return subWidgetReferences;
334    }
335
336    public void setSubWidgetReferences(WidgetReference[] subWidgetReferences) {
337        this.subWidgetReferences = subWidgetReferences;
338    }
339
340    @Override
341    public String getType() {
342        return type;
343    }
344
345    public void setType(String type) {
346        this.type = type;
347    }
348
349    public String getTypeCategory() {
350        return typeCategory;
351    }
352
353    public void setTypeCategory(String typeCategory) {
354        this.typeCategory = typeCategory;
355    }
356
357    @Override
358    public boolean isTranslated() {
359        return translated;
360    }
361
362    public void setTranslated(boolean translated) {
363        this.translated = translated;
364    }
365
366    public boolean isHandlingLabels() {
367        // migration code
368        Map<String, Serializable> controls = getControls(BuiltinModes.ANY, BuiltinModes.ANY);
369        if (controls != null && controls.containsKey("handleLabels")) {
370            Serializable handling = controls.get("handleLabels");
371            if (handling != null) {
372                return Boolean.parseBoolean(handling.toString());
373            }
374        }
375        return handlingLabels;
376    }
377
378    public void setHandlingLabels(boolean handlingLabels) {
379        this.handlingLabels = handlingLabels;
380    }
381
382    public static Map<String, Serializable> getProperties(Map<String, Map<String, Serializable>> properties, String mode) {
383        Map<String, Serializable> res = new HashMap<String, Serializable>();
384        if (properties != null) {
385            Map<String, Serializable> propsInAnyMode = properties.get(BuiltinModes.ANY);
386            if (propsInAnyMode != null) {
387                res.putAll(propsInAnyMode);
388            }
389            Map<String, Serializable> propsInMode = properties.get(mode);
390            if (propsInMode != null) {
391                res.putAll(propsInMode);
392            }
393        }
394        return res;
395    }
396
397    @Override
398    public WidgetSelectOption[] getSelectOptions() {
399        return selectOptions;
400    }
401
402    public void setSelectOptions(WidgetSelectOption[] selectOptions) {
403        this.selectOptions = selectOptions;
404    }
405
406    @Override
407    public Map<String, List<RenderingInfo>> getRenderingInfos() {
408        return renderingInfos;
409    }
410
411    public void setRenderingInfos(Map<String, List<RenderingInfo>> renderingInfos) {
412        this.renderingInfos = renderingInfos;
413    }
414
415    public static List<RenderingInfo> getRenderingInfos(Map<String, List<RenderingInfo>> infos, String mode) {
416        List<RenderingInfo> res = new ArrayList<RenderingInfo>();
417        if (infos != null) {
418            List<RenderingInfo> inAnyMode = infos.get(BuiltinModes.ANY);
419            if (inAnyMode != null) {
420                res.addAll(inAnyMode);
421            }
422            List<RenderingInfo> inMode = infos.get(mode);
423            if (inMode != null) {
424                res.addAll(inMode);
425            }
426        }
427        return res;
428    }
429
430    @Override
431    public List<RenderingInfo> getRenderingInfos(String mode) {
432        return getRenderingInfos(renderingInfos, mode);
433    }
434
435    public boolean isDynamic() {
436        return dynamic;
437    }
438
439    public void setDynamic(boolean dynamic) {
440        this.dynamic = dynamic;
441    }
442
443    public boolean isGlobal() {
444        return global;
445    }
446
447    public void setGlobal(boolean global) {
448        this.global = global;
449    }
450
451    @Override
452    public List<String> getAliases() {
453        return aliases;
454    }
455
456    public void setAliases(List<String> aliases) {
457        this.aliases = aliases;
458    }
459
460    @Override
461    public WidgetDefinition clone() {
462        Map<String, Map<String, Serializable>> cprops = null;
463        if (properties != null) {
464            cprops = new HashMap<String, Map<String, Serializable>>();
465            for (Map.Entry<String, Map<String, Serializable>> entry : properties.entrySet()) {
466                Map<String, Serializable> subProps = entry.getValue();
467                Map<String, Serializable> csubProps = null;
468                if (subProps != null) {
469                    csubProps = new HashMap<String, Serializable>();
470                    csubProps.putAll(subProps);
471                }
472                cprops.put(entry.getKey(), csubProps);
473            }
474        }
475        Map<String, Map<String, Serializable>> ccontrols = null;
476        if (controls != null) {
477            ccontrols = new HashMap<String, Map<String, Serializable>>();
478            for (Map.Entry<String, Map<String, Serializable>> entry : controls.entrySet()) {
479                Map<String, Serializable> subControls = entry.getValue();
480                Map<String, Serializable> csubControls = null;
481                if (subControls != null) {
482                    csubControls = new HashMap<String, Serializable>();
483                    csubControls.putAll(subControls);
484                }
485                ccontrols.put(entry.getKey(), csubControls);
486            }
487        }
488        Map<String, String> clabels = null;
489        if (labels != null) {
490            clabels = new HashMap<String, String>();
491            clabels.putAll(labels);
492        }
493        Map<String, String> chelpLabels = null;
494        if (helpLabels != null) {
495            chelpLabels = new HashMap<String, String>();
496            chelpLabels.putAll(helpLabels);
497        }
498        Map<String, String> cmodes = null;
499        if (modes != null) {
500            cmodes = new HashMap<String, String>();
501            cmodes.putAll(modes);
502        }
503        FieldDefinition[] cfieldDefinitions = null;
504        if (fieldDefinitions != null) {
505            cfieldDefinitions = new FieldDefinition[fieldDefinitions.length];
506            for (int i = 0; i < fieldDefinitions.length; i++) {
507                cfieldDefinitions[i] = fieldDefinitions[i].clone();
508            }
509        }
510        Map<String, Map<String, Serializable>> cwidgetProps = null;
511        if (widgetModeProperties != null) {
512            cwidgetProps = new HashMap<String, Map<String, Serializable>>();
513            for (Map.Entry<String, Map<String, Serializable>> entry : widgetModeProperties.entrySet()) {
514                Map<String, Serializable> subProps = entry.getValue();
515                Map<String, Serializable> csubProps = null;
516                if (subProps != null) {
517                    csubProps = new HashMap<String, Serializable>();
518                    csubProps.putAll(subProps);
519                }
520                cwidgetProps.put(entry.getKey(), csubProps);
521            }
522        }
523        WidgetDefinition[] csubWidgets = null;
524        if (subWidgets != null) {
525            csubWidgets = new WidgetDefinition[subWidgets.length];
526            for (int i = 0; i < subWidgets.length; i++) {
527                csubWidgets[i] = subWidgets[i].clone();
528            }
529        }
530        WidgetReference[] csubWidgetRefs = null;
531        if (subWidgetReferences != null) {
532            csubWidgetRefs = new WidgetReference[subWidgetReferences.length];
533            for (int i = 0; i < subWidgetReferences.length; i++) {
534                csubWidgetRefs[i] = subWidgetReferences[i].clone();
535            }
536        }
537        WidgetSelectOption[] cselectOptions = null;
538        if (selectOptions != null) {
539            cselectOptions = new WidgetSelectOption[selectOptions.length];
540            for (int i = 0; i < selectOptions.length; i++) {
541                cselectOptions[i] = selectOptions[i].clone();
542            }
543        }
544        Map<String, List<RenderingInfo>> crenderingInfos = null;
545        if (renderingInfos != null) {
546            crenderingInfos = new HashMap<String, List<RenderingInfo>>();
547            for (Map.Entry<String, List<RenderingInfo>> item : renderingInfos.entrySet()) {
548                List<RenderingInfo> infos = item.getValue();
549                List<RenderingInfo> clonedInfos = null;
550                if (infos != null) {
551                    clonedInfos = new ArrayList<RenderingInfo>();
552                    for (RenderingInfo info : infos) {
553                        clonedInfos.add(info.clone());
554                    }
555                }
556                crenderingInfos.put(item.getKey(), clonedInfos);
557            }
558        }
559        WidgetDefinitionImpl clone = new WidgetDefinitionImpl(name, type, clabels, chelpLabels, translated, cmodes,
560                cfieldDefinitions, cprops, cwidgetProps, csubWidgets, cselectOptions);
561        clone.setTypeCategory(typeCategory);
562        clone.setRenderingInfos(crenderingInfos);
563        clone.setSubWidgetReferences(csubWidgetRefs);
564        clone.setHandlingLabels(handlingLabels);
565        clone.setControls(ccontrols);
566        if (aliases != null) {
567            clone.setAliases(new ArrayList<String>(aliases));
568        }
569        clone.setDynamic(dynamic);
570        clone.setGlobal(global);
571        return clone;
572    }
573
574    /**
575     * @since 7.2
576     */
577    @Override
578    public boolean equals(Object obj) {
579        if (!(obj instanceof WidgetDefinitionImpl)) {
580            return false;
581        }
582        if (obj == this) {
583            return true;
584        }
585        WidgetDefinitionImpl w = (WidgetDefinitionImpl) obj;
586        return new EqualsBuilder().append(name, w.name).append(type, w.type).append(typeCategory, w.typeCategory).append(
587                labels, w.labels).append(helpLabels, w.helpLabels).append(translated, w.translated).append(
588                handlingLabels, w.handlingLabels).append(modes, w.modes).append(fieldDefinitions, w.fieldDefinitions).append(
589                properties, w.properties).append(widgetModeProperties, w.widgetModeProperties).append(controls,
590                w.controls).append(subWidgets, w.subWidgets).append(subWidgetReferences, w.subWidgetReferences).append(
591                selectOptions, w.selectOptions).append(renderingInfos, w.renderingInfos).append(aliases, w.aliases).append(
592                dynamic, w.dynamic).append(global, w.global).isEquals();
593    }
594
595    /**
596     * @since 7.1
597     */
598    @Override
599    public String toString() {
600        final StringBuilder buf = new StringBuilder();
601
602        buf.append("WidgetDefinitionImpl");
603        buf.append(" {");
604        buf.append(" name=");
605        buf.append(name);
606        buf.append(", type=");
607        buf.append(type);
608        buf.append(", typeCategory=");
609        buf.append(typeCategory);
610        buf.append(", properties=");
611        buf.append(properties);
612        buf.append(", controls=");
613        buf.append(controls);
614        buf.append('}');
615
616        return buf.toString();
617    }
618
619}