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.context;
21  
22  import org.apache.commons.collections.iterators.EmptyIterator;
23  import org.apache.commons.collections.iterators.ObjectArrayIterator;
24  import org.apache.commons.collections.iterators.SingletonIterator;
25  import org.apache.commons.lang.ArrayUtils;
26  import org.apache.commons.lang.StringUtils;
27  
28  import java.io.Serializable;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Iterator;
32  import java.util.List;
33  
34  /**
35   * A markup signs a component to be rendered different from the normal.
36   * E. g. <code>markup="emphasized"</code> might be rendered bold
37   * or a <code>markup="deleted"</code> might be rendered with line-through style.
38   * The concrete rendering depends from the theme.
39   * <p/>
40   * The markup can also hold more than one value, e. g. <code>markup="emphasized, deleted"</code>.
41   * <p/>
42   * The value of the markup is unmodifiable.
43   * <p/>
44   * A markup must be registered for a component, before it can be used.
45   * <p/>
46   * A markup should only contain ASCII characters and digits.
47   */
48  public final class Markup implements Serializable, Iterable<String> {
49  
50    public static final Markup NULL = new Markup((String) null);
51  
52    public static final Markup ASCENDING = valueOf("ascending");
53    public static final Markup CENTER = valueOf("center");
54    public static final Markup CLICKABLE = valueOf("clickable");
55    public static final Markup DEFAULT = valueOf("default");
56    public static final Markup DELETED = valueOf("deleted");
57    public static final Markup DESCENDING = valueOf("descending");
58    public static final Markup DISABLED = valueOf("disabled");
59    public static final Markup ERROR = valueOf("error");
60    public static final Markup EVEN = valueOf("even");
61    public static final Markup EXPANDED = valueOf("expanded");
62    public static final Markup FILLER = valueOf("filler");
63    public static final Markup FATAL = valueOf("fatal");
64    public static final Markup FIRST = valueOf("first");
65    public static final Markup FOLDER = valueOf("folder");
66    public static final Markup INFO = valueOf("info");
67    public static final Markup INLINE = valueOf("inline");
68    public static final Markup LEFT = valueOf("left");
69    public static final Markup MARKED = valueOf("marked");
70    public static final Markup MODAL = valueOf("modal");
71    public static final Markup NUMBER = valueOf("number");
72    public static final Markup ODD = valueOf("odd");
73    public static final Markup PURE = valueOf("pure");
74    public static final Markup READONLY = valueOf("readonly");
75    public static final Markup REQUIRED = valueOf("required");
76    public static final Markup RESIZABLE = valueOf("resizable");
77    public static final Markup RIGHT = valueOf("right");
78    public static final Markup SECONDS = valueOf("seconds");
79    public static final Markup SELECTED = valueOf("selected");
80    public static final Markup SHEET_SELECT_ALL = valueOf("sheetSelectAll");
81    public static final Markup SHEET_DESELECT_ALL = valueOf("sheetDeselectAll");
82    public static final Markup SHEET_TOGGLE_ALL = valueOf("sheetToggleAll");
83    public static final Markup SORTABLE = valueOf("sortable");
84    public static final Markup STRONG = valueOf("strong");
85    public static final Markup TOP = valueOf("top");
86    public static final Markup WARN = valueOf("warn");
87  
88    /* Just one of "values" and "value" must be null */
89  
90    private final String[] values;
91    private final String value;
92  
93    private Markup(String[] values) {
94      this.values = values;
95      this.value = null;
96    }
97  
98    private Markup(String value) {
99      this.values = null;
100     this.value = value;
101   }
102 
103   public static Markup valueOf(String[] values) {
104     if (values == null || values.length == 0) {
105       return null;
106     } else if (values.length == 1) {
107       return valueOf(values[0]);
108     } else {
109       Markup markup = new Markup((String[]) ArrayUtils.clone(values));
110       for (int i = 0; i < markup.values.length; i++) {
111         markup.values[i] = markup.values[i].trim();
112       }
113       return markup;
114     }
115   }
116 
117   public static Markup valueOf(String value) {
118     if (StringUtils.isEmpty(value)) {
119       return null;
120     }
121     if (value.contains(",")) {
122       String[] strings = StringUtils.split(value, ", \t\n");
123       return new Markup(strings);
124     } else {
125       return new Markup(value.trim());
126     }
127   }
128 
129   public static Markup valueOf(Object value) {
130     if (value == null) {
131       return null;
132     }
133     if (value instanceof Markup) {
134       return (Markup) value;
135     }
136     if (value instanceof String) {
137       return valueOf((String) value);
138     }
139     if (value instanceof String[]) {
140       return valueOf((String[]) value);
141     }
142     if (value instanceof Iterable) {
143       List<String> list = new ArrayList<String>();
144       for (Object object : (Iterable) value) {
145         list.add(object.toString());
146       }
147       return valueOf(list.toArray(new String[list.size()]));
148     }
149     return valueOf(value.toString());
150   }
151 
152   @Override
153   public boolean equals(Object o) {
154     if (this == o) {
155       return true;
156     }
157     if (o == null || getClass() != o.getClass()) {
158       return false;
159     }
160 
161     Markup markup = (Markup) o;
162 
163     if (value != null ? !value.equals(markup.value) : markup.value != null) {
164       return false;
165     }
166     if (!Arrays.equals(values, markup.values)) {
167       return false;
168     }
169 
170     return true;
171   }
172 
173   @Override
174   public int hashCode() {
175     int result = values != null ? Arrays.hashCode(values) : 0;
176     result = 31 * result + (value != null ? value.hashCode() : 0);
177     return result;
178   }
179 
180   public Iterator<String> iterator() {
181     if (value != null) {
182       return new SingletonIterator(value);
183     }
184     if (values != null) {
185       return new ObjectArrayIterator(values);
186     }
187     return EmptyIterator.INSTANCE;
188   }
189 
190   /**
191    * Adds one markup to an other.
192    * Attention: The markup itself is not modified, you need to use the result of this operation.
193    */
194   public Markup add(Markup markup) {
195     if (markup == null) {
196       return this;
197     }
198     if (markup == NULL) {
199       return this;
200     }
201     if (markup.value != null) {
202       return add(markup.value);
203     } else {
204       // this part is not optimized, but it will be used rarely, in the moment...
205       Markup result = this;
206       if (markup.values != null) {
207         for (String summand : markup.values) {
208           result = result.add(summand);
209         }
210       }
211       return result;
212     }
213   }
214 
215   private Markup add(String summand) {
216     if (summand == null) {
217       return this;
218     }
219     if (values == null) {
220       if (value == null) {
221         return valueOf(summand);
222       } else {
223         if (summand.equals(value)) {
224           return this;
225         } else {
226           return valueOf(new String[]{value, summand});
227         }
228       }
229     } else {
230       if (ArrayUtils.contains(values, summand)) {
231         return this;
232       } else {
233         final String[] strings = new String[values.length + 1];
234         System.arraycopy(values, 0, strings, 0, values.length);
235         strings[values.length] = summand;
236         return valueOf(strings);
237       }
238     }
239   }
240 
241   public Markup remove(Markup markup) {
242     if (markup.value != null) {
243       return remove(markup.value);
244     } else {
245       // this part is not optimized, but it will be used rarely, in the moment...
246       Markup result = this;
247       for (String summand : markup.values) {
248         result = result.remove(summand);
249       }
250       return result;
251     }
252   }
253 
254   private Markup remove(String summand) {
255     if (summand == null) {
256       return this;
257     }
258     if (values == null) {
259       if (value == null) {
260         return this;
261       } else {
262         if (summand.equals(value)) {
263           return NULL;
264         } else {
265           return this;
266         }
267       }
268     } else {
269       if (ArrayUtils.contains(values, summand)) {
270         final String[] strings = new String[values.length - 1];
271         int found = 0;
272         for (int i = 0; i < strings.length; i++) {
273           if (values[i].equals(summand)) {
274             found++;
275           }
276           strings[i] = values[i + found];
277         }
278         return valueOf(strings);
279       } else {
280         return this;
281       }
282     }
283   }
284 
285   public boolean contains(String markup) {
286     if (markup == null) {
287       return false;
288     }
289     if (this == NULL) {
290       return this == Markup.valueOf(markup);
291     }
292     if (value != null) {
293       return value.equals(markup);
294     }
295     for (String value : values) {
296         if (value.equals(markup)) {
297           return true;
298         }
299       }
300       return false;
301   }
302 
303   @Override
304   public String toString() {
305     if (value != null) {
306       return value;
307     }
308     if (values == null) {
309       return "null";
310     }
311     return Arrays.toString(values);
312   }
313 }