OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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