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 CENTER = valueOf("center");
64    public static final Markup CLICKABLE = valueOf("clickable");
65    public static final Markup DEFAULT = valueOf("default");
66    public static final Markup DELETED = valueOf("deleted");
67    public static final Markup DESCENDING = valueOf("descending");
68    public static final Markup DISABLED = valueOf("disabled");
69    public static final Markup ERROR = valueOf("error");
70    public static final Markup EVEN = valueOf("even");
71    public static final Markup EXPANDED = valueOf("expanded");
72    public static final Markup FILLER = valueOf("filler");
73    public static final Markup FATAL = valueOf("fatal");
74    public static final Markup FIRST = valueOf("first");
75    public static final Markup FOLDER = valueOf("folder");
76    public static final Markup INFO = valueOf("info");
77    public static final Markup INLINE = valueOf("inline");
78    public static final Markup JUSTIFY = valueOf("justify");
79    public static final Markup LEFT = valueOf("left");
80    public static final Markup MARKED = valueOf("marked");
81    public static final Markup MODAL = valueOf("modal");
82    public static final Markup NUMBER = valueOf("number");
83    public static final Markup ODD = valueOf("odd");
84    public static final Markup PORTLET = valueOf("portlet");
85    public static final Markup PURE = valueOf("pure");
86    public static final Markup READONLY = valueOf("readonly");
87    public static final Markup REQUIRED = valueOf("required");
88    public static final Markup RESIZABLE = valueOf("resizable");
89    public static final Markup RIGHT = valueOf("right");
90    public static final Markup SECONDS = valueOf("seconds");
91    public static final Markup SELECTED = valueOf("selected");
92    public static final Markup SHEET_SELECT_ALL = valueOf("sheetSelectAll");
93    public static final Markup SHEET_DESELECT_ALL = valueOf("sheetDeselectAll");
94    public static final Markup SHEET_TOGGLE_ALL = valueOf("sheetToggleAll");
95    public static final Markup SORTABLE = valueOf("sortable");
96    public static final Markup STRONG = valueOf("strong");
97    public static final Markup TOP = valueOf("top");
98    public static final Markup VERTICALLY = valueOf("vertically");
99    public static final Markup WARN = valueOf("warn");
100 
101   /* Just one of "values" and "value" must be null */
102 
103   private final String[] values;
104   private final String value;
105 
106   private Markup(final String[] values) {
107     this.values = values;
108     this.value = null;
109   }
110 
111   private Markup(final String value) {
112     this.values = null;
113     this.value = value;
114   }
115 
116   public static Markup valueOf(final String[] values) {
117     if (values == null || values.length == 0) {
118       return null;
119     } else if (values.length == 1) {
120       return valueOf(values[0]);
121     } else {
122       final Markup markup = new Markup(values.clone());
123       for (int i = 0; i < markup.values.length; i++) {
124         markup.values[i] = markup.values[i].trim();
125       }
126       return markup;
127     }
128   }
129 
130   public static Markup valueOf(final String value) {
131     if (StringUtils.isEmpty(value)) {
132       return null;
133     }
134     if (value.contains(",")) {
135       final String[] strings = StringUtils.split(value, ", \t\n");
136       return new Markup(strings);
137     } else {
138       return new Markup(value.trim());
139     }
140   }
141 
142   public static Markup valueOf(final Object value) {
143     if (value == null) {
144       return null;
145     }
146     if (value instanceof Markup) {
147       return (Markup) value;
148     }
149     if (value instanceof String) {
150       return valueOf((String) value);
151     }
152     if (value instanceof String[]) {
153       return valueOf((String[]) value);
154     }
155     if (value instanceof Iterable) {
156       final List<String> list = new ArrayList<String>();
157       for (final Object object : (Iterable) value) {
158         list.add(object.toString());
159       }
160       return valueOf(list.toArray(new String[list.size()]));
161     }
162     return valueOf(value.toString());
163   }
164 
165   @Override
166   public boolean equals(final Object o) {
167     if (this == o) {
168       return true;
169     }
170     if (o == null || getClass() != o.getClass()) {
171       return false;
172     }
173 
174     final Markup markup = (Markup) o;
175 
176     if (value != null ? !value.equals(markup.value) : markup.value != null) {
177       return false;
178     }
179     if (!Arrays.equals(values, markup.values)) {
180       return false;
181     }
182 
183     return true;
184   }
185 
186   @Override
187   public int hashCode() {
188     int result = values != null ? Arrays.hashCode(values) : 0;
189     result = 31 * result + (value != null ? value.hashCode() : 0);
190     return result;
191   }
192 
193   @Override
194   public Iterator<String> iterator() {
195     if (value != null) {
196       return new SingletonIterator(value);
197     }
198     if (values != null) {
199       return new ObjectArrayIterator(values);
200     }
201     return EmptyIterator.INSTANCE;
202   }
203 
204   /**
205    * Adds one markup to an other.
206    * Attention: The markup itself is not modified, you need to use the result of this operation.
207    */
208   public Markup add(final Markup markup) {
209     if (markup == null) {
210       return this;
211     }
212     if (markup == NULL) {
213       return this;
214     }
215     if (markup.value != null) {
216       return add(markup.value);
217     } else {
218       // this part is not optimized, but it will be used rarely, in the moment...
219       Markup result = this;
220       if (markup.values != null) {
221         for (final String summand : markup.values) {
222           result = result.add(summand);
223         }
224       }
225       return result;
226     }
227   }
228 
229   private Markup add(final String summand) {
230     if (summand == null) {
231       return this;
232     }
233     if (values == null) {
234       if (value == null) {
235         return valueOf(summand);
236       } else {
237         if (summand.equals(value)) {
238           return this;
239         } else {
240           return valueOf(new String[]{value, summand});
241         }
242       }
243     } else {
244       if (ArrayUtils.contains(values, summand)) {
245         return this;
246       } else {
247         final String[] strings = new String[values.length + 1];
248         System.arraycopy(values, 0, strings, 0, values.length);
249         strings[values.length] = summand;
250         return valueOf(strings);
251       }
252     }
253   }
254 
255   public Markup remove(final Markup markup) {
256     if (markup.value != null) {
257       return remove(markup.value);
258     } else {
259       // this part is not optimized, but it will be used rarely, in the moment...
260       Markup result = this;
261       for (final String summand : markup.values) {
262         result = result.remove(summand);
263       }
264       return result;
265     }
266   }
267 
268   private Markup remove(final String summand) {
269     if (summand == null) {
270       return this;
271     }
272     if (values == null) {
273       if (value == null) {
274         return this;
275       } else {
276         if (summand.equals(value)) {
277           return NULL;
278         } else {
279           return this;
280         }
281       }
282     } else {
283       if (ArrayUtils.contains(values, summand)) {
284         final String[] strings = new String[values.length - 1];
285         int found = 0;
286         for (int i = 0; i < strings.length; i++) {
287           if (values[i].equals(summand)) {
288             found++;
289           }
290           strings[i] = values[i + found];
291         }
292         return valueOf(strings);
293       } else {
294         return this;
295       }
296     }
297   }
298 
299   public boolean contains(final String markup) {
300     if (markup == null) {
301       return false;
302     }
303     if (this == NULL) {
304       return this == Markup.valueOf(markup);
305     }
306     if (value != null) {
307       return value.equals(markup);
308     }
309     for (final String value : values) {
310         if (value.equals(markup)) {
311           return true;
312         }
313       }
314       return false;
315   }
316 
317   @Override
318   public String toString() {
319     if (value != null) {
320       return value;
321     }
322     if (values == null) {
323       return "null";
324     }
325     return Arrays.toString(values);
326   }
327 
328 }