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 | 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
 
25 ilm 57
    private static final Calendar getCalendar(final Element elem, Calendar defaultCal) {
58
        final Calendar res;
20 ilm 59
        final String cal = elem.getAttributeValue("calendar", elem.getNamespace());
60
        if (cal == null) {
25 ilm 61
            res = defaultCal;
20 ilm 62
        } else if ("buddhist".equals(cal)) {
25 ilm 63
            res = BUDDHIST_CAL;
20 ilm 64
        } else if ("gengou".equals(cal)) {
25 ilm 65
            res = JAPANESE_CAL;
20 ilm 66
        } else if ("gregorian".equals(cal)) {
25 ilm 67
            res = GREGORIAN_CAL;
20 ilm 68
        } else {
69
            throw new IllegalArgumentException("Unsupported calendar : " + cal);
70
        }
71
        return res;
72
    }
73
 
21 ilm 74
    static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) {
75
        if (decPlaces > 0) {
76
            final DecimalFormat decFormat = new DecimalFormat();
77
            decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
78
            decFormat.setMinimumIntegerDigits(0);
79
            decFormat.setMaximumIntegerDigits(0);
80
            decFormat.setMinimumFractionDigits(decPlaces);
81
            decFormat.setMaximumFractionDigits(decPlaces);
82
            // .12 or .578
83
            return decFormat.format(seconds);
84
        } else {
85
            return "";
86
        }
87
    }
88
 
20 ilm 89
    public DateStyle(final ODPackage pkg, Element elem) {
25 ilm 90
        super(pkg, elem, ODValueType.DATE);
20 ilm 91
    }
92
 
93
    @Override
25 ilm 94
    protected Object convertNonNull(Object o) {
95
        if (o instanceof Number)
96
            return getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o));
97
        else
98
            return null;
99
    }
100
 
101
    private final void format(final StringBuilder res, final StringBuilder pattern, final Locale styleLocale, final Calendar currentCalendar, final Date d) {
102
        if (pattern.length() > 0) {
103
            final SimpleDateFormat fmt = new SimpleDateFormat(pattern.toString(), styleLocale);
104
            pattern.setLength(0);
105
            fmt.setCalendar((Calendar) currentCalendar.clone());
106
            res.append(fmt.format(d));
107
        }
108
    }
109
 
110
    @Override
20 ilm 111
    public String format(Object o, CellStyle defaultStyle, boolean lenient) {
112
        final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
113
        final Namespace numberNS = this.getElement().getNamespace();
174 ilm 114
        final Locale styleLocale = this.getLocale();
25 ilm 115
        final Calendar styleCalendar = Calendar.getInstance(styleLocale);
20 ilm 116
        final StringBuilder res = new StringBuilder();
117
 
25 ilm 118
        Calendar currentCalendar = styleCalendar;
20 ilm 119
        final StringBuilder sb = new StringBuilder();
120
 
121
        @SuppressWarnings("unchecked")
122
        final List<Element> children = this.getElement().getChildren();
123
        for (final Element elem : children) {
124
            if (elem.getNamespace().equals(numberNS)) {
25 ilm 125
                final Calendar calendarLocaleElem = getCalendar(elem, styleCalendar);
126
                if (!calendarLocaleElem.equals(currentCalendar)) {
127
                    format(res, sb, styleLocale, currentCalendar, d);
128
                    currentCalendar = calendarLocaleElem;
20 ilm 129
                }
130
 
131
                if (elem.getName().equals("text")) {
132
                    DataStyle.addStringLiteral(sb, elem.getText());
133
                } else if (elem.getName().equals("era")) {
134
                    sb.append(isShort(elem) ? "G" : "GGGG");
135
                } else if (elem.getName().equals("year")) {
136
                    sb.append(isShort(elem) ? "yy" : "yyyy");
137
                } else if (elem.getName().equals("quarter")) {
25 ilm 138
                    final Calendar cal = (Calendar) currentCalendar.clone();
139
                    cal.setTime(d);
140
                    final double quarterLength = cal.getActualMaximum(Calendar.MONTH) / 4.0;
141
                    final int quarter = (int) (cal.get(Calendar.MONTH) / quarterLength + 1);
142
                    assert quarter >= 1 && quarter <= 4;
20 ilm 143
                    // TODO localize and honor short/long style
144
                    reportError("Quarters are not localized", lenient);
145
                    DataStyle.addStringLiteral(sb, isShort(elem) ? "Q" + quarter : "Q" + quarter);
146
                } else if (elem.getName().equals("month")) {
147
                    final Attribute possessive = elem.getAttribute("possessive-form", numberNS);
148
                    if (possessive != null)
149
                        reportError("Ignoring " + possessive, lenient);
150
                    if (!StyleProperties.parseBoolean(elem.getAttributeValue("textual", numberNS), false))
151
                        sb.append(isShort(elem) ? "M" : "MM");
152
                    else
153
                        sb.append(isShort(elem) ? "MMM" : "MMMM");
154
                } else if (elem.getName().equals("week-of-year")) {
155
                    sb.append("w");
156
                } else if (elem.getName().equals("day")) {
157
                    sb.append(isShort(elem) ? "d" : "dd");
158
                } else if (elem.getName().equals("day-of-week")) {
159
                    sb.append(isShort(elem) ? "E" : "EEEE");
160
                } else if (elem.getName().equals("am-pm")) {
161
                    sb.append("a");
162
                } else if (elem.getName().equals("hours")) {
163
                    // see 16.27.22 : If a <number:am-pm> element is contained in a date or time
164
                    // style, hours are displayed using values from 1 to 12 only.
165
                    if (getElement().getChild("am-pm", numberNS) == null)
166
                        sb.append(isShort(elem) ? "H" : "HH");
167
                    else
168
                        sb.append(isShort(elem) ? "h" : "hh");
169
                } else if (elem.getName().equals("minutes")) {
170
                    sb.append(isShort(elem) ? "m" : "mm");
171
                } else if (elem.getName().equals("seconds")) {
172
                    sb.append(isShort(elem) ? "s" : "ss");
173
                    final int decPlaces = StyleProperties.parseInt(elem.getAttributeValue("decimal-places", numberNS), 0);
174
                    if (decPlaces > 0) {
175
                        // use styleLocale since <seconds> hasn't @calendar
176
                        final Calendar cal = Calendar.getInstance(styleLocale);
177
                        cal.setTime(d);
178
                        final BigDecimal secondFractions = new BigDecimal(cal.get(Calendar.MILLISECOND)).movePointLeft(3);
179
                        assert secondFractions.compareTo(BigDecimal.ONE) < 0;
21 ilm 180
                        final String fractionPart = formatSecondFraction(styleLocale, secondFractions, decPlaces);
20 ilm 181
                        DataStyle.addStringLiteral(sb, fractionPart);
182
                    }
183
                }
184
            }
185
        }
25 ilm 186
        format(res, sb, styleLocale, currentCalendar, d);
187
        return res.toString();
20 ilm 188
    }
189
}