001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (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 * Nuxeo - initial API and implementation 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.ui.web.directory; 021 022import java.io.IOException; 023import java.util.List; 024import java.util.Locale; 025import java.util.Map; 026 027import javax.faces.component.UICommand; 028import javax.faces.component.UIComponent; 029import javax.faces.component.UIOutput; 030import javax.faces.component.UIParameter; 031import javax.faces.context.FacesContext; 032import javax.faces.context.ResponseWriter; 033import javax.faces.el.ValueBinding; 034 035import org.apache.commons.lang.StringUtils; 036import org.apache.commons.logging.Log; 037import org.apache.commons.logging.LogFactory; 038import org.nuxeo.common.utils.i18n.I18NUtils; 039 040/** 041 * @author <a href="mailto:glefter@nuxeo.com">George Lefter</a> 042 */ 043public class ChainSelectStatus extends UIOutput { 044 045 public static final String COMPONENT_TYPE = "nxdirectory.chainSelectStatus"; 046 047 public static final String COMPONENT_FAMILY = "nxdirectory.chainSelectStatus"; 048 049 public static final String REMOVE_ID = "chainSelect_removeId"; 050 051 @SuppressWarnings("unused") 052 private static final Log log = LogFactory.getLog(ChainSelectStatus.class); 053 054 private String name; 055 056 private boolean displayIncremental = false; 057 058 private boolean displayRoot = false; 059 060 private String cssStyle; 061 062 private String cssStyleClass; 063 064 private String entryCssStyle; 065 066 private String entryCssStyleClass; 067 068 private String entrySeparator; 069 070 private String image; 071 072 // what to display - the value or the selection of the component 073 private String display; 074 075 // what will be display as a label in front of the select result 076 private String label; 077 078 public String getEntrySeparator() { 079 return entrySeparator; 080 } 081 082 public void setEntrySeparator(String entrySeparator) { 083 this.entrySeparator = entrySeparator; 084 } 085 086 @Override 087 public String getFamily() { 088 return COMPONENT_FAMILY; 089 } 090 091 @Override 092 public String getRendererType() { 093 return null; 094 } 095 096 @Override 097 public void restoreState(FacesContext context, Object state) { 098 Object[] values = (Object[]) state; 099 super.restoreState(context, values[0]); 100 name = (String) values[1]; 101 displayIncremental = (Boolean) values[2]; 102 displayRoot = (Boolean) values[3]; 103 cssStyle = (String) values[4]; 104 cssStyleClass = (String) values[5]; 105 entryCssStyle = (String) values[6]; 106 entryCssStyleClass = (String) values[7]; 107 entrySeparator = (String) values[8]; 108 display = (String) values[9]; 109 image = (String) values[10]; 110 label = (String) values[11]; 111 } 112 113 @Override 114 public Object saveState(FacesContext arg0) { 115 Object[] values = new Object[12]; 116 values[0] = super.saveState(arg0); 117 values[1] = name; 118 values[2] = displayIncremental; 119 values[3] = displayRoot; 120 values[4] = cssStyle; 121 values[5] = cssStyleClass; 122 values[6] = entryCssStyle; 123 values[7] = entryCssStyleClass; 124 values[8] = entrySeparator; 125 values[9] = display; 126 values[10] = image; 127 values[11] = label; 128 return values; 129 } 130 131 @Override 132 public void encodeBegin(FacesContext context) throws IOException { 133 ResponseWriter writer = context.getResponseWriter(); 134 String id = getClientId(context); 135 136 String cssStyle = getStringProperty("cssStyle", null); 137 String cssStyleClass = getStringProperty("cssStyleClass", null); 138 String separator = getStringProperty("separator", "/"); 139 String entrySeparator = getStringProperty("entrySeparator", null); 140 String label = getStringProperty("label", null); 141 142 ChainSelect chain = getChain(); 143 Boolean displayValueOnly = chain.getBooleanProperty("displayValueOnly", false); 144 String display = getStringProperty("display", "selection"); 145 146 Selection[] selections; 147 if (display.equals("selection")) { 148 selections = chain.getSelections(); 149 } else { 150 selections = chain.getComponentValue(); 151 } 152 153 boolean multiParentSelect = chain.getBooleanProperty("multiParentSelect", false); 154 155 if (displayValueOnly) { 156 cssStyle = chain.getStringProperty("displayValueOnlyStyle", null); 157 cssStyleClass = chain.getStringProperty("displayValueOnlyStyleClass", null); 158 } 159 160 writer.startElement("div", this); 161 writer.writeAttribute("id", id, "id"); 162 if (cssStyle != null) { 163 writer.writeAttribute("style", cssStyle, "style"); 164 } 165 if (cssStyleClass != null) { 166 writer.writeAttribute("class", cssStyleClass, "class"); 167 } 168 169 if (selections.length > 0 && label != null) { 170 writer.write(label); 171 } 172 173 for (int i = 0; i < selections.length; i++) { 174 writer.startElement("div", this); 175 if (entryCssStyle != null) { 176 writer.writeAttribute("style", entryCssStyle, "style"); 177 } 178 if (entryCssStyleClass != null) { 179 // FIXME: is this a typo? Should it be entryCssStyleClass down there instead of entryCssStyle? 180 writer.writeAttribute("class", entryCssStyle, "class"); 181 } 182 if (!displayValueOnly && display.equals("value") && multiParentSelect) { 183 UICommand button = (UICommand) getFacet("removeButton"); 184 if (button == null) { 185 throw new RuntimeException("f:facet with name='removeButton' not found for component " + getId()); 186 } 187 String selectionId = selections[i].getValue(chain.getKeySeparator()); 188 getUIParameter(button).setValue(selectionId); 189 190 button.encodeBegin(context); 191 button.encodeChildren(context); 192 button.encodeEnd(context); 193 } 194 195 String[] labels = selections[i].getLabels(); 196 String[] values = selections[i].getValues(); 197 String[] displayedLabels = null; 198 if (labels != null) { 199 displayedLabels = new String[labels.length]; 200 for (int j = 0; j < labels.length; j++) { 201 // boolean localize = chain.getComponent(j) 202 // .getBooleanProperty("localize", false); 203 boolean localize; 204 String compDisplay; 205 if (chain.compInfos.get(i) != null) { 206 localize = chain.compInfos.get(i).localize; 207 compDisplay = chain.compInfos.get(i).display; 208 } else { 209 // fallback on the old solution 210 localize = chain.getComponent(j).getBooleanProperty("localize", false); 211 compDisplay = chain.getComponent(j).getDisplay(); 212 } 213 214 String compLabel = labels[j]; 215 if (localize) { 216 compLabel = translate(context, compLabel); 217 } 218 219 if ("id".equals(compDisplay)) { 220 displayedLabels[j] = values[j]; 221 } else if ("idAndLabel".equals(compDisplay)) { 222 displayedLabels[j] = values[j] + " " + compLabel; 223 } else { 224 // default to "label" 225 displayedLabels[j] = compLabel; 226 } 227 } 228 } 229 230 String concatenatedLabel = StringUtils.join(displayedLabels, separator); 231 if (concatenatedLabel.compareTo("") == 0 && displayedLabels.length != 0) { 232 concatenatedLabel = translate(context, "label.directories.error"); 233 } 234 writer.write(concatenatedLabel); 235 writer.endElement("div"); 236 if (i != selections.length - 1) { 237 if (entrySeparator != null) { 238 writer.write(entrySeparator); 239 } 240 } 241 } 242 } 243 244 private UIParameter getUIParameter(UIComponent component) { 245 UIParameter param = null; 246 for (UIComponent child : component.getChildren()) { 247 if (child instanceof UIParameter) { 248 UIParameter paramChild = (UIParameter) child; 249 if (REMOVE_ID.equals(paramChild.getName())) { 250 param = (UIParameter) child; 251 break; 252 } 253 } 254 } 255 if (param == null) { 256 param = new UIParameter(); 257 param.setName(REMOVE_ID); 258 component.getChildren().add(param); 259 } 260 261 return param; 262 } 263 264 @Override 265 public void encodeChildren(FacesContext context) throws IOException { 266 } 267 268 @Override 269 public void encodeEnd(FacesContext context) throws IOException { 270 ResponseWriter writer = context.getResponseWriter(); 271 writer.endElement("div"); 272 273 List<UIComponent> children = getChildren(); 274 for (UIComponent component : children) { 275 component.setRendered(true); 276 } 277 } 278 279 public Object getProperty(String name) { 280 ValueBinding vb = getValueBinding(name); 281 if (vb != null) { 282 return vb.getValue(FacesContext.getCurrentInstance()); 283 } else { 284 Map<String, Object> attrMap = getAttributes(); 285 return attrMap.get(name); 286 } 287 } 288 289 public String getStringProperty(String name, String defaultValue) { 290 String value = (String) getProperty(name); 291 return value != null ? value : defaultValue; 292 } 293 294 public Boolean getBooleanProperty(String name, Boolean defaultValue) { 295 Boolean value = (Boolean) getProperty(name); 296 return value != null ? value : defaultValue; 297 } 298 299 public String getName() { 300 return name; 301 } 302 303 public void setName(String name) { 304 this.name = name; 305 } 306 307 public ChainSelect getChain() { 308 UIComponent component = getParent(); 309 while (component != null && !(component instanceof ChainSelect)) { 310 component = component.getParent(); 311 } 312 return (ChainSelect) component; 313 } 314 315 public boolean isDisplayIncremental() { 316 return displayIncremental; 317 } 318 319 public void setDisplayIncremental(boolean displayIncremental) { 320 this.displayIncremental = displayIncremental; 321 } 322 323 public boolean isDisplayRoot() { 324 return displayRoot; 325 } 326 327 public void setDisplayRoot(boolean displayRoot) { 328 this.displayRoot = displayRoot; 329 } 330 331 public String getCssStyle() { 332 return cssStyle; 333 } 334 335 public void setCssStyle(String cssStyle) { 336 this.cssStyle = cssStyle; 337 } 338 339 public String getCssStyleClass() { 340 return cssStyleClass; 341 } 342 343 public void setCssStyleClass(String cssStyleClass) { 344 this.cssStyleClass = cssStyleClass; 345 } 346 347 public String getEntryCssStyle() { 348 return entryCssStyle; 349 } 350 351 public void setEntryCssStyle(String entryCssStyle) { 352 this.entryCssStyle = entryCssStyle; 353 } 354 355 public String getEntryCssStyleClass() { 356 return entryCssStyleClass; 357 } 358 359 public void setEntryCssStyleClass(String entryCssStyleClass) { 360 this.entryCssStyleClass = entryCssStyleClass; 361 } 362 363 public String getImage() { 364 return image; 365 } 366 367 public void setImage(String image) { 368 this.image = image; 369 } 370 371 public String getDisplay() { 372 return display; 373 } 374 375 public void setDisplay(String display) { 376 this.display = display; 377 } 378 379 public String getLabel() { 380 return label; 381 } 382 383 public void setLabel(String label) { 384 this.label = label; 385 } 386 387 protected static String translate(FacesContext context, String label) { 388 String bundleName = context.getApplication().getMessageBundle(); 389 Locale locale = context.getViewRoot().getLocale(); 390 label = I18NUtils.getMessageString(bundleName, label, null, locale); 391 return label; 392 } 393 394}