001/*
002 * (C) Copyright 2011 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.functions;
018
019import java.io.Serializable;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.Comparator;
023import java.util.List;
024import java.util.Map;
025
026import org.nuxeo.ecm.platform.forms.layout.api.FieldDefinition;
027import org.nuxeo.ecm.platform.forms.layout.api.Layout;
028import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
029import org.nuxeo.ecm.platform.forms.layout.api.LayoutRow;
030import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
031import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
032import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
033import org.nuxeo.ecm.platform.forms.layout.api.WidgetSelectOption;
034import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
035import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * Provides helper methods, declared as static, to be used by the rendering framework.
040 *
041 * @since 5.5
042 */
043public class LayoutFunctions {
044
045    public static WidgetTypeDefinition getWidgetTypeDefinition(String category, String typeName) {
046        LayoutStore layoutService = Framework.getService(LayoutStore.class);
047        return layoutService.getWidgetTypeDefinition(category, typeName);
048    }
049
050    /**
051     * Returns a String representing each of the field definitions property name, separated by a space.
052     */
053    public static String getFieldDefinitionsAsString(FieldDefinition[] defs) {
054        StringBuilder buff = new StringBuilder();
055        if (defs != null) {
056            for (FieldDefinition def : defs) {
057                buff.append(def.getPropertyName()).append(" ");
058            }
059        }
060        return buff.toString().trim();
061    }
062
063    public static List<LayoutRow> getSelectedRows(Layout layout, List<String> selectedRowNames,
064            boolean showAlwaysSelected) {
065        LayoutRow[] rows = layout.getRows();
066        List<LayoutRow> selectedRows = new ArrayList<LayoutRow>();
067        if (rows != null) {
068            for (LayoutRow row : rows) {
069                if (row.isAlwaysSelected() && showAlwaysSelected) {
070                    selectedRows.add(row);
071                } else if (selectedRowNames == null && row.isSelectedByDefault() && !row.isAlwaysSelected()) {
072                    selectedRows.add(row);
073                } else if (selectedRowNames != null && selectedRowNames.contains(row.getName())) {
074                    selectedRows.add(row);
075                }
076            }
077        }
078        // preserve selected rows order
079        Collections.sort(selectedRows, new LayoutRowsSorter(selectedRowNames));
080        return selectedRows;
081    }
082
083    public static List<LayoutRow> getNotSelectedRows(Layout layout, List<String> selectedRowNames) {
084        LayoutRow[] rows = layout.getRows();
085        List<LayoutRow> notSelectedRows = new ArrayList<LayoutRow>();
086        if (rows != null) {
087            for (LayoutRow row : rows) {
088                if (selectedRowNames == null && !row.isSelectedByDefault() && !row.isAlwaysSelected()) {
089                    notSelectedRows.add(row);
090                } else if (selectedRowNames != null && !row.isAlwaysSelected()
091                        && !selectedRowNames.contains(row.getName())) {
092                    notSelectedRows.add(row);
093                }
094            }
095        }
096        return notSelectedRows;
097    }
098
099    public static List<String> getDefaultSelectedRowNames(Layout layout, boolean showAlwaysSelected) {
100        List<LayoutRow> selectedRows = getSelectedRows(layout, null, showAlwaysSelected);
101        List<String> selectedRowNames = null;
102        if (selectedRows != null && !selectedRows.isEmpty()) {
103            selectedRowNames = new ArrayList<String>();
104            for (LayoutRow row : selectedRows) {
105                selectedRowNames.add(row.getName());
106            }
107        }
108        return selectedRowNames;
109    }
110
111    /**
112     * Returns an identifier computed from this definition so that an identical definition will have the same id.
113     *
114     * @since 5.5
115     */
116    public static String computeLayoutDefinitionId(LayoutDefinition layoutDef) {
117        StringBuilder builder = new StringBuilder();
118        builder.append(layoutDef.getName()).append(";");
119        Map<String, String> templates = layoutDef.getTemplates();
120        if (templates != null) {
121            builder.append(templates.toString());
122        }
123        builder.append(";");
124        LayoutRowDefinition[] rows = layoutDef.getRows();
125        if (rows != null) {
126            for (LayoutRowDefinition row : rows) {
127                if (row != null) {
128                    builder.append(computeLayoutRowDefinitionId(row)).append(",");
129                }
130            }
131        }
132        builder.append(";");
133        Map<String, Map<String, Serializable>> properties = layoutDef.getProperties();
134        if (properties != null) {
135            builder.append(properties.toString());
136        }
137        builder.append(";");
138
139        Integer intValue = new Integer(builder.toString().hashCode());
140        return intValue.toString();
141    }
142
143    /**
144     * Returns an identifier computed from this definition so that an identical definition will have the same id.
145     *
146     * @since 5.5
147     */
148    public static String computeLayoutRowDefinitionId(LayoutRowDefinition layoutRowDef) {
149        StringBuffer builder = new StringBuffer();
150        builder.append(layoutRowDef.getName()).append(";");
151        builder.append(layoutRowDef.isSelectedByDefault()).append(";");
152        builder.append(layoutRowDef.isAlwaysSelected()).append(";");
153        WidgetReference[] widgets = layoutRowDef.getWidgetReferences();
154        if (widgets != null) {
155            for (WidgetReference widget : widgets) {
156                if (widget != null) {
157                    builder.append(widget.getName() + "(" + widget.getCategory() + ")").append(",");
158                }
159            }
160        }
161        builder.append(";");
162
163        Map<String, Map<String, Serializable>> properties = layoutRowDef.getProperties();
164        if (properties != null) {
165            builder.append(properties.toString());
166        }
167        builder.append(";");
168
169        Integer intValue = new Integer(builder.toString().hashCode());
170        return intValue.toString();
171
172    }
173
174    /**
175     * Returns an identifier computed from this definition so that an identical definition will have the same id.
176     *
177     * @since 5.5
178     */
179    public static String computeWidgetDefinitionId(WidgetDefinition widgetDef) {
180        StringBuffer builder = new StringBuffer();
181        builder.append(widgetDef.getName()).append(";");
182        builder.append(widgetDef.getType()).append(";");
183        builder.append(widgetDef.getTypeCategory()).append(";");
184
185        FieldDefinition[] fieldDefinitions = widgetDef.getFieldDefinitions();
186        if (fieldDefinitions != null) {
187            for (FieldDefinition fieldDef : fieldDefinitions) {
188                builder.append(fieldDef.getPropertyName() + ",");
189            }
190        }
191        builder.append(";");
192
193        Map<String, String> labels = widgetDef.getLabels();
194        if (labels != null) {
195            builder.append(labels.toString());
196        }
197        builder.append(";");
198        Map<String, String> helpLabels = widgetDef.getHelpLabels();
199        if (helpLabels != null) {
200            builder.append(helpLabels.toString());
201        }
202        builder.append(";");
203
204        WidgetDefinition[] subWidgets = widgetDef.getSubWidgetDefinitions();
205        if (subWidgets != null) {
206            for (WidgetDefinition widget : subWidgets) {
207                if (widget != null) {
208                    builder.append(computeWidgetDefinitionId(widget)).append(",");
209                }
210            }
211        }
212        builder.append(";");
213
214        WidgetReference[] subWidgetRefs = widgetDef.getSubWidgetReferences();
215        if (subWidgetRefs != null) {
216            for (WidgetReference widget : subWidgetRefs) {
217                if (widget != null) {
218                    builder.append(widget.getName() + "(" + widget.getCategory() + ")").append(",");
219                }
220            }
221        }
222        builder.append(";");
223
224        Map<String, Map<String, Serializable>> properties = widgetDef.getProperties();
225        if (properties != null) {
226            builder.append(properties.toString());
227        }
228        builder.append(";");
229        Map<String, Map<String, Serializable>> widgetModeProperties = widgetDef.getWidgetModeProperties();
230        if (widgetModeProperties != null) {
231            builder.append(widgetModeProperties.toString());
232        }
233        builder.append(";");
234
235        builder.append(widgetDef.isTranslated()).append(";");
236        builder.append(widgetDef.isHandlingLabels()).append(";");
237
238        Map<String, String> modes = widgetDef.getModes();
239        if (modes != null) {
240            builder.append(modes.toString());
241        }
242        builder.append(";");
243
244        WidgetSelectOption[] selectOptions = widgetDef.getSelectOptions();
245        if (selectOptions != null) {
246            for (WidgetSelectOption option : selectOptions) {
247                if (option != null) {
248                    builder.append(option.getTagConfigId()).append(",");
249                }
250            }
251        }
252        builder.append(";");
253
254        Map<String, Map<String, Serializable>> controls = widgetDef.getControls();
255        if (controls != null) {
256            builder.append(controls.toString());
257        }
258        builder.append(";");
259
260        Integer intValue = new Integer(builder.toString().hashCode());
261        return intValue.toString();
262    }
263
264    /**
265     * Sorter that re-arranges rows according to the row names order.
266     *
267     * @since 5.6
268     */
269    public static class LayoutRowsSorter implements Comparator<LayoutRow> {
270
271        protected List<String> orderedRowNames;
272
273        private LayoutRowsSorter(List<String> orderedRowNames) {
274            super();
275            this.orderedRowNames = orderedRowNames;
276        }
277
278        @Override
279        public int compare(LayoutRow o1, LayoutRow o2) {
280            if (orderedRowNames == null || orderedRowNames.size() == 0) {
281                return 0;
282            }
283            if (o1 == null && o2 == null) {
284                return 0;
285            }
286            if (o1 == null) {
287                return -1;
288            }
289            if (o2 == null) {
290                return 1;
291            }
292            String id1 = o1.getName();
293            String id2 = o2.getName();
294            if (id1 == null && id2 == null) {
295                return 0;
296            }
297            if (id1 == null) {
298                return -1;
299            }
300            if (id2 == null) {
301                return 1;
302            }
303            if (orderedRowNames.indexOf(id1) <= orderedRowNames.indexOf(id2)) {
304                return -1;
305            } else {
306                return 1;
307            }
308        }
309
310    }
311
312}