OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 21 | Rev 73 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.openoffice;
15
 
16
import org.openconcerto.utils.DecimalUtils;
17
import org.openconcerto.utils.Tuple2;
18
 
19
import java.math.BigDecimal;
20
import java.math.RoundingMode;
21
import java.util.regex.Matcher;
22
import java.util.regex.Pattern;
23
 
24
/**
25
 * Units of length.
26
 *
27
 * @author Sylvain CUAZ
25 ilm 28
 * @see <a href="http://www.w3.org/TR/xsl/#d0e5752">W3C Definitions</a>
17 ilm 29
 */
30
public enum LengthUnit {
31
    /**
32
     * The millimetre.
33
     */
34
    MM("mm", BigDecimal.ONE),
35
    /**
36
     * The centimetre.
37
     */
38
    CM("cm", BigDecimal.TEN),
39
    /**
40
     * The inch.
41
     */
42
    INCH("in", new BigDecimal("25.4")),
43
    /**
44
     * The point (1/72in).
45
     */
46
    POINT("pt", INCH.multiplier.divide(new BigDecimal(72), DecimalUtils.HIGH_PRECISION)),
47
    /**
48
     * The pica (12pt i.e. 1/6in).
49
     */
50
    PICA("pc", INCH.multiplier.divide(new BigDecimal(6), DecimalUtils.HIGH_PRECISION));
51
 
52
    private final String symbol;
53
    private final BigDecimal multiplier;
54
 
55
    private LengthUnit(final String abbr, BigDecimal multiplier) {
56
        this.symbol = abbr;
57
        this.multiplier = multiplier;
58
    }
59
 
60
    /**
61
     * The symbol for this unit of length.
62
     *
63
     * @return the symbol, eg "cm".
64
     */
65
    public final String getSymbol() {
66
        return this.symbol;
67
    }
68
 
69
    /**
70
     * Convert from this unit to another.
71
     *
72
     * @param d a length, eg 1.
73
     * @param other another unit, eg {@link #CM}.
74
     * @return the {@link RoundingMode#HALF_UP rounded} result, eg 2.54 if this is {@link #INCH}
75
     */
76
    public final BigDecimal convertTo(final BigDecimal d, LengthUnit other) {
77
        if (this == other) {
78
            return d;
79
        } else {
80
            return d.multiply(this.multiplier).divide(other.multiplier, DecimalUtils.HIGH_PRECISION);
81
        }
82
    }
83
 
21 ilm 84
    public final String format(final BigDecimal d) {
85
        return d.toPlainString() + getSymbol();
86
    }
87
 
17 ilm 88
    public static final LengthUnit fromSymbol(final String s) {
89
        for (final LengthUnit lu : values())
90
            if (lu.symbol.equals(s))
91
                return lu;
92
        return null;
93
    }
94
 
95
    // match all lengths in relaxNG : length, nonNegativeLength and positiveLength ; eg 15.2cm
96
    // if you want to tell them apart do it in java on the BigDecimal.
97
    private static final Pattern lenghPattern = Pattern.compile("(-?\\d+(\\.\\d+)?)(\\p{Alpha}+)?");
98
 
99
    // 0: value, eg 15 ; 1: unit, eg "cm" or null
100
    private static final String[] parseLength2String(String l) {
101
        final Matcher m = lenghPattern.matcher(l);
102
        if (!m.matches())
103
            throw new IllegalStateException("unable to parse " + l);
104
        return new String[] { m.group(1), m.group(3) };
105
    }
106
 
107
    public static final Tuple2<BigDecimal, LengthUnit> parseLength(final String l) {
108
        if (l == null)
109
            return null;
110
        final String[] valAndUnit = parseLength2String(l);
111
        final LengthUnit unit = LengthUnit.fromSymbol(valAndUnit[1]);
112
        if (unit == null)
113
            throw new IllegalStateException("unknown unit " + unit);
114
        return Tuple2.create(new BigDecimal(valAndUnit[0]), unit);
115
    }
116
 
117
    /**
118
     * Parse a length.
119
     *
120
     * @param l the length, can be <code>null</code>, e.g. "2.0cm".
121
     * @param to the result unit, e.g. {@link LengthUnit#MM}.
122
     * @return the parsed length, <code>null</code> if <code>l</code> is, e.g. 20.
123
     */
124
    public static final BigDecimal parseLength(final String l, final LengthUnit to) {
125
        if (l == null)
126
            return null;
127
        final Tuple2<BigDecimal, LengthUnit> valAndUnit = LengthUnit.parseLength(l);
128
        return valAndUnit.get1().convertTo(valAndUnit.get0(), to);
129
    }
130
 
131
    public static final BigDecimal parsePositiveLength(final String l, final LengthUnit to, boolean strict) {
132
        final BigDecimal res = parseLength(l, to);
133
        if (res.compareTo(BigDecimal.ZERO) < 0)
134
            throw new IllegalArgumentException(res + " < 0");
135
        if (strict && res.compareTo(BigDecimal.ZERO) == 0)
136
            throw new IllegalArgumentException(res + " == 0");
137
        return res;
138
    }
139
}