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  
20  package org.apache.myfaces.tobago.renderkit;
21  
22  import org.apache.myfaces.tobago.component.SupportsAccessKey;
23  import org.apache.myfaces.tobago.component.UISelectBooleanCheckbox;
24  import org.apache.myfaces.tobago.config.TobagoConfig;
25  import org.apache.myfaces.tobago.internal.util.Deprecation;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  import javax.faces.context.FacesContext;
30  import java.util.Locale;
31  
32  public final class LabelWithAccessKey {
33  
34    private static final Logger LOG = LoggerFactory.getLogger(LabelWithAccessKey.class);
35  
36    public static final char INDICATOR = '_';
37    private static final String ESCAPED_INDICATOR = "__";
38  
39    private final String label;
40    private final Character accessKey;
41    private final int pos;
42  
43    /**
44     * @deprecated since 2.0.0. This is a workaround.
45     */
46    @Deprecated
47    public LabelWithAccessKey(final String label) {
48      this(new SupportsAccessKey() {
49        public Character getAccessKey() {
50          return null;
51        }
52  
53        public String getLabel() {
54          return label;
55        }
56      });
57    }
58  
59    public LabelWithAccessKey(final SupportsAccessKey component) {
60  
61      String label0;
62      Character accessKey0;
63      int pos0 = -1;
64  
65      label0 = component.getLabel();
66  
67      // compatibility since TOBAGO-1093
68      if (component instanceof UISelectBooleanCheckbox) {
69        final String itemLabel = ((UISelectBooleanCheckbox) component).getItemLabel();
70        if (itemLabel != null) {
71          label0 = itemLabel;
72        }
73      }
74  
75      accessKey0 = component.getAccessKey();
76      if (accessKey0 != null) {
77        accessKey0 = Character.toLowerCase(accessKey0);
78        if (!isPermitted(accessKey0)) {
79          LOG.warn("Ignoring illegal access key: " + accessKey0);
80          accessKey0 = null;
81        }
82      }
83  
84      boolean auto = TobagoConfig.getInstance(FacesContext.getCurrentInstance()).isAutoAccessKeyFromLabel();
85      // try to find the accessKey from the label if
86      // a) it's configured to do that AND
87      // b) there wasn't an accessKey defined in the component AND
88      // c) there is a label
89      if (auto && component.getAccessKey() == null && label0 != null) {
90  
91        final int first = label0.indexOf(INDICATOR);
92        if (first > -1) {
93          final char[] chars = label0.toCharArray();
94          int j = first;
95          for (int i = first; i < chars.length; i++) {
96            if (chars[i] == INDICATOR) {
97              if (i + 1 < chars.length) {
98                i++; // ignore the first one
99                chars[j] = chars[i];
100               if (chars[i] != INDICATOR) {
101                 if (accessKey0 == null) {
102                   pos0 = j;
103                   accessKey0 = Character.toLowerCase(chars[i]);
104                   if (!isPermitted(accessKey0)) {
105                     LOG.warn("Ignoring illegal access key: " + accessKey0);
106                     accessKey0 = null;
107                     pos0 = -1;
108                   }
109                 }
110               }
111               j++;
112             } else {
113               LOG.warn("'" + INDICATOR + "' in label is last char, this is not allowed label='" + label0 + "'.");
114             }
115           } else {
116             chars[j] = chars[i];
117             j++;
118           }
119         }
120         label0 = new String(chars, 0, j);
121       }
122 
123     } else {
124       if (accessKey0 != null && label0 != null) {
125         pos0 = label0.toLowerCase(Locale.ENGLISH).indexOf(accessKey0);
126       }
127     }
128 
129     label = label0;
130     accessKey = accessKey0;
131     pos = pos0;
132   }
133 
134 /*
135   private void findIndicator(final String label, int index, int escapedIndicatorCount) {
136 
137     index = label.indexOf(INDICATOR, index);
138     if (index == -1) {
139       text = label;
140     } else {
141       if (index == label.length() - 1) {
142         LOG.warn(INDICATOR + " in label is last char, this is not allowed"
143             + "label='" + label + "'.");
144         text = label.substring(0, label.length() - 1);
145         pos = -1;
146       } else if (label.charAt(index + 1) == INDICATOR) {
147         escapedIndicatorCount++;
148         findIndicator(label, index + 2, escapedIndicatorCount);
149       } else {
150         text = label.substring(0, index)
151             + label.substring(index + 1);
152         setAccessKey(text.charAt(index));
153         pos = index - escapedIndicatorCount;
154       }
155     }
156   }
157 */
158 
159   /**
160    * @deprecated since 2.0.0. Attributes are final now, use a new instance.
161    */
162   @Deprecated
163   public void setup(final String label) {
164     Deprecation.LOG.error("Ignoring label: " + label);
165   }
166 
167   /**
168    * @deprecated since 2.0.0. Attributes are final now, use a new instance.
169    */
170   @Deprecated
171   public void reset() {
172     Deprecation.LOG.error("Ignoring reset.");
173   }
174 
175   /**
176    * @deprecated since 2.0.0. Please use {@link #getLabel()}.
177    */
178   @Deprecated
179   public String getText() {
180     return label;
181   }
182 
183   public String getLabel() {
184     return label;
185   }
186 
187   public Character getAccessKey() {
188     return accessKey;
189   }
190 
191   public int getPos() {
192     return pos;
193   }
194 
195   /**
196    * @deprecated since 2.0.0. Attributes are final now, use a new instance.
197    */
198   @Deprecated
199   public void setText(final String text) {
200     Deprecation.LOG.error("Ignoring label: " + text);
201   }
202 
203   /**
204    * @deprecated since 2.0.0. Attributes are final now, use a new instance.
205    */
206   @Deprecated
207   public void setAccessKey(Character accessKey) {
208     Deprecation.LOG.error("Ignoring accessKey: " + accessKey);
209   }
210 
211   /**
212    * Ensures, that no illegal character will be write out.
213    * (If this is changed from only allowing normal letters and numbers, the renderers may change the escaping)
214    */
215   private boolean isPermitted(final Character accessKey) {
216     return accessKey == null || accessKey >= 'a' && accessKey <= 'z' || accessKey >= '0' && accessKey <= '9';
217   }
218 }