View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared.renderkit.html.util;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Set;
25  import javax.faces.component.UIComponent;
26  import javax.faces.component.UISelectItems;
27  import javax.faces.component.UISelectMany;
28  import javax.faces.component.UISelectOne;
29  import javax.faces.context.FacesContext;
30  import javax.faces.context.ResponseWriter;
31  import javax.faces.convert.Converter;
32  import javax.faces.model.SelectItem;
33  import javax.faces.model.SelectItemGroup;
34  import org.apache.myfaces.shared.component.EscapeCapable;
35  import org.apache.myfaces.shared.renderkit.JSFAttr;
36  import org.apache.myfaces.shared.renderkit.RendererUtils;
37  import org.apache.myfaces.shared.renderkit.html.HTML;
38  import static org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils.isHideNoSelectionOption;
39  import org.apache.myfaces.shared.util.SelectItemsIterator;
40  
41  /**
42   * Utility methods to manipulate SelectItem/SelectItems
43   */
44  public class SelectItemsUtils
45  {
46      private static final char TABULATOR = '\t';
47  
48      public static List<SelectItemInfo> getSelectItemInfoList(UISelectMany uiSelectMany,
49              FacesContext facesContext)
50      {
51          List<SelectItemInfo> list = new ArrayList<SelectItemInfo>();
52  
53          for (SelectItemsIterator iter = new SelectItemsIterator(uiSelectMany, facesContext); iter.hasNext();)
54          {
55              list.add(new SelectItemInfo(iter.next(), iter.getCurrentComponent(), iter.getCurrentValue()));
56          }
57          return list;
58      }
59  
60      public static List<SelectItemInfo> getSelectItemInfoList(UISelectOne uiSelectOne,
61              FacesContext facesContext)
62      {
63          List<SelectItemInfo> list = new ArrayList<SelectItemInfo>();
64          for (SelectItemsIterator iter = new SelectItemsIterator(uiSelectOne, facesContext); iter.hasNext();)
65          {
66              list.add(new SelectItemInfo(iter.next(), iter.getCurrentComponent(), iter.getCurrentValue()));
67          }
68          return list;
69      }
70      
71      public static void renderSelectOptions(FacesContext context,
72              UIComponent component, Converter converter, Set lookupSet,
73              List<SelectItemInfo> selectItemList) throws IOException
74      {
75          ResponseWriter writer = context.getResponseWriter();
76          // check for the hideNoSelectionOption attribute
77          boolean hideNoSelectionOption = isHideNoSelectionOption(component);
78          boolean componentDisabled = isTrue(component.getAttributes()
79                  .get("disabled"));
80  
81          for (int i = 0; i < selectItemList.size(); i++)
82          {
83              SelectItemInfo selectItemInfo = selectItemList.get(i);
84              SelectItem selectItem = selectItemInfo.getItem();
85              if (selectItem instanceof SelectItemGroup)
86              {
87                  writer.startElement(HTML.OPTGROUP_ELEM, selectItemInfo.getComponent()); // component);
88                  writer.writeAttribute(HTML.LABEL_ATTR, selectItem.getLabel(), null);
89  
90                  SelectItem[] selectItems = ((SelectItemGroup) selectItem).getSelectItems();
91                  List<SelectItemInfo> selectItemsGroupList = new ArrayList<SelectItemInfo>(selectItems.length);
92                  for (SelectItem item : selectItems)
93                  {
94                      selectItemsGroupList.add(new SelectItemInfo(item, null));
95                  }
96                  renderSelectOptions(context, component, converter, lookupSet,
97                          selectItemsGroupList);
98                  writer.endElement(HTML.OPTGROUP_ELEM);
99              }
100             else
101             {
102                 String itemStrValue = org.apache.myfaces.shared.renderkit.RendererUtils
103                         .getConvertedStringValue(context, component, converter,
104                                 selectItem);
105                 boolean selected = lookupSet.contains(itemStrValue); 
106                 //TODO/FIX: we always compare the String vales, better fill lookupSet with Strings 
107                 //only when useSubmittedValue==true, else use the real item value Objects
108 
109                 // IF the hideNoSelectionOption attribute of the component is true
110                 // AND this selectItem is the "no selection option"
111                 // AND there are currently selected items 
112                 // AND this item (the "no selection option") is not selected
113                 // (if there is currently no value on UISelectOne, lookupSet contains "")
114                 if (hideNoSelectionOption && selectItem.isNoSelectionOption()
115                         && !lookupSet.isEmpty()
116                         && !(lookupSet.size() == 1 && lookupSet.contains(""))
117                         && !selected)
118                 {
119                     // do not render this selectItem
120                     continue;
121                 }
122 
123                 writer.write(TABULATOR);
124                 
125                 boolean wroteRequestMapVarValue = false;
126                 Object oldRequestMapVarValue = null;
127                 String var = null;
128                 if (selectItemInfo != null && selectItemInfo.getComponent() instanceof UISelectItems)
129                 {
130                     var = (String) selectItemInfo.getComponent().getAttributes().get(JSFAttr.VAR_ATTR);
131                     if(var != null && !"".equals(var))
132                     {
133                         // save the current value of the key listed in var from the request map
134                         oldRequestMapVarValue = context.getExternalContext().getRequestMap().put(var, 
135                                 selectItemInfo.getValue());
136                         wroteRequestMapVarValue = true;
137                     }
138                 }
139                 
140                 writer.startElement(HTML.OPTION_ELEM, selectItemInfo.getComponent()); // component);
141                 if (itemStrValue != null)
142                 {
143                     writer.writeAttribute(HTML.VALUE_ATTR, itemStrValue, null);
144                 }
145                 else
146                 {
147                     writer.writeAttribute(HTML.VALUE_ATTR, "", null);
148                 }
149 
150                 if (selected)
151                 {
152                     writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
153                 }
154 
155                 boolean disabled = selectItem.isDisabled();
156                 if (disabled)
157                 {
158                     writer.writeAttribute(HTML.DISABLED_ATTR, HTML.DISABLED_ATTR, null);
159                 }
160 
161                 String labelClass = null;
162 
163                 if (componentDisabled || disabled)
164                 {
165                     labelClass = (String) component.getAttributes().get(JSFAttr.DISABLED_CLASS_ATTR);
166                 }
167                 else
168                 {
169                     labelClass = (String) component.getAttributes().get(JSFAttr.ENABLED_CLASS_ATTR);
170                 }
171                 if (labelClass != null)
172                 {
173                     writer.writeAttribute("class", labelClass, "labelClass");
174                 }
175 
176                 boolean escape;
177                 if (component instanceof EscapeCapable)
178                 {
179                     escape = ((EscapeCapable) component).isEscape();
180 
181                     // Preserve tomahawk semantic. If escape=false
182                     // all items should be non escaped. If escape
183                     // is true check if selectItem.isEscape() is
184                     // true and do it.
185                     // This is done for remain compatibility.
186                     if (escape && selectItem.isEscape())
187                     {
188                         writer.writeText(selectItem.getLabel(), null);
189                     }
190                     else
191                     {
192                         writer.write(selectItem.getLabel());
193                     }
194                 }
195                 else
196                 {
197                     escape = RendererUtils.getBooleanAttribute(component, JSFAttr.ESCAPE_ATTR, false);
198                     //default is to escape
199                     //In JSF 1.2, when a SelectItem is created by default 
200                     //selectItem.isEscape() returns true (this property
201                     //is not available on JSF 1.1).
202                     //so, if we found a escape property on the component
203                     //set to true, escape every item, but if not
204                     //check if isEscape() = true first.
205                     if (escape || selectItem.isEscape())
206                     {
207                         writer.writeText(selectItem.getLabel(), null);
208                     }
209                     else
210                     {
211                         writer.write(selectItem.getLabel());
212                     }
213                 }
214 
215                 writer.endElement(HTML.OPTION_ELEM);
216                 
217                 // remove the value with the key from var from the request map, if previously written
218                 if(wroteRequestMapVarValue)
219                 {
220                     // If there was a previous value stored with the key from var in the request map, restore it
221                     if (oldRequestMapVarValue != null)
222                     {
223                         context.getExternalContext().getRequestMap().put(var, oldRequestMapVarValue);
224                     }
225                     else
226                     {
227                         context.getExternalContext().getRequestMap().remove(var);
228                     }
229                 }
230             }
231         }
232     }
233 
234     private static boolean isTrue(Object obj)
235     {
236         if (obj instanceof String)
237         {
238             return Boolean.valueOf((String) obj);
239         }
240         if (!(obj instanceof Boolean))
241         {
242             return false;
243         }
244         return ((Boolean) obj).booleanValue();
245     }
246 }