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}