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.myfaces.tobago.internal.util.ArrayUtils;
23  import org.apache.myfaces.tobago.internal.util.StringUtils;
24  
25  import java.io.Serializable;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  /**
33   * <p>
34   * A markup signs a component to be rendered different from the normal.
35   * E. g. <code>markup="emphasized"</code> might be rendered bold
36   * or a <code>markup="deleted"</code> might be rendered with line-through style.
37   * The concrete rendering depends from the theme.
38   * </p>
39   * <p>
40   * The markup can also hold more than one value, e. g. <code>markup="emphasized, deleted"</code>.
41   * </p>
42   * <p>
43   * The value of the markup is unmodifiable.
44   * </p>
45   * <p>
46   * A markup must be registered for a component, before it can be used.
47   * </p>
48   * <p>
49   * A markup should only contain ASCII characters and digits.
50   * </p>
51   * <p>
52   * In JSPs the class {@link org.apache.myfaces.tobago.context.MarkupEditor} will convert the string literals.
53   * </p>
54   */
55  public final class Markup implements Serializable, Iterable<String> {
56  
57    public static final Markup NULL = new Markup((String) null);
58  
59    public static final Markup ASCENDING = valueOf("ascending");
60    public static final Markup BIG = valueOf("big");
61    public static final Markup BORDERED = valueOf("bordered");
62    public static final Markup CENTER = valueOf("center");
63    public static final Markup CLICKABLE = valueOf("clickable");
64    public static final Markup DANGER = valueOf("danger");
65    public static final Markup DARK = valueOf("dark");
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 EXTRA_LARGE = valueOf("extraLarge");
74    public static final Markup FILLER = valueOf("filler");
75    public static final Markup FATAL = valueOf("fatal");
76    /**
77     * @deprecated Can be selected via CSS3.
78     */
79    @Deprecated
80    public static final Markup FIRST = valueOf("first");
81    public static final Markup FOLDER = valueOf("folder");
82    public static final Markup HOVER = valueOf("hover");
83    public static final Markup INFO = valueOf("info");
84    public static final Markup INLINE = valueOf("inline");
85    public static final Markup JUSTIFY = valueOf("justify");
86    /**
87     * @deprecated since 4.0.0, please use {@link #DARK}
88     */
89    @Deprecated
90    public static final Markup INVERSE = valueOf("inverse");
91    public static final Markup LARGE = valueOf("large");
92    public static final Markup LEFT = valueOf("left");
93    public static final Markup LIGHT = valueOf("light");
94    public static final Markup LOCAL_MENU = valueOf("localMenu");
95    public static final Markup MARKED = valueOf("marked");
96    public static final Markup MEDIUM = valueOf("medium");
97    public static final Markup MODAL = valueOf("modal");
98    public static final Markup NONE = valueOf("none");
99    public static final Markup NUMBER = valueOf("number");
100   public static final Markup ODD = valueOf("odd");
101   public static final Markup PORTLET = valueOf("portlet");
102   public static final Markup PRIMARY = valueOf("primary");
103   public static final Markup READONLY = valueOf("readonly");
104   public static final Markup REQUIRED = valueOf("required");
105   public static final Markup RESIZABLE = valueOf("resizable");
106   public static final Markup RIGHT = valueOf("right");
107   public static final Markup SECONDARY = valueOf("secondary");
108   public static final Markup SECONDS = valueOf("seconds");
109   public static final Markup SELECTED = valueOf("selected");
110   /**
111    * @deprecated since 3.0.4
112    */
113   @Deprecated
114   public static final Markup SHEET_SELECT_ALL = valueOf("sheetSelectAll");
115   /**
116    * @deprecated since 3.0.4
117    */
118   @Deprecated
119   public static final Markup SHEET_DESELECT_ALL = valueOf("sheetDeselectAll");
120   /**
121    * @deprecated since 3.0.4
122    */
123   @Deprecated
124   public static final Markup SHEET_TOGGLE_ALL = valueOf("sheetToggleAll");
125   public static final Markup SMALL = valueOf("small");
126   public static final Markup SORTABLE = valueOf("sortable");
127   public static final Markup SPREAD = valueOf("spread");
128   public static final Markup STRIPED = valueOf("striped");
129   public static final Markup STRONG = valueOf("strong");
130   public static final Markup SUCCESS = valueOf("success");
131   public static final Markup TOGGLER_LEFT = valueOf("togglerLeft");
132   public static final Markup TOP = valueOf("top");
133   public static final Markup VERTICALLY = valueOf("vertically");
134   public static final Markup WARN = valueOf("warn");
135   public static final Markup WARNING = valueOf("warning");
136 
137   public static final String STRING_ASCENDING = "ascending";
138   public static final String STRING_BIG = "big";
139   public static final String STRING_BORDERED = "bordered";
140   public static final String STRING_CENTER = "center";
141   public static final String STRING_CLICKABLE = "clickable";
142   public static final String STRING_DANGER = "danger";
143   public static final String STRING_DARK = "dark";
144   public static final String STRING_DEFAULT = "default";
145   public static final String STRING_DELETED = "deleted";
146   public static final String STRING_DESCENDING = "descending";
147   public static final String STRING_DISABLED = "disabled";
148   public static final String STRING_ERROR = "error";
149   public static final String STRING_EVEN = "even";
150   public static final String STRING_EXPANDED = "expanded";
151   public static final String STRING_EXTRA_LARGE = "extraLarge";
152   public static final String STRING_FILLER = "filler";
153   public static final String STRING_FATAL = "fatal";
154   /**
155    * @deprecated Can be selected via CSS3.
156    */
157   @Deprecated
158   public static final String STRING_FIRST = "first";
159   public static final String STRING_FOLDER = "folder";
160   public static final String STRING_HOVER = "hover";
161   public static final String STRING_INFO = "info";
162   public static final String STRING_INLINE = "inline";
163   public static final String STRING_JUSTIFY = "justify";
164   /**
165    * @deprecated since 4.0.0, please use {@link #DARK}
166    */
167   @Deprecated
168   public static final String STRING_INVERSE = "inverse";
169   public static final String STRING_LARGE = "large";
170   public static final String STRING_LEFT = "left";
171   public static final String STRING_LIGHT = "light";
172   public static final String STRING_LOCAL_MENU = "localMenu";
173   public static final String STRING_MARKED = "marked";
174   public static final String STRING_MEDIUM = "medium";
175   public static final String STRING_MODAL = "modal";
176   public static final String STRING_NONE = "none";
177   public static final String STRING_NUMBER = "number";
178   public static final String STRING_ODD = "odd";
179   public static final String STRING_PORTLET = "portlet";
180   public static final String STRING_PRIMARY = "primary";
181   public static final String STRING_READONLY = "readonly";
182   public static final String STRING_REQUIRED = "required";
183   public static final String STRING_RESIZABLE = "resizable";
184   public static final String STRING_RIGHT = "right";
185   public static final String STRING_SECONDARY = "secondary";
186   public static final String STRING_SECONDS = "seconds";
187   public static final String STRING_SELECTED = "selected";
188   /**
189    * @deprecated since 3.0.4
190    */
191   @Deprecated
192   public static final String STRING_SHEET_SELECT_ALL = "sheetSelectAll";
193   /**
194    * @deprecated since 3.0.4
195    */
196   @Deprecated
197   public static final String STRING_SHEET_DESELECT_ALL = "sheetDeselectAll";
198   /**
199    * @deprecated since 3.0.4
200    */
201   @Deprecated
202   public static final String STRING_SHEET_TOGGLE_ALL = "sheetToggleAll";
203   public static final String STRING_SMALL = "small";
204   public static final String STRING_SORTABLE = "sortable";
205   public static final String STRING_SPREAD = "spread";
206   public static final String STRING_STRIPED = "striped";
207   public static final String STRING_STRONG = "strong";
208   public static final String STRING_SUCCESS = "success";
209   public static final String STRING_TOGGLER_LEFT = "togglerLeft";
210   public static final String STRING_TOP = "top";
211   public static final String STRING_VERTICALLY = "vertically";
212   public static final String STRING_WARN = "warn";
213   public static final String STRING_WARNING = "warning";
214 
215   /* Just one of "values" and "value" must be null */
216 
217   private final String[] values;
218   private final String value;
219 
220   private Markup(final String[] values) {
221     this.values = values;
222     this.value = null;
223   }
224 
225   private Markup(final String value) {
226     this.values = null;
227     this.value = value;
228   }
229 
230   public static Markup valueOf(final String[] values) {
231     if (values == null || values.length == 0) {
232       return null;
233     } else if (values.length == 1) {
234       return valueOf(values[0]);
235     } else {
236       final Markup markup = new Markup(values.clone());
237       for (int i = 0; i < markup.values.length; i++) {
238         markup.values[i] = markup.values[i].trim();
239       }
240       return markup;
241     }
242   }
243 
244   public static Markup valueOf(final String value) {
245     if (StringUtils.isEmpty(value)) {
246       return null;
247     }
248     if (value.contains(" ") || value.contains(",")) {
249       final String[] strings = StringUtils.split(value, ", \t\n");
250       return new Markup(strings);
251     } else {
252       return new Markup(value.trim());
253     }
254   }
255 
256   public static Markup valueOf(final Object value) {
257     if (value == null) {
258       return null;
259     }
260     if (value instanceof Markup) {
261       return (Markup) value;
262     }
263     if (value instanceof String) {
264       return valueOf((String) value);
265     }
266     if (value instanceof String[]) {
267       return valueOf((String[]) value);
268     }
269     if (value instanceof Iterable) {
270       final List<String> list = new ArrayList<>();
271       for (final Object object : (Iterable) value) {
272         list.add(object.toString());
273       }
274       return valueOf(list.toArray(new String[list.size()]));
275     }
276     return valueOf(value.toString());
277   }
278 
279   @Override
280   public boolean equals(final Object o) {
281     if (this == o) {
282       return true;
283     }
284     if (o == null || getClass() != o.getClass()) {
285       return false;
286     }
287 
288     final Markup markup = (Markup) o;
289 
290     if (value != null ? !value.equals(markup.value) : markup.value != null) {
291       return false;
292     }
293     if (!Arrays.equals(values, markup.values)) {
294       return false;
295     }
296 
297     return true;
298   }
299 
300   @Override
301   public int hashCode() {
302     int result = values != null ? Arrays.hashCode(values) : 0;
303     result = 31 * result + (value != null ? value.hashCode() : 0);
304     return result;
305   }
306 
307   @Override
308   public Iterator<String> iterator() {
309     if (value != null) {
310       return Collections.singleton(value).iterator();
311     }
312     if (values != null) {
313       return Arrays.asList(values).iterator();
314     }
315     return Collections.emptyIterator();
316   }
317 
318   /**
319    * Adds one markup to an other.
320    * Attention: The markup itself is not modified, you need to use the result of this operation.
321    */
322   public Markup add(final Markup markup) {
323     if (markup == null) {
324       return this;
325     }
326     if (markup == NULL) {
327       return this;
328     }
329     if (markup.value != null) {
330       return add(markup.value);
331     } else {
332       // this part is not optimized, but it will be used rarely, in the moment...
333       Markup result = this;
334       if (markup.values != null) {
335         for (final String summand : markup.values) {
336           final Markup combined = result.add(summand);
337           if (combined != null) {
338             result = combined;
339           }
340         }
341       }
342       return result;
343     }
344   }
345 
346   private Markup add(final String summand) {
347     if (summand == null) {
348       return this;
349     }
350     if (values == null) {
351       if (value == null) {
352         return valueOf(summand);
353       } else {
354         if (summand.equals(value)) {
355           return this;
356         } else {
357           return valueOf(new String[]{value, summand});
358         }
359       }
360     } else {
361       if (ArrayUtils.contains(values, summand)) {
362         return this;
363       } else {
364         final String[] strings = new String[values.length + 1];
365         System.arraycopy(values, 0, strings, 0, values.length);
366         strings[values.length] = summand;
367         return valueOf(strings);
368       }
369     }
370   }
371 
372   public Markup remove(final Markup markup) {
373     if (markup.value != null) {
374       return remove(markup.value);
375     } else {
376       // this part is not optimized, but it will be used rarely, in the moment...
377       Markup result = this;
378       for (final String summand : markup.values) {
379         final Markup removed = result.remove(summand);
380         if (removed == null) {
381           result = NULL;
382         } else {
383           result = removed;
384         }
385       }
386       return result;
387     }
388   }
389 
390   private Markup remove(final String summand) {
391     if (summand == null) {
392       return this;
393     }
394     if (values == null) {
395       if (value == null) {
396         return this;
397       } else {
398         if (summand.equals(value)) {
399           return NULL;
400         } else {
401           return this;
402         }
403       }
404     } else {
405       if (ArrayUtils.contains(values, summand)) {
406         final String[] strings = new String[values.length - 1];
407         int found = 0;
408         for (int i = 0; i < strings.length; i++) {
409           if (summand.equals(values[i])) {
410             found++;
411           }
412           strings[i] = values[i + found];
413         }
414         return valueOf(strings);
415       } else {
416         return this;
417       }
418     }
419   }
420 
421   public boolean contains(final String markup) {
422     if (markup == null) {
423       return true;
424     }
425     if (this == NULL) {
426       return this == Markup.valueOf(markup);
427     }
428     if (value != null) {
429       return value.equals(markup);
430     }
431     for (final String v : values) {
432       if (v.equals(markup)) {
433         return true;
434       }
435     }
436     return false;
437   }
438 
439   public boolean contains(final Markup markup) {
440     if (markup == null || markup == NULL) {
441       return true;
442     }
443     if (this == NULL) {
444       return this == markup;
445     }
446     if (markup.value != null) {
447       if (value != null) {
448         return value.equals(markup.value);
449       } else {
450         for (final String v : values) {
451           if (v.equals(markup.value)) {
452             return true;
453           }
454         }
455         return false;
456       }
457     } else {
458       if (value != null) {
459         return false;
460       } else {
461         for (final String markupString : markup.values) {
462           if (!contains(markupString)) {
463             return false;
464           }
465         }
466         return true;
467       }
468     }
469   }
470 
471   /**
472    * Check if there is no value set inside this markup.
473    */
474   public boolean isEmpty() {
475     return !(value != null || values != null && values.length != 0);
476   }
477 
478   @Override
479   public String toString() {
480     if (value != null) {
481       return value;
482     }
483     if (values == null) {
484       return "null";
485     }
486     return Arrays.toString(values);
487   }
488 
489 }