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.demo.jsf;
018
019import static org.jboss.seam.ScopeType.EVENT;
020import static org.jboss.seam.ScopeType.SESSION;
021
022import java.io.Serializable;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Locale;
028import java.util.Map;
029
030import org.jboss.seam.annotations.Factory;
031import org.jboss.seam.annotations.In;
032import org.jboss.seam.annotations.Name;
033import org.jboss.seam.annotations.Scope;
034import org.jboss.seam.faces.FacesMessages;
035import org.jboss.seam.international.LocaleSelector;
036import org.jboss.seam.international.StatusMessage;
037import org.nuxeo.ecm.core.api.DocumentModel;
038import org.nuxeo.ecm.core.api.NuxeoException;
039import org.nuxeo.ecm.core.api.validation.ConstraintViolation;
040import org.nuxeo.ecm.core.api.validation.DocumentValidationReport;
041import org.nuxeo.ecm.core.api.validation.DocumentValidationService;
042import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
043import org.nuxeo.ecm.platform.forms.layout.api.LayoutRowDefinition;
044import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
045import org.nuxeo.ecm.platform.forms.layout.api.WidgetReference;
046import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
047import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
048import org.nuxeo.ecm.platform.forms.layout.demo.service.DemoWidgetType;
049import org.nuxeo.ecm.platform.forms.layout.demo.service.LayoutDemoManager;
050import org.nuxeo.ecm.platform.forms.layout.service.WebLayoutManager;
051import org.nuxeo.ecm.platform.url.api.DocumentView;
052import org.nuxeo.runtime.api.Framework;
053
054/**
055 * Seam component providing a document model for layout demo and testing, and handling reset of this document model when
056 * the page changes.
057 *
058 * @author Anahide Tchertchian
059 */
060@Name("layoutDemoActions")
061@Scope(SESSION)
062public class LayoutDemoActions implements Serializable {
063
064    private static final long serialVersionUID = 1L;
065
066    @In(create = true)
067    protected LayoutDemoManager layoutDemoManager;
068
069    @In(create = true)
070    protected WebLayoutManager webLayoutManager;
071
072    @In(create = true)
073    protected DocumentModel layoutBareDemoDocument;
074
075    @In(create = true)
076    protected DocumentModel layoutValidationDocument;
077
078    @In(create = true)
079    protected LayoutDemoContext layoutDemoContext;
080
081    protected DocumentModel layoutDemoDocument;
082
083    protected DemoWidgetType currentWidgetType;
084
085    protected String currentTabId;
086
087    protected String currentSubTabId;
088
089    protected PreviewLayoutDefinition viewPreviewLayoutDef;
090
091    protected PreviewLayoutDefinition editPreviewLayoutDef;
092
093    /**
094     * @since 7.2
095     */
096    @In(create = true)
097    protected transient LocaleSelector localeSelector;
098
099    /**
100     * @since 7.2
101     */
102    @In(create = true)
103    protected FacesMessages facesMessages;
104
105    /**
106     * @since 7.2
107     */
108    @In(create = true)
109    protected Map<String, String> messages;
110
111    @Factory(value = "layoutDemoDocument", scope = EVENT)
112    public DocumentModel getDemoDocument() {
113        if (layoutDemoDocument == null) {
114            try {
115                layoutDemoDocument = layoutBareDemoDocument.clone();
116            } catch (CloneNotSupportedException e) {
117                throw new NuxeoException(e);
118            }
119        }
120        return layoutDemoDocument;
121    }
122
123    public String initContextFromRestRequest(DocumentView docView) {
124
125        DemoWidgetType widgetType = null;
126        boolean isPreviewFrame = false;
127        if (docView != null) {
128            String viewId = docView.getViewId();
129            if (viewId != null) {
130                // try to deduce current widget type
131                widgetType = layoutDemoManager.getWidgetTypeByViewId(viewId);
132            }
133        }
134
135        if (!isPreviewFrame) {
136            // avoid resetting contextual info when generating preview frame
137            setCurrentWidgetType(widgetType);
138        }
139
140        return null;
141    }
142
143    public void setCurrentWidgetType(DemoWidgetType newWidgetType) {
144        if (currentWidgetType != null && !currentWidgetType.equals(newWidgetType)) {
145            // reset demo doc too
146            layoutDemoDocument = null;
147            viewPreviewLayoutDef = null;
148            editPreviewLayoutDef = null;
149            currentTabId = null;
150            currentSubTabId = null;
151        }
152        currentWidgetType = newWidgetType;
153    }
154
155    @Factory(value = "currentWidgetType", scope = EVENT)
156    public DemoWidgetType getCurrentWidgetType() {
157        return currentWidgetType;
158    }
159
160    @Factory(value = "currentWidgetTypeDef", scope = EVENT)
161    public WidgetTypeDefinition getCurrentWidgetTypeDefinition() {
162        if (currentWidgetType != null) {
163            String type = currentWidgetType.getName();
164            LayoutStore lm = Framework.getLocalService(LayoutStore.class);
165            return lm.getWidgetTypeDefinition(currentWidgetType.getWidgetTypeCategory(), type);
166        }
167        return null;
168    }
169
170    @Factory(value = "layoutDemoCurrentTabId", scope = EVENT)
171    public String getCurrentTabId() {
172        return currentTabId;
173    }
174
175    public void setCurrentTabId(String currentTabId) {
176        this.currentTabId = currentTabId;
177    }
178
179    @Factory(value = "layoutDemoCurrentSubTabId", scope = EVENT)
180    public String getCurrentSubTabId() {
181        return currentSubTabId;
182    }
183
184    public void setCurrentSubTabId(String currentSubTabId) {
185        this.currentSubTabId = currentSubTabId;
186    }
187
188    protected PreviewLayoutDefinition createPreviewLayoutDefinition(DemoWidgetType widgetType) {
189        String type = widgetType.getName();
190
191        Map<String, Serializable> props = new HashMap<>();
192        if (widgetType.getDefaultProperties() != null) {
193            props.putAll(widgetType.getDefaultProperties());
194        }
195        if (type != null && type.contains("Aggregate")) {
196            // fill up aggregates mapping as default properties
197            if (type.contains("Aggregate")) {
198                props.put("selectOptions", "#{layoutDemoAggregates['dir_terms'].buckets}");
199            } else {
200                props.put("selectOptions", "#{layoutDemoAggregates['string_terms'].buckets}");
201            }
202            props.put("directoryName", "layout_demo_crew");
203        }
204        PreviewLayoutDefinition def = new PreviewLayoutDefinition(widgetType.getName(), widgetType.getFields(), props);
205
206        if (def != null) {
207            // add some special conf for preview needs, hardcoded right now
208            if ("list".equals(type)) {
209                LayoutDefinition ldef = webLayoutManager.getLayoutDefinition("complexListWidgetLayout");
210                def.setSubWidgets(retrieveSubWidgets(ldef));
211            } else if ("complex".equals(type)) {
212                LayoutDefinition ldef = webLayoutManager.getLayoutDefinition("complexWidgetLayout");
213                def.setSubWidgets(retrieveSubWidgets(ldef));
214            } else if ("container".equals(type)) {
215                LayoutDefinition ldef = webLayoutManager.getLayoutDefinition("containerWidgetLayout");
216                def.setSubWidgets(retrieveSubWidgets(ldef));
217                def.setHandlingLabels(Boolean.TRUE);
218            } else if ("actions".equals(type) || "toggleableLayoutWithForms".equals(type)) {
219                def.setHandlingLabels(Boolean.TRUE);
220            }
221        }
222
223        // set a custom label and help label
224        def.setLabel("My widget label");
225        def.setHelpLabel("My widget help label");
226        return def;
227    }
228
229    protected List<WidgetDefinition> retrieveSubWidgets(LayoutDefinition layoutDef) {
230        List<WidgetDefinition> res = new ArrayList<WidgetDefinition>();
231        LayoutRowDefinition[] rows = layoutDef.getRows();
232        if (rows != null && rows.length > 0) {
233            WidgetReference[] refs = rows[0].getWidgetReferences();
234            if (refs != null && refs.length > 0) {
235                String wName = refs[0].getName();
236                WidgetDefinition wDef = layoutDef.getWidgetDefinition(wName);
237                if (wDef != null) {
238                    WidgetDefinition[] subs = wDef.getSubWidgetDefinitions();
239                    if (subs != null) {
240                        res.addAll(Arrays.asList(subs));
241                    }
242                }
243            }
244        }
245        return res;
246    }
247
248    @Factory(value = "viewPreviewLayoutDef", scope = EVENT)
249    public PreviewLayoutDefinition getViewPreviewLayoutDefinition() {
250        if (viewPreviewLayoutDef == null && currentWidgetType != null) {
251            viewPreviewLayoutDef = createPreviewLayoutDefinition(currentWidgetType);
252        }
253        return viewPreviewLayoutDef;
254    }
255
256    @Factory(value = "editPreviewLayoutDef", scope = EVENT)
257    public PreviewLayoutDefinition getEditPreviewLayoutDefinition() {
258        if (editPreviewLayoutDef == null && currentWidgetType != null) {
259            editPreviewLayoutDef = createPreviewLayoutDefinition(currentWidgetType);
260        }
261        return editPreviewLayoutDef;
262    }
263
264    /**
265     * @since 7.2
266     */
267    public void validateDocument() {
268        DocumentValidationService s = Framework.getService(DocumentValidationService.class);
269        DocumentValidationReport report = s.validate(layoutValidationDocument);
270        if (report.hasError()) {
271            Locale locale = localeSelector.getLocale();
272            for (ConstraintViolation v : report.asList()) {
273                String msg = v.getMessage(locale);
274                facesMessages.addToControl("errors", StatusMessage.Severity.ERROR, msg);
275            }
276        } else {
277            facesMessages.addToControl("errors", StatusMessage.Severity.INFO, "Validation done");
278        }
279    }
280
281    /**
282     * @since 7.2
283     */
284    public String resetValidationDocument() {
285        layoutDemoContext.resetValidationDocument();
286        return null;
287    }
288
289}