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