OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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

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