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<String, String>();
079        if (template != null) {
080            this.templates.put(BuiltinModes.ANY, template);
081        }
082        this.widgets = new HashMap<String, WidgetDefinition>();
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<String, WidgetDefinition>();
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 = new Integer(0);
125            LayoutRowDefinition[] rows = getRows();
126            for (LayoutRowDefinition def : rows) {
127                int current = def.getWidgetReferences().length;
128                if (current > columns.intValue()) {
129                    columns = new Integer(current);
130                }
131            }
132        }
133        return columns.intValue();
134    }
135
136    @Override
137    public String getName() {
138        return name;
139    }
140
141    public void setName(String name) {
142        this.name = name;
143    }
144
145    /**
146     * @since 6.0
147     */
148    public String getType() {
149        return type;
150    }
151
152    /**
153     * @since 6.0
154     */
155    public void setType(String type) {
156        this.type = type;
157    }
158
159    /**
160     * @since 6.0
161     */
162    public String getTypeCategory() {
163        return typeCategory;
164    }
165
166    /**
167     * @since 6.0
168     */
169    public void setTypeCategory(String typeCategory) {
170        this.typeCategory = typeCategory;
171    }
172
173    @Override
174    public Map<String, Serializable> getProperties(String layoutMode) {
175        return WidgetDefinitionImpl.getProperties(properties, layoutMode);
176    }
177
178    @Override
179    public Map<String, Map<String, Serializable>> getProperties() {
180        return properties;
181    }
182
183    public void setProperties(Map<String, Map<String, Serializable>> properties) {
184        this.properties = properties;
185    }
186
187    @Override
188    public LayoutRowDefinition[] getRows() {
189        return rows;
190    }
191
192    public void setRows(LayoutRowDefinition[] rows) {
193        this.rows = rows;
194    }
195
196    /**
197     * @since 6.0
198     */
199    public static String getTemplate(Map<String, String> templates, String mode) {
200        if (templates != null) {
201            String template = templates.get(mode);
202            if (template == null) {
203                template = templates.get(BuiltinModes.ANY);
204            }
205            return template;
206        }
207        return null;
208    }
209
210    @Override
211    public String getTemplate(String mode) {
212        return getTemplate(templates, mode);
213    }
214
215    @Override
216    public Map<String, String> getTemplates() {
217        return templates;
218    }
219
220    public void setTemplates(Map<String, String> templates) {
221        this.templates = templates;
222    }
223
224    @Override
225    public WidgetDefinition getWidgetDefinition(String name) {
226        if (widgets != null) {
227            return widgets.get(name);
228        }
229        return null;
230    }
231
232    @Override
233    public Map<String, WidgetDefinition> getWidgetDefinitions() {
234        return widgets;
235    }
236
237    @Override
238    public Map<String, List<RenderingInfo>> getRenderingInfos() {
239        return renderingInfos;
240    }
241
242    public void setRenderingInfos(Map<String, List<RenderingInfo>> renderingInfos) {
243        this.renderingInfos = renderingInfos;
244    }
245
246    @Override
247    public List<RenderingInfo> getRenderingInfos(String mode) {
248        return WidgetDefinitionImpl.getRenderingInfos(renderingInfos, mode);
249    }
250
251    public boolean isEmpty() {
252        LayoutRowDefinition[] rows = getRows();
253        if (rows == null) {
254            return true;
255        }
256        for (LayoutRowDefinition row : rows) {
257            WidgetReference[] refs = row.getWidgetReferences();
258            if (refs != null) {
259                for (WidgetReference ref : refs) {
260                    if (ref.getName() != null && !ref.getName().isEmpty()) {
261                        return false;
262                    }
263                }
264            }
265        }
266        return true;
267    }
268
269    @Override
270    public List<String> getAliases() {
271        return aliases;
272    }
273
274    public void setAliases(List<String> aliases) {
275        this.aliases = aliases;
276    }
277
278    public boolean isDynamic() {
279        return dynamic;
280    }
281
282    public void setDynamic(boolean dynamic) {
283        this.dynamic = dynamic;
284    }
285
286    @Override
287    public LayoutDefinition clone() {
288        Map<String, Map<String, Serializable>> cprops = null;
289        if (properties != null) {
290            cprops = new HashMap<String, Map<String, Serializable>>();
291            for (Map.Entry<String, Map<String, Serializable>> entry : properties.entrySet()) {
292                Map<String, Serializable> subProps = entry.getValue();
293                Map<String, Serializable> csubProps = null;
294                if (subProps != null) {
295                    csubProps = new HashMap<String, Serializable>();
296                    csubProps.putAll(subProps);
297                }
298                cprops.put(entry.getKey(), csubProps);
299            }
300        }
301        Map<String, String> ctemplates = null;
302        if (templates != null) {
303            ctemplates = new HashMap<String, String>();
304            ctemplates.putAll(templates);
305        }
306        LayoutRowDefinition[] crows = null;
307        if (rows != null) {
308            crows = new LayoutRowDefinition[rows.length];
309            for (int i = 0; i < rows.length; i++) {
310                crows[i] = rows[i].clone();
311            }
312        }
313        Map<String, WidgetDefinition> cwidgets = null;
314        if (widgets != null) {
315            cwidgets = new LinkedHashMap<String, WidgetDefinition>();
316            for (Map.Entry<String, WidgetDefinition> entry : widgets.entrySet()) {
317                WidgetDefinition w = entry.getValue();
318                if (w != null) {
319                    w = w.clone();
320                }
321                cwidgets.put(entry.getKey(), w);
322            }
323        }
324        Map<String, List<RenderingInfo>> crenderingInfos = null;
325        if (renderingInfos != null) {
326            crenderingInfos = new HashMap<String, List<RenderingInfo>>();
327            for (Map.Entry<String, List<RenderingInfo>> item : renderingInfos.entrySet()) {
328                List<RenderingInfo> infos = item.getValue();
329                List<RenderingInfo> clonedInfos = null;
330                if (infos != null) {
331                    clonedInfos = new ArrayList<RenderingInfo>();
332                    for (RenderingInfo info : infos) {
333                        clonedInfos.add(info.clone());
334                    }
335                }
336                crenderingInfos.put(item.getKey(), clonedInfos);
337            }
338        }
339        LayoutDefinitionImpl clone = new LayoutDefinitionImpl(name, cprops, ctemplates, crows, cwidgets);
340        clone.setRenderingInfos(crenderingInfos);
341        clone.setType(type);
342        clone.setTypeCategory(typeCategory);
343        if (aliases != null) {
344            clone.setAliases(new ArrayList<String>(aliases));
345        }
346        clone.setDynamic(dynamic);
347        return clone;
348    }
349
350    /**
351     * @since 7.2
352     */
353    @Override
354    public boolean equals(Object obj) {
355        if (!(obj instanceof LayoutDefinitionImpl)) {
356            return false;
357        }
358        if (obj == this) {
359            return true;
360        }
361        LayoutDefinitionImpl ld = (LayoutDefinitionImpl) obj;
362        return new EqualsBuilder().append(name, ld.name).append(type, ld.type).append(typeCategory, ld.typeCategory).append(
363                properties, ld.properties).append(templates, ld.templates).append(rows, ld.rows).append(widgets,
364                ld.widgets).append(renderingInfos, ld.renderingInfos).append(aliases, ld.aliases).append(dynamic,
365                ld.dynamic).isEquals();
366    }
367
368}