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