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