001 package org.apache.myfaces.tobago.context;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.collections.iterators.EmptyIterator;
021 import org.apache.commons.collections.iterators.ObjectArrayIterator;
022 import org.apache.commons.collections.iterators.SingletonIterator;
023 import org.apache.commons.lang.ArrayUtils;
024 import org.apache.commons.lang.StringUtils;
025
026 import java.io.Serializable;
027 import java.util.ArrayList;
028 import java.util.Arrays;
029 import java.util.Iterator;
030 import java.util.List;
031
032 /**
033 * A markup signs a component to be rendered different from the normal.
034 * E. g. <code>markup="emphasized"</code> might be rendered bold
035 * or a <code>markup="deleted"</code> might be rendered with line-through style.
036 * The concrete rendering depends from the theme.
037 * <p/>
038 * The markup can also hold more than one value, e. g. <code>markup="emphasized, deleted"</code>.
039 * <p/>
040 * The value of the markup is unmodifiable.
041 * <p/>
042 * A markup must be registered for a component, before it can be used.
043 * <p/>
044 * A markup should only contain ASCII characters and digits.
045 */
046 public final class Markup implements Serializable, Iterable<String> {
047
048 public static final Markup NULL = new Markup((String) null);
049
050 public static final Markup ASCENDING = valueOf("ascending");
051 public static final Markup CENTER = valueOf("center");
052 public static final Markup CLICKABLE = valueOf("clickable");
053 public static final Markup DESCENDING = valueOf("descending");
054 public static final Markup DELETED = valueOf("deleted");
055 public static final Markup DISABLED = valueOf("disabled");
056 public static final Markup ERROR = valueOf("error");
057 public static final Markup EVEN = valueOf("even");
058 public static final Markup FATAL = valueOf("fatal");
059 public static final Markup FIRST = valueOf("first");
060 public static final Markup FOLDER = valueOf("folder");
061 public static final Markup INFO = valueOf("info");
062 public static final Markup LEFT = valueOf("left");
063 public static final Markup MARKED = valueOf("marked");
064 public static final Markup MODAL = valueOf("modal");
065 public static final Markup NUMBER = valueOf("number");
066 public static final Markup ODD = valueOf("odd");
067 public static final Markup PURE = valueOf("pure");
068 public static final Markup READONLY = valueOf("readonly");
069 public static final Markup REQUIRED = valueOf("required");
070 public static final Markup RESIZABLE = valueOf("resizable");
071 public static final Markup RIGHT = valueOf("right");
072 public static final Markup SELECTED = valueOf("selected");
073 public static final Markup SORTABLE = valueOf("sortable");
074 public static final Markup STRONG = valueOf("strong");
075 public static final Markup TOP = valueOf("top");
076 public static final Markup WARN = valueOf("warn");
077
078 /* Just one of "values" and "value" must be null */
079
080 private final String[] values;
081 private final String value;
082
083 private Markup(String[] values) {
084 this.values = values;
085 this.value = null;
086 }
087
088 private Markup(String value) {
089 this.values = null;
090 this.value = value;
091 }
092
093 public static Markup valueOf(String[] values) {
094 if (values == null || values.length == 0) {
095 return null;
096 } else if (values.length == 1) {
097 return valueOf(values[0]);
098 } else {
099 Markup markup = new Markup((String[]) ArrayUtils.clone(values));
100 for (int i = 0; i < markup.values.length; i++) {
101 markup.values[i] = markup.values[i].trim();
102 }
103 return markup;
104 }
105 }
106
107 public static Markup valueOf(String value) {
108 if (StringUtils.isEmpty(value)) {
109 return null;
110 }
111 if (value.contains(",")) {
112 String[] strings = StringUtils.split(value, ", \t\n");
113 return new Markup(strings);
114 } else {
115 return new Markup(value.trim());
116 }
117 }
118
119 public static Markup valueOf(Object value) {
120 if (value == null) {
121 return null;
122 }
123 if (value instanceof Markup) {
124 return (Markup) value;
125 }
126 if (value instanceof String) {
127 return valueOf((String) value);
128 }
129 if (value instanceof String[]) {
130 return valueOf((String[]) value);
131 }
132 if (value instanceof Iterable) {
133 List<String> list = new ArrayList<String>();
134 for (Object object : (Iterable) value) {
135 list.add(object.toString());
136 }
137 return valueOf(list.toArray(new String[list.size()]));
138 }
139 return valueOf(value.toString());
140 }
141
142 @Override
143 public boolean equals(Object o) {
144 if (this == o) {
145 return true;
146 }
147 if (o == null || getClass() != o.getClass()) {
148 return false;
149 }
150
151 Markup markup = (Markup) o;
152
153 if (value != null ? !value.equals(markup.value) : markup.value != null) {
154 return false;
155 }
156 if (!Arrays.equals(values, markup.values)) {
157 return false;
158 }
159
160 return true;
161 }
162
163 @Override
164 public int hashCode() {
165 int result = values != null ? Arrays.hashCode(values) : 0;
166 result = 31 * result + (value != null ? value.hashCode() : 0);
167 return result;
168 }
169
170 public Iterator<String> iterator() {
171 if (value != null) {
172 return new SingletonIterator(value);
173 }
174 if (values != null) {
175 return new ObjectArrayIterator(values);
176 }
177 return EmptyIterator.INSTANCE;
178 }
179
180 public Markup add(Markup markup) {
181 if (markup == null) {
182 return this;
183 }
184 if (markup == NULL) {
185 return this;
186 }
187 if (markup.value != null) {
188 return add(markup.value);
189 } else {
190 // this part is not optimized, but it will be used rarely, in the moment...
191 Markup result = this;
192 for (String summand : markup.values) {
193 result = result.add(summand);
194 }
195 return result;
196 }
197 }
198
199 private Markup add(String summand) {
200 if (summand == null) {
201 return this;
202 }
203 if (values == null) {
204 if (value == null) {
205 return valueOf(summand);
206 } else {
207 if (summand.equals(value)) {
208 return this;
209 } else {
210 return valueOf(new String[]{value, summand});
211 }
212 }
213 } else {
214 if (ArrayUtils.contains(values, summand)) {
215 return this;
216 } else {
217 final String[] strings = new String[values.length + 1];
218 System.arraycopy(values, 0, strings, 0, values.length);
219 strings[values.length] = summand;
220 return valueOf(strings);
221 }
222 }
223 }
224
225 public Markup remove(Markup markup) {
226 if (markup.value != null) {
227 return remove(markup.value);
228 } else {
229 // this part is not optimized, but it will be used rarely, in the moment...
230 Markup result = this;
231 for (String summand : markup.values) {
232 result = result.remove(summand);
233 }
234 return result;
235 }
236 }
237
238 private Markup remove(String summand) {
239 if (summand == null) {
240 return this;
241 }
242 if (values == null) {
243 if (value == null) {
244 return this;
245 } else {
246 if (summand.equals(value)) {
247 return NULL;
248 } else {
249 return this;
250 }
251 }
252 } else {
253 if (ArrayUtils.contains(values, summand)) {
254 final String[] strings = new String[values.length - 1];
255 int found = 0;
256 for (int i = 0; i < strings.length; i++) {
257 if (values[i].equals(summand)) {
258 found++;
259 }
260 strings[i] = values[i + found];
261 }
262 return valueOf(strings);
263 } else {
264 return this;
265 }
266 }
267 }
268
269 public boolean contains(String markup) {
270 if (markup == null) {
271 return false;
272 }
273 if (this == NULL) {
274 return this == Markup.valueOf(markup);
275 }
276 if (value != null) {
277 return value.equals(markup);
278 }
279 for (String value : values) {
280 if (value.equals(markup)) {
281 return true;
282 }
283 }
284 return false;
285 }
286
287 @Override
288 public String toString() {
289 if (value != null) {
290 return value;
291 }
292 if (values == null) {
293 return "null";
294 }
295 return Arrays.toString(values);
296 }
297 }