OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 174 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 174 Rev 180
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
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
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
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.
9
 * language governing permissions and limitations under the License.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.openoffice.style.data;
14
 package org.openconcerto.openoffice.style.data;
15
 
15
 
16
import org.openconcerto.openoffice.ODPackage;
16
import org.openconcerto.openoffice.ODPackage;
17
import org.openconcerto.openoffice.ODValueType;
17
import org.openconcerto.openoffice.ODValueType;
18
import org.openconcerto.openoffice.StyleProperties;
18
import org.openconcerto.openoffice.StyleProperties;
19
import org.openconcerto.openoffice.XMLVersion;
19
import org.openconcerto.openoffice.XMLVersion;
20
import org.openconcerto.openoffice.spreadsheet.CellStyle;
20
import org.openconcerto.openoffice.spreadsheet.CellStyle;
21
import org.openconcerto.utils.convertor.NumberConvertor;
21
import org.openconcerto.utils.convertor.NumberConvertor;
22
 
22
 
23
import java.math.BigDecimal;
23
import java.math.BigDecimal;
24
import java.text.DecimalFormat;
24
import java.text.DecimalFormat;
25
import java.text.DecimalFormatSymbols;
25
import java.text.DecimalFormatSymbols;
26
import java.text.SimpleDateFormat;
26
import java.text.SimpleDateFormat;
27
import java.util.Calendar;
27
import java.util.Calendar;
28
import java.util.Date;
28
import java.util.Date;
29
import java.util.GregorianCalendar;
29
import java.util.GregorianCalendar;
30
import java.util.List;
30
import java.util.List;
31
import java.util.Locale;
31
import java.util.Locale;
32
 
32
 
33
import org.jdom.Attribute;
33
import org.jdom.Attribute;
34
import org.jdom.Element;
34
import org.jdom.Element;
35
import org.jdom.Namespace;
35
import org.jdom.Namespace;
36
 
36
 
37
// from section 16.27.10 in v1.2-cs01-part1
37
// from section 16.27.10 in v1.2-cs01-part1
38
public class DateStyle extends DataStyle {
38
public class DateStyle extends DataStyle {
39
 
39
 
40
    // see http://download.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
40
    // see http://download.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
41
    private static final Calendar BUDDHIST_CAL = Calendar.getInstance(new Locale("th", "TH"));
41
    private static final Calendar BUDDHIST_CAL = Calendar.getInstance(new Locale("th", "TH"));
42
    private static final Calendar JAPANESE_CAL = Calendar.getInstance(new Locale("ja", "JP", "JP"));
42
    private static final Calendar JAPANESE_CAL = Calendar.getInstance(new Locale("ja", "JP", "JP"));
43
    private static final Calendar GREGORIAN_CAL = new GregorianCalendar();
43
    private static final Calendar GREGORIAN_CAL = new GregorianCalendar();
44
 
44
 
45
    static final DataStyleDesc<DateStyle> DESC = new DataStyleDesc<DateStyle>(DateStyle.class, XMLVersion.OD, "date-style", "N") {
45
    static final DataStyleDesc<DateStyle> DESC = new DataStyleDesc<DateStyle>(DateStyle.class, XMLVersion.OD, "date-style", "N") {
46
        @Override
46
        @Override
47
        public DateStyle create(ODPackage pkg, Element e) {
47
        public DateStyle create(ODPackage pkg, Element e) {
48
            return new DateStyle(pkg, e);
48
            return new DateStyle(pkg, e);
49
        }
49
        }
50
    };
50
    };
51
 
51
 
52
    static final boolean isShort(final Element elem) {
52
    static final boolean isShort(final Element elem) {
53
        // in OOo the default is short
53
        // in OOo the default is short
54
        return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
54
        return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
55
    }
55
    }
56
 
56
 
57
    static final Locale getElementLocale(final Element elem) {
-
 
58
        final Locale res;
-
 
59
        final String country = elem.getAttributeValue("country", elem.getNamespace());
-
 
60
        final String lang = elem.getAttributeValue("language", elem.getNamespace());
-
 
61
        if (lang != null) {
-
 
62
            res = new Locale(lang, country == null ? "" : country);
-
 
63
        } else {
-
 
64
            res = null;
-
 
65
        }
-
 
66
        return res;
-
 
67
    }
-
 
68
 
-
 
69
    private static final Calendar getCalendar(final Element elem, Calendar defaultCal) {
57
    private static final Calendar getCalendar(final Element elem, Calendar defaultCal) {
70
        final Calendar res;
58
        final Calendar res;
71
        final String cal = elem.getAttributeValue("calendar", elem.getNamespace());
59
        final String cal = elem.getAttributeValue("calendar", elem.getNamespace());
72
        if (cal == null) {
60
        if (cal == null) {
73
            res = defaultCal;
61
            res = defaultCal;
74
        } else if ("buddhist".equals(cal)) {
62
        } else if ("buddhist".equals(cal)) {
75
            res = BUDDHIST_CAL;
63
            res = BUDDHIST_CAL;
76
        } else if ("gengou".equals(cal)) {
64
        } else if ("gengou".equals(cal)) {
77
            res = JAPANESE_CAL;
65
            res = JAPANESE_CAL;
78
        } else if ("gregorian".equals(cal)) {
66
        } else if ("gregorian".equals(cal)) {
79
            res = GREGORIAN_CAL;
67
            res = GREGORIAN_CAL;
80
        } else {
68
        } else {
81
            throw new IllegalArgumentException("Unsupported calendar : " + cal);
69
            throw new IllegalArgumentException("Unsupported calendar : " + cal);
82
        }
70
        }
83
        return res;
71
        return res;
84
    }
72
    }
85
 
73
 
86
    static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) {
74
    static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) {
87
        if (decPlaces > 0) {
75
        if (decPlaces > 0) {
88
            final DecimalFormat decFormat = new DecimalFormat();
76
            final DecimalFormat decFormat = new DecimalFormat();
89
            decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
77
            decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
90
            decFormat.setMinimumIntegerDigits(0);
78
            decFormat.setMinimumIntegerDigits(0);
91
            decFormat.setMaximumIntegerDigits(0);
79
            decFormat.setMaximumIntegerDigits(0);
92
            decFormat.setMinimumFractionDigits(decPlaces);
80
            decFormat.setMinimumFractionDigits(decPlaces);
93
            decFormat.setMaximumFractionDigits(decPlaces);
81
            decFormat.setMaximumFractionDigits(decPlaces);
94
            // .12 or .578
82
            // .12 or .578
95
            return decFormat.format(seconds);
83
            return decFormat.format(seconds);
96
        } else {
84
        } else {
97
            return "";
85
            return "";
98
        }
86
        }
99
    }
87
    }
