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 LARGE = valueOf("large");
87    public static final Markup LEFT = valueOf("left");
88    public static final Markup MARKED = valueOf("marked");
89    public static final Markup MODAL = valueOf("modal");
90    public static final Markup NUMBER = valueOf("number");
91    public static final Markup ODD = valueOf("odd");
92    public static final Markup PORTLET = valueOf("portlet");
93    public static final Markup READONLY = valueOf("readonly");
94    public static final Markup REQUIRED = valueOf("required");
95    public static final Markup RESIZABLE = valueOf("resizable");
96    public static final Markup RIGHT = valueOf("right");
97    public static final Markup SECONDS = valueOf("seconds");
98    public static final Markup SELECTED = valueOf("selected");
99    /** @deprecated since 3.0.4 */
100   @Deprecated
101   public static final Markup SHEET_SELECT_ALL = valueOf("sheetSelectAll");
102   /** @deprecated since 3.0.4 */
103   @Deprecated
104   public static final Markup SHEET_DESELECT_ALL = valueOf("sheetDeselectAll");
105   /** @deprecated since 3.0.4 */
106   @Deprecated
107   public static final Markup SHEET_TOGGLE_ALL = valueOf("sheetToggleAll");
108   public static final Markup SMALL = valueOf("small");
109   public static final Markup SORTABLE = valueOf("sortable");
110   public static final Markup SPREAD = valueOf("spread");
111   public static final Markup STRIPED = valueOf("striped");
112   public static final Markup STRONG = valueOf("strong");
113   public static final Markup TOP = valueOf("top");
114   public static final Markup VERTICALLY = valueOf("vertically");
115   public static final Markup WARN = valueOf("warn");
116 
117   /* Just one of "values" and "value" must be null */
118 
119   private final String[] values;
120   private final String value;
121 
122   private Markup(final String[] values) {
123     this.values = values;
124     this.value = null;
125   }
126 
127   private Markup(final String value) {
128     this.values = null;
129     this.value = value;
130   }
131 
132   public static Markup valueOf(final String[] values) {
133     if (values == null || values.length == 0) {
134       return null;
135     } else if (values.length == 1) {
136       return valueOf(values[0]);
137     } else {
138       final Markup markup = new Markup(values.clone());
139       for (int i = 0; i < markup.values.length; i++) {
140         markup.values[i] = markup.values[i].trim();
141       }
142       return markup;
143     }
144   }
145 
146   public static Markup valueOf(final String value) {
147     if (StringUtils.isEmpty(value)) {
148       return null;
149     }
150     if (value.contains(",")) {
151       final String[] strings = StringUtils.split(value, ", \t\n");
152       return new Markup(strings);
153     } else {
154       return new Markup(value.trim());
155     }
156   }
157 
158   public static Markup valueOf(final Object value) {
159     if (value == null) {
160       return null;
161     }
162     if (value instanceof Markup) {
163       return (Markup) value;
164     }
165     if (value instanceof String) {
166       return valueOf((String) value);
167     }
168     if (value instanceof String[]) {
169       return valueOf((String[]) value);
170     }
171     if (value instanceof Iterable) {
172       final List<String> list = new ArrayList<String>();
173       for (final Object object : (Iterable) value) {
174         list.add(object.toString());
175       }
176       return valueOf(list.toArray(new String[list.size()]));
177     }
178     return valueOf(value.toString());
179   }
180 
181   @Override
182   public boolean equals(final Object o) {
183     if (this == o) {
184       return true;
185     }
186     if (o == null || getClass() != o.getClass()) {
187       return false;
188     }
189 
190     final Markup markup = (Markup) o;
191 
192     if (value != null ? !value.equals(markup.value) : markup.value != null) {
193       return false;
194     }
195     if (!Arrays.equals(values, markup.values)) {
196       return false;
197     }
198 
199     return true;
200   }
201 
202   @Override
203   public int hashCode() {
204     int result = values != null ? Arrays.hashCode(values) : 0;
205     result = 31 * result + (value != null ? value.hashCode() : 0);
206     return result;
207   }
208 
209   @Override
210   public Iterator<String> iterator() {
211     if (value != null) {
212       return new SingletonIterator(value);
213     }
214     if (values != null) {
215       return new ObjectArrayIterator(values);
216     }
217     return EmptyIterator.INSTANCE;
218   }
219 
220   /**
221    * Adds one markup to an other.
222    * Attention: The markup itself is not modified, you need to use the result of this operation.
223    */
224   public Markup add(final Markup markup) {
225     if (markup == null) {
226       return this;
227     }
228     if (markup == NULL) {
229       return this;
230     }
231     if (markup.value != null) {
232       return add(markup.value);
233     } else {
234       // this part is not optimized, but it will be used rarely, in the moment...
235       Markup result = this;
236       if (markup.values != null) {
237         for (final String summand : markup.values) {
238           result = result.add(summand);
239         }
240       }
241       return result;
242     }
243   }
244 
245   private Markup add(final String summand) {
246     if (summand == null) {
247       return this;
248     }
249     if (values == null) {
250       if (value == null) {
251         return valueOf(summand);
252       } else {
253         if (summand.equals(value)) {
254           return this;
255         } else {
256           return valueOf(new String[]{value, summand});
257         }
258       }
259     } else {
260       if (ArrayUtils.contains(values, summand)) {
261         return this;
262       } else {
263         final String[] strings = new String[values.length + 1];
264         System.arraycopy(values, 0, strings, 0, values.length);
265         strings[values.length] = summand;
266         return valueOf(strings);
267       }
268     }
269   }
270 
271   public Markup remove(final Markup markup) {
272     if (markup.value != null) {
273       return remove(markup.value);
274     } else {
275       // this part is not optimized, but it will be used rarely, in the moment...
276       Markup result = this;
277       for (final String summand : markup.values) {
278         result = result.remove(summand);
279       }
280       return result;
281     }
282   }
283 
284   private Markup remove(final String summand) {
285     if (summand == null) {
286       return this;
287     }
288     if (values == null) {
289       if (value == null) {
290         return this;
291       } else {
292         if (summand.equals(value)) {
293           return NULL;
294         } else {
295           return this;
296         }
297       }
298     } else {
299       if (ArrayUtils.contains(values, summand)) {
300         final String[] strings = new String[values.length - 1];
301         int found = 0;
302         for (int i = 0; i < strings.length; i++) {
303           if (values[i].equals(summand)) {
304             found++;
305           }
306           strings[i] = values[i + found];
307         }
308         return valueOf(strings);
309       } else {
310         return this;
311       }
312     }
313   }
314 
315   public boolean contains(final String markup) {
316     if (markup == null) {
317       return true;
318     }
319     if (this == NULL) {
320       return this == Markup.valueOf(markup);
321     }
322     if (value != null) {
323       return value.equals(markup);
324     }
325     for (final String v : values) {
326       if (v.equals(markup)) {
327         return true;
328       }
329     }
330     return false;
331   }
332 
333   public boolean contains(final Markup markup) {
334     if (markup == null || markup == NULL) {
335       return true;
336     }
337     if (this == NULL) {
338       return this == markup;
339     }
340     if (markup.value != null) {
341       if (value != null) {
342         return value.equals(markup.value);
343       } else {
344         for (final String v : values) {
345           if (v.equals(markup.value)) {
346             return true;
347           }
348         }
349         return false;
350       }
351     } else {
352       if (value != null) {
353         return false;
354       } else {
355         for (final String markupString : markup.values) {
356           if (!contains(markupString)) {
357             return false;
358           }
359         }
360         return true;
361       }
362     }
363   }
364 
365   @Override
366   public String toString() {
367     if (value != null) {
368       return value;
369     }
370     if (values == null) {
371       return "null";
372     }
373     return Arrays.toString(values);
374   }
375 
376 }