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