100
 
88
 
101
    public DateStyle(final ODPackage pkg, Element elem) {
89
    public DateStyle(final ODPackage pkg, Element elem) {
102
        super(pkg, elem, ODValueType.DATE);
90
        super(pkg, elem, ODValueType.DATE);
103
    }
91
    }
104
 
92
 
105
    @Override
93
    @Override
106
    protected Object convertNonNull(Object o) {
94
    protected Object convertNonNull(Object o) {
107
        if (o instanceof Number)
95
        if (o instanceof Number)
108
            return getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o));
96
            return getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o));
109
        else
97
        else
110
            return null;
98
            return null;
111
    }
99
    }
112
 
100
 
113
    private final void format(final StringBuilder res, final StringBuilder pattern, final Locale styleLocale, final Calendar currentCalendar, final Date d) {
101
    private final void format(final StringBuilder res, final StringBuilder pattern, final Locale styleLocale, final Calendar currentCalendar, final Date d) {
114
        if (pattern.length() > 0) {
102
        if (pattern.length() > 0) {
115
            final SimpleDateFormat fmt = new SimpleDateFormat(pattern.toString(), styleLocale);
103
            final SimpleDateFormat fmt = new SimpleDateFormat(pattern.toString(), styleLocale);
116
            pattern.setLength(0);
104
            pattern.setLength(0);
117
            fmt.setCalendar((Calendar) currentCalendar.clone());
105
            fmt.setCalendar((Calendar) currentCalendar.clone());
118
            res.append(fmt.format(d));
106
            res.append(fmt.format(d));
119
        }
107
        }
120
    }
108
    }
121
 
109
 
122
    @Override
110
    @Override
