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.LinkedHashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.nuxeo.ecm.platform.forms.layout.api.BuiltinModes;
029import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
030import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
031import org.nuxeo.ecm.platform.forms.layout.api.RenderingInfo;
032import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
033import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
034
035/**
036 * Default implementation for a layout definition.
037 * <p>
038 * Useful to compute layouts independently from the layout service.
039 *
040 * @author Anahide Tchertchian
041 * @since 5.4
042 */
043public class LayoutDefinitionImpl implements LayoutDefinition {
044
045    private static final long serialVersionUID = 1L;
046
047    protected String name;
048
049    protected String type;
050
051    protected String typeCategory;
052
053    protected Map<String, Map<String, Serializable>> properties;
054
055    protected Map<String, String> templates;
056
057    protected LayoutRowDefinition[] rows;
058
059    protected Map<String, WidgetDefinition> widgets;
060
061    protected Map<String, List<RenderingInfo>> renderingInfos;
062
063    protected Integer columns;
064
065    protected List<String> aliases;
066
067    protected boolean dynamic = false;
068
069    // needed by GWT serialization
070    protected LayoutDefinitionImpl() {
071        super();
072    }
073
074    public LayoutDefinitionImpl(String name, String template, WidgetDefinition widgetDefinition) {
075        super();
076        this.name = name;
077        this.properties = null;
078        this.templates = new HashMap<>();
079        if (template != null) {
080            this.templates.put(BuiltinModes.ANY, template);
081        }
082        this.widgets = new HashMap<>();
083        if (widgetDefinition != null) {
084            this.widgets.put(widgetDefinition.getName(), widgetDefinition);
085            this.rows = new LayoutRowDefinition[] { new LayoutRowDefinitionImpl(null, widgetDefinition.getName()) };
086        } else {
087            this.rows = new LayoutRowDefinition[0];
088        }
089    }
090
091    public LayoutDefinitionImpl(String name, Map<String, Map<String, Serializable>> properties,
092            Map<String, String> templates, List<LayoutRowDefinition> rows, List<WidgetDefinition> widgetDefinitions) {
093        super();
094        this.name = name;
095        this.properties = properties;
096        this.templates = templates;
097        if (rows == null) {
098            this.rows = new LayoutRowDefinition[0];
099        } else {
100            this.rows = rows.toArray(new LayoutRowDefinition[0]);
101        }
102        this.widgets = new HashMap<>();
103        if (widgetDefinitions != null) {
104            for (WidgetDefinition widgetDef : widgetDefinitions) {
105                this.widgets.put(widgetDef.getName(), widgetDef);
106            }
107        }
108    }
109
110    public LayoutDefinitionImpl(String name, Map<String, Map<String, Serializable>> properties,
111            Map<String, String> templates, LayoutRowDefinition[] rows, Map<String, WidgetDefinition> widgets) {
112        super();
113        this.name = name;
114        this.properties = properties;
115        this.templates = templates;
116        this.rows = rows;
117        this.widgets = widgets;
118    }
119
120    @Override
121    public int getColumns() {
122        if (columns == null) {
123            // compute it
124            columns = Integer.valueOf(0);
125            LayoutRowDefinition[] rows = getRows();
126            for (LayoutRowDefinition def : rows) {
127                int current = def.getWidgetReferences().length;
128                if (current > columns.intValue()) {
129                    columns = Integer.valueOf(current);
130                }
131            }
132        }
133        return columns.intValue();
134    }
135
136    @Override
137    public String getName() {
138        return name;
139    }
140
141    @Override
142    public void setName(String name) {
143        this.name = name;
144    }
145
146    /**
147     * @since 6.0
148     */
149    @Override
150    public String getType() {
151        return type;
152    }
153
154    /**
155     * @since 6.0
156     */
157    public void setType(String type) {
158        this.type = type;
159    }
160
161    /**
162     * @since 6.0
163     */
164    @Override
165    public String getTypeCategory() {
166        return typeCategory;
167    }
168
169    /**
170     * @since 6.0
171     */
172    public void setTypeCategory(String typeCategory) {
173        this.typeCategory = typeCategory;
174    }
175
176    @Override
177    public Map<String, Serializable> getProperties(String layoutMode) {
178        return WidgetDefinitionImpl.getProperties(properties, layoutMode);
179    }
180
181    @Override
182    public Map<String, Map<String, Serializable>> getProperties() {
183        return properties;
184    }
185
186    @Override
187    public void setProperties(Map<String, Map<String, Serializable>> properties) {
188        this.properties = properties;
189    }
190
191    @Override
192    public LayoutRowDefinition[] getRows() {
193        return rows;
194    }
195
196    @Override
197    public void setRows(LayoutRowDefinition[] rows) {
198        this.rows = rows;
199    }
200
201    /**
202     * @since 6.0
203     */
204    public static String getTemplate(Map<String, String> templates, String mode) {
205        if (templates != null) {
206            String template = templates.get(mode);
207            if (template == null) {
208                template = templates.get(BuiltinModes.ANY);
209            }
210            return template;
211        }
212        return null;
213    }
214
215    @Override
216    public String getTemplate(String mode) {
217        return getTemplate(templates, mode);
218    }
219
220    @Override
221    public Map<String, String> getTemplates() {
222        return templates;
223    }
224
225    @Override
226    public void setTemplates(Map<String, String> templates) {
227        this.templates = templates;
228    }
229
230    @Override
231    public WidgetDefinition getWidgetDefinition(String name) {
232        if (widgets != null) {
233            return widgets.get(name);
234        }
235        return null;
236    }
237
238    @Override
239    public Map<String, WidgetDefinition> getWidgetDefinitions() {
240        return widgets;
241    }
242
243    @Override
244    public Map<String, List<RenderingInfo>> getRenderingInfos() {
245        return renderingInfos;
246    }
247
248    @Override
249    public void setRenderingInfos(Map<String, List<RenderingInfo>> renderingInfos) {
250        this.renderingInfos = renderingInfos;
251    }
252
253    @Override
254    public List<RenderingInfo> getRenderingInfos(String mode) {
255        return WidgetDefinitionImpl.getRenderingInfos(renderingInfos, mode);
256    }
257
258    @Override
259    public boolean isEmpty() {
260        LayoutRowDefinition[] rows = getRows();
261        if (rows == null) {
262            return true;
263        }
264        for (LayoutRowDefinition row : rows) {
265            WidgetReference[] refs = row.getWidgetReferences();
266            if (refs != null) {
267                for (WidgetReference ref : refs) {
268                    if (ref.getName() != null && !ref.getName().isEmpty()) {
269                        return false;
270                    }
271                }
272            }
273        }
274        return true;
275    }
276
277    @Override
278    public List<String> getAliases() {
279        return aliases;
280    }
281
282    public void setAliases(List<String> aliases) {
283        this.aliases = aliases;
284    }
285
286    @Override
287    public boolean isDynamic() {
288        return dynamic;
289    }
290
291    public void setDynamic(boolean dynamic) {
292        this.dynamic = dynamic;
293    }
294
295    @Override
296    public LayoutDefinition clone() {
297        Map<String, Map<String, Serializable>> cprops = null;
298        if (properties != null) {
299            cprops = new HashMap<>();
300            for (Map.Entry<String, Map<String, Serializable>> entry : properties.entrySet()) {
301                Map<String, Serializable> subProps = entry.getValue();
302                Map<String, Serializable> csubProps = null;
303                if (subProps != null) {
304                    csubProps = new HashMap<>();
305                    csubProps.putAll(subProps);
306                }
307                cprops.put(entry.getKey(), csubProps);
308            }
309        }
310        Map<String, String> ctemplates = null;
311        if (templates != null) {
312            ctemplates = new HashMap<>();
313            ctemplates.putAll(templates);
314        }
315        LayoutRowDefinition[] crows = null;
316        if (rows != null) {
317            crows = new LayoutRowDefinition[rows.length];
318            for (int i = 0; i < rows.length; i++) {
319                crows[i] = rows[i].clone();
320            }
321        }
322        Map<String, WidgetDefinition> cwidgets = null;
323        if (widgets != null) {
324            cwidgets = new LinkedHashMap<>();
325            for (Map.Entry<String, WidgetDefinition> entry : widgets.entrySet()) {
326                WidgetDefinition w = entry.getValue();
327                if (w != null) {
328                    w = w.clone();
329                }
330                cwidgets.put(entry.getKey(), w);
331            }
332        }
333        Map<String, List<RenderingInfo>> crenderingInfos = null;
334        if (renderingInfos != null) {
335            crenderingInfos = new HashMap<>();
336            for (Map.Entry<String, List<RenderingInfo>> item : renderingInfos.entrySet()) {
337                List<RenderingInfo> infos = item.getValue();
338                List<RenderingInfo> clonedInfos = null;
339                if (infos != null) {
340                    clonedInfos = new ArrayList<>();
341                    for (RenderingInfo info : infos) {
342                        clonedInfos.add(info.clone());
343                    }
344                }
345                crenderingInfos.put(item.getKey(), clonedInfos);
346            }
347        }
348        LayoutDefinitionImpl clone = new LayoutDefinitionImpl(name, cprops, ctemplates, crows, cwidgets);
349        clone.setRenderingInfos(crenderingInfos);
350        clone.setType(type);
351        clone.setTypeCategory(typeCategory);
352        if (aliases != null) {
353            clone.setAliases(new ArrayList<>(aliases));
354        }
355        clone.setDynamic(dynamic);
356        return clone;
357    }
358
359    /**
360     * @since 7.2
361     */
362    @Override
363    public boolean equals(Object obj) {
364        if (!(obj instanceof LayoutDefinitionImpl)) {
365            return false;
366        }
367        if (obj == this) {
368            return true;
369        }
370        LayoutDefinitionImpl ld = (LayoutDefinitionImpl) obj;
371        return new EqualsBuilder().append(name, ld.name).append(type, ld.type).append(typeCategory, ld.typeCategory).append(
372                properties, ld.properties).append(templates, ld.templates).append(rows, ld.rows).append(widgets,
373                ld.widgets).append(renderingInfos, ld.renderingInfos).append(aliases, ld.aliases).append(dynamic,
374                ld.dynamic).isEquals();
375    }
376
377}