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