123
    public String format(Object o, CellStyle defaultStyle, boolean lenient) {
111
    public String format(Object o, CellStyle defaultStyle, boolean lenient) {
124
        final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
112
        final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
125
        final Namespace numberNS = this.getElement().getNamespace();
113
        final Namespace numberNS = this.getElement().getNamespace();
126
        final Locale styleLocale = this.getLocale();
114
        final Locale styleLocale = this.getLocale();
127
        final Calendar styleCalendar = Calendar.getInstance(styleLocale);
115
        final Calendar styleCalendar = Calendar.getInstance(styleLocale);
128
        final StringBuilder res = new StringBuilder();
116
        final StringBuilder res = new StringBuilder();
129
 
117
 
130
        Calendar currentCalendar = styleCalendar;
118
        Calendar currentCalendar = styleCalendar;
131
        final StringBuilder sb = new StringBuilder();
119
        final StringBuilder sb = new StringBuilder();
132
 
120
 
133
        @SuppressWarnings("unchecked")
121
        @SuppressWarnings("unchecked")
134
        final List<Element> children = this.getElement().getChildren();
122
        final List<Element> children = this.getElement().getChildren();
135
        for (final Element elem : children) {
123
        for (final Element elem : children) {
136
            if (elem.getNamespace().equals(numberNS)) {
124
            if (elem.getNamespace().equals(numberNS)) {
137
                final Calendar calendarLocaleElem = getCalendar(elem, styleCalendar);
125
                final Calendar calendarLocaleElem = getCalendar(elem, styleCalendar);
138
                if (!calendarLocaleElem.equals(currentCalendar)) {
126
                if (!calendarLocaleElem.equals(currentCalendar)) {
139
                    format(res, sb, styleLocale, currentCalendar, d);
127
                    format(res, sb, styleLocale, currentCalendar, d);
140
                    currentCalendar = calendarLocaleElem;
128
                    currentCalendar = calendarLocaleElem;
141
                }
129
                }
142
 
130
 
143
                if (elem.getName().equals("text")) {
131
                if (elem.getName().equals("text")) {
144
                    DataStyle.addStringLiteral(sb, elem.getText());
132
                    DataStyle.addStringLiteral(sb, elem.getText());
145
                } else if (elem.getName().equals("era")) {
133
                } else if (elem.getName().equals("era")) {
146
                    sb.append(isShort(elem) ? "G" : "GGGG");
134
                    sb.append(isShort(elem) ? "G" : "GGGG");
147
                } else if (elem.getName().equals("year")) {
135
                } else if (elem.getName().equals("year")) {
148
                    sb.append(isShort(elem) ? "yy" : "yyyy");
136
                    sb.append(isShort(elem) ? "yy" : "yyyy");
149
                } else if (elem.getName().equals("quarter")) {
137
                } else if (elem.getName().equals("quarter")) {
150
                    final Calendar cal = (Calendar) currentCalendar.clone();
138
                    final Calendar cal = (Calendar) currentCalendar.clone();
151
                    cal.setTime(d);
139
                    cal.setTime(d);
152
                    final double quarterLength = cal.getActualMaximum(Calendar.MONTH) / 4.0;
140
                    final double quarterLength = cal.getActualMaximum(Calendar.MONTH) / 4.0;
153
                    final int quarter = (int) (cal.get(Calendar.MONTH) / quarterLength + 1);
141
                    final int quarter = (int) (cal.get(Calendar.MONTH) / quarterLength + 1);
154
                    assert quarter >= 1 && quarter <= 4;
142
                    assert quarter >= 1 && quarter <= 4;
155
                    // TODO localize and honor short/long style
143
                    // TODO localize and honor short/long style
156
                    reportError("Quarters are not localized", lenient);
144
                    reportError("Quarters are not localized", lenient);
157
                    DataStyle.addStringLiteral(sb, isShort(elem) ? "Q" + quarter : "Q" + quarter);
145
                    DataStyle.addStringLiteral(sb, isShort(elem) ? "Q" + quarter : "Q" + quarter);
158
                } else if (elem.getName().equals("month")) {
146
                } else if (elem.getName().equals("month")) {
159
                    final Attribute possessive = elem.getAttribute("possessive-form", numberNS);
147
                    final Attribute possessive = elem.getAttribute("possessive-form", numberNS);
160
                    if (possessive != null)
148
                    if (possessive != null)
161
                        reportError("Ignoring " + possessive, lenient);
149
                        reportError("Ignoring " + possessive, lenient);
162
                    if (!StyleProperties.parseBoolean(elem.getAttributeValue("textual", numberNS), false))
150
                    if (!StyleProperties.parseBoolean(elem.getAttributeValue("textual", numberNS), false))
163
                        sb.append(isShort(elem) ? "M" : "MM");
151
                        sb.append(isShort(elem) ? "M" : "MM");
164
                    else
152
                    else
165
                        sb.append(isShort(elem) ? "MMM" : "MMMM");
153
                        sb.append(isShort(elem) ? "MMM" : "MMMM");
166
                } else if (elem.getName().equals("week-of-year")) {
154
                } else if (elem.getName().equals("week-of-year")) {
167
                    sb.append("w");
155
                    sb.append("w");
168
                } else if (elem.getName().equals("day")) {
156
                } else if (elem.getName().equals("day")) {
169
                    sb.append(isShort(elem) ? "d" : "dd");
157
                    sb.append(isShort(elem) ? "d" : "dd");
170
                } else if (elem.getName().equals("day-of-week")) {
158
                } else if (elem.getName().equals("day-of-week")) {
171
                    sb.append(isShort(elem) ? "E" : "EEEE");
159
                    sb.append(isShort(elem) ? "E" : "EEEE");
172
                } else if (elem.getName().equals("am-pm")) {
160
                } else if (elem.getName().equals("am-pm")) {
173
                    sb.append("a");
161
                    sb.append("a");
174
                } else if (elem.getName().equals("hours")) {
162
                } else if (elem.getName().equals("hours")) {
175
                    // see 16.27.22 : If a <number:am-pm> element is contained in a date or time
163
                    // see 16.27.22 : If a <number:am-pm> element is contained in a date or time
176
                    // style, hours are displayed using values from 1 to 12 only.
164
                    // style, hours are displayed using values from 1 to 12 only.
177
                    if (getElement().getChild("am-pm", numberNS) == null)
165
                    if (getElement().getChild("am-pm", numberNS) == null)
178
                        sb.append(isShort(elem) ? "H" : "HH");
166
                        sb.append(isShort(elem) ? "H" : "HH");
179
                    else
167
                    else
180
                        sb.append(isShort(elem) ? "h" : "hh");
168
                        sb.append(isShort(elem) ? "h" : "hh");
181
                } else if (elem.getName().equals("minutes")) {
169
                } else if (elem.getName().equals("minutes")) {
182
                    sb.append(isShort(elem) ? "m" : "mm");
170
                    sb.append(isShort(elem) ? "m" : "mm");
183
                } else if (elem.getName().equals("seconds")) {
171
                } else if (elem.getName().equals("seconds")) {
184
                    sb.append(isShort(elem) ? "s" : "ss");
172
                    sb.append(isShort(elem) ? "s" : "ss");
185
                    final int decPlaces = StyleProperties.parseInt(elem.getAttributeValue("decimal-places", numberNS), 0);
173
                    final int decPlaces = StyleProperties.parseInt(elem.getAttributeValue("decimal-places", numberNS), 0);
186
                    if (decPlaces > 0) {
174
                    if (decPlaces > 0) {
187
                        // use styleLocale since <seconds> hasn't @calendar
175
                        // use styleLocale since <seconds> hasn't @calendar
188
                        final Calendar cal = Calendar.getInstance(styleLocale);
176
                        final Calendar cal = Calendar.getInstance(styleLocale);
189
                        cal.setTime(d);
177
                        cal.setTime(d);
190
                        final BigDecimal secondFractions = new BigDecimal(cal.get(Calendar.MILLISECOND)).movePointLeft(3);
178
                        final BigDecimal secondFractions = new BigDecimal(cal.get(Calendar.MILLISECOND)).movePointLeft(3);
191
                        assert secondFractions.compareTo(BigDecimal.ONE) < 0;
179
                        assert secondFractions.compareTo(BigDecimal.ONE) < 0;
192
                        final String fractionPart = formatSecondFraction(styleLocale, secondFractions, decPlaces);
180
                        final String fractionPart = formatSecondFraction(styleLocale, secondFractions, decPlaces);
193
                        DataStyle.addStringLiteral(sb, fractionPart);
181
                        DataStyle.addStringLiteral(sb, fractionPart);
194
                    }
182
                    }
195
                }
183
                }
196
            }
184
            }
197
        }
185
        }
198
        format(res, sb, styleLocale, currentCalendar, d);
186
        format(res, sb, styleLocale, currentCalendar, d);
199
        return res.toString();
187
        return res.toString();
200
    }
188
    }
201
}
189
}