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