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<>();
100        if (label != null) {
101            this.labels.put(BuiltinModes.ANY, label);
102        }
103        this.helpLabels = new HashMap<>();
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<>();
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    @Override
206    public void setHelpLabels(Map<String, String> helpLabels) {
207        this.helpLabels = helpLabels;
208    }
209
210    @Override
211    public String getLabel(String mode) {
212        String label = labels.get(mode);
213        if (label == null) {
214            label = labels.get(BuiltinModes.ANY);
215        }
216        return label;
217    }
218
219    @Override
220    public Map<String, String> getLabels() {
221        return labels;
222    }
223
224    @Override
225    public void setLabels(Map<String, String> labels) {
226        this.labels = labels;
227    }
228
229    @Override
230    public String getMode(String layoutMode) {
231        if (modes != null) {
232            String mode = modes.get(layoutMode);
233            if (mode == null) {
234                mode = modes.get(BuiltinModes.ANY);
235            }
236            return mode;
237        }
238        return null;
239    }
240
241    @Override
242    public Map<String, String> getModes() {
243        return modes;
244    }
245
246    @Override
247    public void setModes(Map<String, String> modes) {
248        this.modes = modes;
249    }
250
251    @Override
252    public String getName() {
253        return name;
254    }
255
256    @Override
257    public void setName(String name) {
258        this.name = name;
259    }
260
261    @Override
262    public Map<String, Serializable> getProperties(String layoutMode, String mode) {
263        Map<String, Serializable> modeProps = getProperties(properties, layoutMode);
264        Map<String, Serializable> widgetModeProps = getProperties(widgetModeProperties, mode);
265        // take mode values, and override with widget mode values
266        Map<String, Serializable> res = new HashMap<>(modeProps);
267        res.putAll(widgetModeProps);
268        return res;
269    }
270
271    @Override
272    public Map<String, Map<String, Serializable>> getProperties() {
273        return properties;
274    }
275
276    @Override
277    public void setProperties(Map<String, Map<String, Serializable>> properties) {
278        this.properties = properties;
279    }
280
281    @Override
282    public Map<String, Map<String, Serializable>> getWidgetModeProperties() {
283        return widgetModeProperties;
284    }
285
286    @Override
287    public void setWidgetModeProperties(Map<String, Map<String, Serializable>> widgetModeProperties) {
288        this.widgetModeProperties = widgetModeProperties;
289    }
290
291    @Override
292    public Map<String, Serializable> getControls(String layoutMode, String mode) {
293        return getProperties(controls, layoutMode);
294    }
295
296    @Override
297    public Map<String, Map<String, Serializable>> getControls() {
298        return controls;
299    }
300
301    @Override
302    public void setControls(Map<String, Map<String, Serializable>> controls) {
303        this.controls = controls;
304    }
305
306    @Override
307    public String getRequired(String layoutMode, String mode) {
308        String res = "false";
309        Map<String, Serializable> props = getProperties(layoutMode, mode);
310        if (props != null && props.containsKey(REQUIRED_PROPERTY_NAME)) {
311            Object value = props.get(REQUIRED_PROPERTY_NAME);
312            if (value instanceof Boolean) {
313                res = value.toString();
314            } else if (value instanceof String) {
315                res = (String) value;
316            }
317        }
318        return res;
319    }
320
321    @Override
322    public WidgetDefinition[] getSubWidgetDefinitions() {
323        return subWidgets;
324    }
325
326    @Override
327    public void setSubWidgetDefinitions(WidgetDefinition[] subWidgets) {
328        this.subWidgets = subWidgets;
329    }
330
331    @Override
332    public WidgetReference[] getSubWidgetReferences() {
333        return subWidgetReferences;
334    }
335
336    @Override
337    public void setSubWidgetReferences(WidgetReference[] subWidgetReferences) {
338        this.subWidgetReferences = subWidgetReferences;
339    }
340
341    @Override
342    public String getType() {
343        return type;
344    }
345
346    @Override
347    public void setType(String type) {
348        this.type = type;
349    }
350
351    @Override
352    public String getTypeCategory() {
353        return typeCategory;
354    }
355
356    @Override
357    public void setTypeCategory(String typeCategory) {
358        this.typeCategory = typeCategory;
359    }
360
361    @Override
362    public boolean isTranslated() {
363        return translated;
364    }
365
366    @Override
367    public void setTranslated(boolean translated) {
368        this.translated = translated;
369    }
370
371    @Override
372    public boolean isHandlingLabels() {
373        // migration code
374        Map<String, Serializable> controls = getControls(BuiltinModes.ANY, BuiltinModes.ANY);
375        if (controls != null && controls.containsKey("handleLabels")) {
376            Serializable handling = controls.get("handleLabels");
377            if (handling != null) {
378                return Boolean.parseBoolean(handling.toString());
379            }
380        }
381        return handlingLabels;
382    }
383
384    @Override
385    public void setHandlingLabels(boolean handlingLabels) {
386        this.handlingLabels = handlingLabels;
387    }
388
389    public static Map<String, Serializable> getProperties(Map<String, Map<String, Serializable>> properties, String mode) {
390        Map<String, Serializable> res = new HashMap<>();
391        if (properties != null) {
392            Map<String, Serializable> propsInAnyMode = properties.get(BuiltinModes.ANY);
393            if (propsInAnyMode != null) {
394                res.putAll(propsInAnyMode);
395            }
396            Map<String, Serializable> propsInMode = properties.get(mode);
397            if (propsInMode != null) {
398                res.putAll(propsInMode);
399            }
400        }
401        return res;
402    }
403
404    @Override
405    public WidgetSelectOption[] getSelectOptions() {
406        return selectOptions;
407    }
408
409    @Override
410    public void setSelectOptions(WidgetSelectOption[] selectOptions) {
411        this.selectOptions = selectOptions;
412    }
413
414    @Override
415    public Map<String, List<RenderingInfo>> getRenderingInfos() {
416        return renderingInfos;
417    }
418
419    @Override
420    public void setRenderingInfos(Map<String, List<RenderingInfo>> renderingInfos) {
421        this.renderingInfos = renderingInfos;
422    }
423
424    public static List<RenderingInfo> getRenderingInfos(Map<String, List<RenderingInfo>> infos, String mode) {
425        List<RenderingInfo> res = new ArrayList<>();
426        if (infos != null) {
427            List<RenderingInfo> inAnyMode = infos.get(BuiltinModes.ANY);
428            if (inAnyMode != null) {
429                res.addAll(inAnyMode);
430            }
431            List<RenderingInfo> inMode = infos.get(mode);
432            if (inMode != null) {
433                res.addAll(inMode);
434            }
435        }
436        return res;
437    }
438
439    @Override
440    public List<RenderingInfo> getRenderingInfos(String mode) {
441        return getRenderingInfos(renderingInfos, mode);
442    }
443
444    @Override
445    public boolean isDynamic() {
446        return dynamic;
447    }
448
449    public void setDynamic(boolean dynamic) {
450        this.dynamic = dynamic;
451    }
452
453    @Override
454    public boolean isGlobal() {
455        return global;
456    }
457
458    @Override
459    public void setGlobal(boolean global) {
460        this.global = global;
461    }
462
463    @Override
464    public List<String> getAliases() {
465        return aliases;
466    }
467
468    public void setAliases(List<String> aliases) {
469        this.aliases = aliases;
470    }
471
472    @Override
473    public WidgetDefinition clone() {
474        Map<String, Map<String, Serializable>> cprops = null;
475        if (properties != null) {
476            cprops = new HashMap<>();
477            for (Map.Entry<String, Map<String, Serializable>> entry : properties.entrySet()) {
478                Map<String, Serializable> subProps = entry.getValue();
479                Map<String, Serializable> csubProps = null;
480                if (subProps != null) {
481                    csubProps = new HashMap<>();
482                    csubProps.putAll(subProps);
483                }
484                cprops.put(entry.getKey(), csubProps);
485            }
486        }
487        Map<String, Map<String, Serializable>> ccontrols = null;
488        if (controls != null) {
489            ccontrols = new HashMap<>();
490            for (Map.Entry<String, Map<String, Serializable>> entry : controls.entrySet()) {
491                Map<String, Serializable> subControls = entry.getValue();
492                Map<String, Serializable> csubControls = null;
493                if (subControls != null) {
494                    csubControls = new HashMap<>();
495                    csubControls.putAll(subControls);
496                }
497                ccontrols.put(entry.getKey(), csubControls);
498            }
499        }
500        Map<String, String> clabels = null;
501        if (labels != null) {
502            clabels = new HashMap<>();
503            clabels.putAll(labels);
504        }
505        Map<String, String> chelpLabels = null;
506        if (helpLabels != null) {
507            chelpLabels = new HashMap<>();
508            chelpLabels.putAll(helpLabels);
509        }
510        Map<String, String> cmodes = null;
511        if (modes != null) {
512            cmodes = new HashMap<>();
513            cmodes.putAll(modes);
514        }
515        FieldDefinition[] cfieldDefinitions = null;
516        if (fieldDefinitions != null) {
517            cfieldDefinitions = new FieldDefinition[fieldDefinitions.length];
518            for (int i = 0; i < fieldDefinitions.length; i++) {
519                cfieldDefinitions[i] = fieldDefinitions[i].clone();
520            }
521        }
522        Map<String, Map<String, Serializable>> cwidgetProps = null;
523        if (widgetModeProperties != null) {
524            cwidgetProps = new HashMap<>();
525            for (Map.Entry<String, Map<String, Serializable>> entry : widgetModeProperties.entrySet()) {
526                Map<String, Serializable> subProps = entry.getValue();
527                Map<String, Serializable> csubProps = null;
528                if (subProps != null) {
529                    csubProps = new HashMap<>();
530                    csubProps.putAll(subProps);
531                }
532                cwidgetProps.put(entry.getKey(), csubProps);
533            }
534        }
535        WidgetDefinition[] csubWidgets = null;
536        if (subWidgets != null) {
537            csubWidgets = new WidgetDefinition[subWidgets.length];
538            for (int i = 0; i < subWidgets.length; i++) {
539                csubWidgets[i] = subWidgets[i].clone();
540            }
541        }
542        WidgetReference[] csubWidgetRefs = null;
543        if (subWidgetReferences != null) {
544            csubWidgetRefs = new WidgetReference[subWidgetReferences.length];
545            for (int i = 0; i < subWidgetReferences.length; i++) {
546                csubWidgetRefs[i] = subWidgetReferences[i].clone();
547            }
548        }
549        WidgetSelectOption[] cselectOptions = null;
550        if (selectOptions != null) {
551            cselectOptions = new WidgetSelectOption[selectOptions.length];
552            for (int i = 0; i < selectOptions.length; i++) {
553                cselectOptions[i] = selectOptions[i].clone();
554            }
555        }
556        Map<String, List<RenderingInfo>> crenderingInfos = null;
557        if (renderingInfos != null) {
558            crenderingInfos = new HashMap<>();
559            for (Map.Entry<String, List<RenderingInfo>> item : renderingInfos.entrySet()) {
560                List<RenderingInfo> infos = item.getValue();
561                List<RenderingInfo> clonedInfos = null;
562                if (infos != null) {
563                    clonedInfos = new ArrayList<>();
564                    for (RenderingInfo info : infos) {
565                        clonedInfos.add(info.clone());
566                    }
567                }
568                crenderingInfos.put(item.getKey(), clonedInfos);
569            }
570        }
571        WidgetDefinitionImpl clone = new WidgetDefinitionImpl(name, type, clabels, chelpLabels, translated, cmodes,
572                cfieldDefinitions, cprops, cwidgetProps, csubWidgets, cselectOptions);
573        clone.setTypeCategory(typeCategory);
574        clone.setRenderingInfos(crenderingInfos);
575        clone.setSubWidgetReferences(csubWidgetRefs);
576        clone.setHandlingLabels(handlingLabels);
577        clone.setControls(ccontrols);
578        if (aliases != null) {
579            clone.setAliases(new ArrayList<>(aliases));
580        }
581        clone.setDynamic(dynamic);
582        clone.setGlobal(global);
583        return clone;
584    }
585
586    /**
587     * @since 7.2
588     */
589    @Override
590    public boolean equals(Object obj) {
591        if (!(obj instanceof WidgetDefinitionImpl)) {
592            return false;
593        }
594        if (obj == this) {
595            return true;
596        }
597        WidgetDefinitionImpl w = (WidgetDefinitionImpl) obj;
598        return new EqualsBuilder().append(name, w.name).append(type, w.type).append(typeCategory, w.typeCategory).append(
599                labels, w.labels).append(helpLabels, w.helpLabels).append(translated, w.translated).append(
600                handlingLabels, w.handlingLabels).append(modes, w.modes).append(fieldDefinitions, w.fieldDefinitions).append(
601                properties, w.properties).append(widgetModeProperties, w.widgetModeProperties).append(controls,
602                w.controls).append(subWidgets, w.subWidgets).append(subWidgetReferences, w.subWidgetReferences).append(
603                selectOptions, w.selectOptions).append(renderingInfos, w.renderingInfos).append(aliases, w.aliases).append(
604                dynamic, w.dynamic).append(global, w.global).isEquals();
605    }
606
607    /**
608     * @since 7.1
609     */
610    @Override
611    public String toString() {
612        final StringBuilder sb = new StringBuilder();
613
614        sb.append("WidgetDefinitionImpl");
615        sb.append(" {");
616        sb.append(" name=");
617        sb.append(name);
618        sb.append(", type=");
619        sb.append(type);
620        sb.append(", typeCategory=");
621        sb.append(typeCategory);
622        sb.append(", properties=");
623        sb.append(properties);
624        sb.append(", controls=");
625        sb.append(controls);
626        sb.append('}');
627
628        return sb.toString();
629    }
630
631}