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