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