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.layout;
21  
22  import org.apache.myfaces.tobago.internal.util.StringUtils;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  import java.io.Serializable;
27  
28  /**
29   * In PDLs the class {@link org.apache.myfaces.tobago.layout.MeasureEditor} will convert the string literals.
30   */
31  public final class Measure implements Serializable {
32  
33    private static final long serialVersionUID = 1L;
34  
35    private static final Logger LOG = LoggerFactory.getLogger(Measure.class);
36  
37    public static final Measure ZERO = valueOf(0);
38    public static final Measure AUTO = valueOf("auto");
39    public static final Measure FRACTION1 = valueOf("1fr");
40  
41    private final float value;
42    private final Unit unit;
43  
44    private Measure() {
45      this.value = 0;
46      this.unit = Unit.AUTO;
47    }
48  
49    public Measure(final int i, final Unit unit) {
50      this.value = i;
51      this.unit = unit;
52    }
53  
54    public Measure(final double d, final Unit unit) {
55      this.value = (float) d;
56      this.unit = unit;
57    }
58  
59    public Measure(final String string, final Unit unit) {
60      this.value = Float.parseFloat(string);
61      this.unit = unit;
62    }
63  
64    public static Measure valueOf(final Measure measure) {
65      if (measure == null) {
66        return ZERO;
67      }
68      return measure;
69    }
70  
71    public static Measure valueOf(final int value) {
72      return new Measure(value, Unit.PX);
73    }
74  
75    public static Measure valueOf(final Integer i) {
76      if (i == null) {
77        return ZERO;
78      }
79      return valueOf(i.intValue());
80    }
81  
82    public static Measure valueOf(final Number n) {
83      if (n == null) {
84        return ZERO;
85      }
86      return valueOf(n.doubleValue());
87    }
88  
89    public static Measure valueOf(final String s) {
90      return valueOf(s, Unit.PX);
91    }
92  
93    public static Measure valueOf(final String s, final Unit defaultUnit) {
94      try {
95        if (StringUtils.isEmpty(s)) {
96          return null;
97        }
98        final int length = s.length();
99        if (s.endsWith("%")) {
100         return new Measure(s.substring(0, length - 1), Unit.PERCENT);
101       }
102       if (s.endsWith("*")) {
103         if (s.length() == 1) {
104           return new Measure(1, Unit.FR);
105         } else {
106           return new Measure(s.substring(0, length - 1), Unit.FR);
107         }
108       }
109       if (s.equals("auto")) {
110         return new Measure();
111       }
112       for (int i = 4; i >= 2; i--) {
113         final int pos = length - i;
114         if (length >= i && Character.isLetter(s.charAt(pos))) {
115           return new Measure(s.substring(0, pos), Unit.valueOf(s.substring(pos).toUpperCase()));
116         }
117       }
118       return new Measure(s, defaultUnit);
119 
120     } catch (final RuntimeException e) {
121       LOG.warn("Can't parse to any measure: '" + s + "'");
122     }
123     return null;
124   }
125 
126   public static Measure valueOf(final Object object) {
127     if (object == null) {
128       return null;
129     }
130     if (object instanceof Measure) {
131       return valueOf((Measure) object);
132     }
133     if (object instanceof Number) {
134       return valueOf((Number) object);
135     }
136     if (object instanceof String) {
137       return valueOf((String) object);
138     }
139     return valueOf(object.toString());
140   }
141 
142   public String serialize() {
143     final StringBuilder builder = new StringBuilder();
144     if (unit != Unit.AUTO) {
145       builder.append(value);
146     }
147     final int length = builder.length();
148     if (length >= 3 && builder.charAt(length - 1) == '0' && builder.charAt(length - 2) == '.') {
149       builder.deleteCharAt(length - 1);
150       builder.deleteCharAt(length - 2);
151     }
152     builder.append(unit.getValue());
153     return builder.toString();
154   }
155 
156   public float getValue() {
157     return value;
158   }
159 
160   public Unit getUnit() {
161     return unit;
162   }
163 
164   public String toString() {
165     return serialize();
166   }
167 
168   @Override
169   public boolean equals(final Object o) {
170     if (this == o) {
171       return true;
172     }
173     if (o == null || getClass() != o.getClass()) {
174       return false;
175     }
176 
177     final Measure measure = (Measure) o;
178 
179     if (Float.compare(measure.value, value) != 0) {
180       return false;
181     }
182     return unit == measure.unit;
183   }
184 
185   @Override
186   public int hashCode() {
187     int result = value != +0.0f ? Float.floatToIntBits(value) : 0;
188     result = 31 * result + unit.hashCode();
189     return result;
190   }
191 
192   public enum Unit {
193 
194     EM,
195     PX,
196     EX,
197     PT,
198     CM,
199     MM,
200     IN,
201     PC,
202     CH, // Relative to width of the "0" (zero)
203     REM, // Relative to font-size of the root element
204     VW, // Relative to 1% of the width of the viewport*
205     VH, // Relative to 1% of the height of the viewport*
206     VMIN, // Relative to 1% of viewport's* smaller dimension
207     VMAX, // Relative to 1% of viewport's* larger dimension
208     PERCENT,
209     FR, // Fraction - same as * in classic Tobago
210     SEG, // Number of used columns in segment layout (Tobago specific)
211     AUTO; // Marker for CSS 'auto', not a regular measure
212 
213     private final String value;
214 
215     Unit() {
216       value = name().equals("PERCENT") ? "%" : name().toLowerCase();
217     }
218 
219     String getValue() {
220       return value;
221     }
222   }
223 }