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