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 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 174 Rev 180
Line 15... Line 15...
15
 
15
 
16
import org.openconcerto.openoffice.Log;
16
import org.openconcerto.openoffice.Log;
17
import org.openconcerto.openoffice.ODEpoch;
17
import org.openconcerto.openoffice.ODEpoch;
18
import org.openconcerto.openoffice.ODPackage;
18
import org.openconcerto.openoffice.ODPackage;
19
import org.openconcerto.openoffice.ODValueType;
19
import org.openconcerto.openoffice.ODValueType;
-
 
20
import org.openconcerto.openoffice.OOUtils;
20
import org.openconcerto.openoffice.Style;
21
import org.openconcerto.openoffice.Style;
21
import org.openconcerto.openoffice.StyleDesc;
22
import org.openconcerto.openoffice.StyleDesc;
22
import org.openconcerto.openoffice.StyleProperties;
23
import org.openconcerto.openoffice.StyleProperties;
23
import org.openconcerto.openoffice.XMLVersion;
24
import org.openconcerto.openoffice.XMLVersion;
24
import org.openconcerto.openoffice.spreadsheet.CellStyle;
25
import org.openconcerto.openoffice.spreadsheet.CellStyle;
Line 49... Line 50...
49
    private static final int DEFAULT_GROUPING_SIZE = new DecimalFormat().getGroupingSize();
50
    private static final int DEFAULT_GROUPING_SIZE = new DecimalFormat().getGroupingSize();
50
    // 15 as of LibreOffice 6, was 10 earlier
51
    // 15 as of LibreOffice 6, was 10 earlier
51
    /**
52
    /**
52
     * The default number of decimal digits if neither defined in the style nor in default-style.
53
     * The default number of decimal digits if neither defined in the style nor in default-style.
53
     */
54
     */
54
    public static final int DEFAULT_DECIMAL_PLACES = Integer.parseInt(System.getProperty("openDocument.defaultDecimalPlaces", "15"));
55
    public static final int DEFAULT_DECIMAL_PLACES;
55
    private static final Pattern QUOTE_PATRN = Pattern.compile("'", Pattern.LITERAL);
56
    private static final Pattern QUOTE_PATRN = Pattern.compile("'", Pattern.LITERAL);
56
    private static final Pattern EXP_PATTERN = Pattern.compile("E(\\d+)$");
57
    private static final Pattern EXP_PATTERN = Pattern.compile("E(\\d+)$");
57
 
58
 
58
    public static int getDecimalPlaces(final CellStyle defaultStyle) {
59
    public static int getDecimalPlaces(final CellStyle defaultStyle) {
59
        if (defaultStyle != null) {
60
        if (defaultStyle != null) {
60
            return defaultStyle.getTableCellProperties(null).getDecimalPlaces();
61
            final int res = defaultStyle.getTableCellProperties(null).getDecimalPlaces();
-
 
62
            // Ignore invalid value
-
 
63
            return res < 0 ? DEFAULT_DECIMAL_PLACES : res;
61
        } else {
64
        } else {
62
            return DEFAULT_DECIMAL_PLACES;
65
            return DEFAULT_DECIMAL_PLACES;
63
        }
66
        }
64
    }
67
    }
65
 
68
 
-
 
69
    protected static final int parsePositive(final String attr, final boolean lenient) {
-
 
70
        final int res = Integer.parseInt(attr);
-
 
71
        if (res < 0) {
-
 
72
            reportError("Negative value for " + attr, lenient);
-
 
73
            return 0;
-
 
74
        }
-
 
75
        return res;
-
 
76
    }
-
 
77
 
66
    public static void addStringLiteral(final StringBuilder formatSB, final String s) {
78
    public static void addStringLiteral(final StringBuilder formatSB, final String s) {
67
        formatSB.append('\'');
79
        formatSB.append('\'');
68
        formatSB.append(QUOTE_PATRN.matcher(s).replaceAll("''"));
80
        formatSB.append(QUOTE_PATRN.matcher(s).replaceAll("''"));
69
        formatSB.append('\'');
81
        formatSB.append('\'');
70
    }
82
    }
Line 81... Line 93...
81
        l.add(DateStyle.class);
93
        l.add(DateStyle.class);
82
        l.add(TimeStyle.class);
94
        l.add(TimeStyle.class);
83
        l.add(BooleanStyle.class);
95
        l.add(BooleanStyle.class);
84
        DATA_STYLES = Collections.unmodifiableSet(l);
96
        DATA_STYLES = Collections.unmodifiableSet(l);
85
        assert DATA_STYLES_DESCS.length == DATA_STYLES.size() : "Discrepancy between classes and descs";
97
        assert DATA_STYLES_DESCS.length == DATA_STYLES.size() : "Discrepancy between classes and descs";
-
 
98
 
-
 
99
        final String decPlacesProp = System.getProperty("openDocument.defaultDecimalPlaces");
-
 
100
        final int decPlacesParsed = decPlacesProp == null ? -1 : Integer.parseInt(decPlacesProp);
-
 
101
        // Ignore invalid value
-
 
102
        DEFAULT_DECIMAL_PLACES = decPlacesParsed < 0 ? 15 : decPlacesParsed;
-
 
103
        assert DEFAULT_DECIMAL_PLACES >= 0;
86
    }
104
    }
87
 
105
 
88
    public static abstract class DataStyleDesc<S extends DataStyle> extends StyleDesc<S> {
106
    public static abstract class DataStyleDesc<S extends DataStyle> extends StyleDesc<S> {
89
 
107
 
90
        protected DataStyleDesc(Class<S> clazz, XMLVersion version, String elemName, String baseName) {
108
        protected DataStyleDesc(Class<S> clazz, XMLVersion version, String elemName, String baseName) {
Line 180... Line 198...
180
        else
198
        else
181
            throw new UnsupportedOperationException(msg);
199
            throw new UnsupportedOperationException(msg);
182
    }
200
    }
183
 
201
 
184
    public final Locale getLocale() {
202
    public final Locale getLocale() {
185
        return this.getLocale(this.getElement());
203
        return this.getLocale(false);
186
    }
204
    }
187
 
205
 
188
    protected final Locale getLocale(final Element elem) {
206
    public final Locale getLocale(final boolean local) {
189
        final Locale res = DateStyle.getElementLocale(elem);
-
 
190
        return res != null ? res : this.getPackage().getLocale();
207
        return this.getLocale(this.getElement(), local);
191
    }
208
    }
192
 
209
 
193
    protected final String formatNumberOrScientificNumber(final Element elem, final Number n, CellStyle defaultStyle) {
210
    protected final Locale getLocale(final Element elem, final boolean local) {
-
 
211
        final Locale res = OOUtils.getElementLocale(elem);
194
        return this.formatNumberOrScientificNumber(elem, n, 1, defaultStyle);
212
        return local || res != null ? res : this.getPackage().getLocale();
195
    }
213
    }
196
 
214
 
-
 
215
    public final void setLocale(final Locale l) {
-
 
216
        OOUtils.setElementLocale(this.getElement(), this.getElement().getNamespace(), l);
-
 
217
    }
-
 
218
 
-
 
219
    @SuppressWarnings("unchecked")
-
 
220
    public final List<Element> getMapChildren() {
-
 
221
        return this.getElement().getChildren("map", getSTYLE());
-
 
222
    }
-
 
223
 
-
 
224
    protected final String formatNumberOrScientificNumber(final Element elem, final Number n, CellStyle defaultStyle, final boolean lenient) {
-
 
225
        return this.formatNumberOrScientificNumber(elem, n, 1, defaultStyle, lenient);
-
 
226
    }
-
 
227
 
197
    protected final String formatNumberOrScientificNumber(final Element elem, final Number n, final int multiplier, CellStyle defaultStyle) {
228
    protected final String formatNumberOrScientificNumber(final Element elem, final Number n, final int multiplier, CellStyle defaultStyle, final boolean lenient) {
198
        final Namespace numberNS = this.getElement().getNamespace();
229
        final Namespace numberNS = this.getElement().getNamespace();
199
        final StringBuilder numberSB = new StringBuilder();
230
        final StringBuilder numberSB = new StringBuilder();
200
 
231
 
201
        final List<?> embeddedTexts = elem.getChildren("embedded-text", numberNS);
232
        final List<?> embeddedTexts = elem.getChildren("embedded-text", numberNS);
202
        final SortedMap<Integer, String> embeddedTextByPosition = new TreeMap<Integer, String>(Collections.reverseOrder());
233
        final SortedMap<Integer, String> embeddedTextByPosition = new TreeMap<Integer, String>(Collections.reverseOrder());
Line 219... Line 250...
219
            for (int i = 0; i < minIntDig; i++)
250
            for (int i = 0; i < minIntDig; i++)
220
                numberSB.append('0');
251
                numberSB.append('0');
221
        }
252
        }
222
 
253
 
223
        // e.g. if it's "--", 12,3 is displayed "12,3" and 12 is displayed "12,--"
254
        // e.g. if it's "--", 12,3 is displayed "12,3" and 12 is displayed "12,--"
-
 
255
        // From v1.3 §19.356.2 decimal-replacement can be empty
224
        final String decReplacement = elem.getAttributeValue("decimal-replacement", numberNS);
256
        final String decReplacement = elem.getAttributeValue("decimal-replacement", numberNS, "");
225
        final boolean decSeparatorAlwaysShown;
257
        final boolean decSeparatorAlwaysShown;
226
        if (decReplacement != null && !NumberUtils.hasFractionalPart(n)) {
258
        if (!decReplacement.isEmpty() && !NumberUtils.hasFractionalPart(n)) {
227
            decSeparatorAlwaysShown = true;
259
            decSeparatorAlwaysShown = true;
228
            numberSB.append('.');
260
            numberSB.append('.');
229
            // escape quote in replacement
261
            // escape quote in replacement
230
            addStringLiteral(numberSB, decReplacement);
262
            addStringLiteral(numberSB, decReplacement);
231
        } else {
263
        } else {
232
            decSeparatorAlwaysShown = false;
264
            decSeparatorAlwaysShown = false;
233
            // see 19.343.2
265
            // see 19.343.2
234
            final Attribute decPlacesAttr = elem.getAttribute("decimal-places", numberNS);
266
            final String decPlacesAttr = elem.getAttributeValue("decimal-places", numberNS, "");
-
 
267
            final String minDecPlacesAttr = elem.getAttributeValue("min-decimal-places", numberNS, "");
235
            final int decPlaces;
268
            final int forcedPlaces, nonZeroPlaces;
236
            final char decChar;
269
            if (!decPlacesAttr.isEmpty()) {
-
 
270
                final int decPlaces = parsePositive(decPlacesAttr, lenient);
237
            if (decPlacesAttr != null) {
271
                if (minDecPlacesAttr.isEmpty()) {
-
 
272
                    forcedPlaces = decPlaces;
-
 
273
                    nonZeroPlaces = 0;
238
                decChar = '0';
274
                } else {
239
                decPlaces = Integer.parseInt(decPlacesAttr.getValue());
275
                    forcedPlaces = parsePositive(minDecPlacesAttr, lenient);
-
 
276
                    if (forcedPlaces > decPlaces) {
-
 
277
                        DataStyle.reportError("min-decimal-places greater than decimal-places : " + minDecPlacesAttr + " > " + decPlacesAttr, lenient);
-
 
278
                        nonZeroPlaces = 0;
-
 
279
                    } else {
-
 
280
                        nonZeroPlaces = decPlaces - forcedPlaces;
-
 
281
                    }
-
 
282
                }
240
            } else {
283
            } else {
241
                // default style specifies the maximum
284
                // default style specifies the maximum
242
                decChar = '#';
285
                forcedPlaces = 0;
243
                decPlaces = getDecimalPlaces(defaultStyle);
286
                nonZeroPlaces = getDecimalPlaces(defaultStyle);
244
            }
287
            }
245
 
288
 
246
            if (decPlaces > 0) {
289
            if (forcedPlaces + nonZeroPlaces > 0) {
247
                numberSB.append('.');
290
                numberSB.append('.');
248
                for (int i = 0; i < decPlaces; i++)
291
                for (int i = 0; i < forcedPlaces; i++)
-
 
292
                    numberSB.append('0');
-
 
293
                for (int i = 0; i < nonZeroPlaces; i++)
249
                    numberSB.append(decChar);
294
                    numberSB.append('#');
250
            }
295
            }
251
        }
296
        }
252
 
297
 
253
        final Attribute minExpAttr = elem.getAttribute("min-exponent-digits", numberNS);
298
        final Attribute minExpAttr = elem.getAttribute("min-exponent-digits", numberNS);
-
 
299
        final boolean forcedExpSign;
254
        if (minExpAttr != null) {
300
        if (minExpAttr != null) {
-
 
301
            forcedExpSign = Boolean.parseBoolean(elem.getAttributeValue("forced-exponent-sign", numberNS, "true"));
255
            numberSB.append('E');
302
            numberSB.append('E');
256
            for (int i = 0; i < Integer.parseInt(minExpAttr.getValue()); i++)
303
            for (int i = 0; i < Integer.parseInt(minExpAttr.getValue()); i++)
257
                numberSB.append('0');
304
                numberSB.append('0');
-
 
305
        } else {
-
 
306
            forcedExpSign = false;
258
        }
307
        }
259
 
308
 
260
        final DecimalFormatSymbols symbols = new DecimalFormatSymbols(this.getLocale());
309
        final DecimalFormatSymbols symbols = new DecimalFormatSymbols(this.getLocale());
261
 
310
 
262
        final DecimalFormat decFormat = new DecimalFormat(numberSB.toString(), symbols);
311
        final DecimalFormat decFormat = new DecimalFormat(numberSB.toString(), symbols);
Line 265... Line 314...
265
        decFormat.setGroupingUsed(grouping);
314
        decFormat.setGroupingUsed(grouping);
266
        // needed since the default size is overwritten by the pattern
315
        // needed since the default size is overwritten by the pattern
267
        decFormat.setGroupingSize(DEFAULT_GROUPING_SIZE);
316
        decFormat.setGroupingSize(DEFAULT_GROUPING_SIZE);
268
        decFormat.setDecimalSeparatorAlwaysShown(decSeparatorAlwaysShown);
317
        decFormat.setDecimalSeparatorAlwaysShown(decSeparatorAlwaysShown);
269
        String res = decFormat.format(NumberUtils.divide(n, factor));
318
        String res = decFormat.format(NumberUtils.divide(n, factor));
270
        // java only puts the minus sign, OO also puts the plus sign
319
        // There's no way to force the plus sign in DecimalFormat
271
        if (minExpAttr != null) {
320
        if (forcedExpSign) {
272
            final Matcher m = EXP_PATTERN.matcher(res);
321
            final Matcher m = EXP_PATTERN.matcher(res);
273
            if (m.find())
322
            if (m.find())
274
                res = res.substring(0, m.start()) + "E+" + m.group(1);
323
                res = res.substring(0, m.start()) + "E+" + m.group(1);
275
        }
324
        }
276
        if (embeddedTextByPosition.size() > 0) {
325
        if (embeddedTextByPosition.size() > 0) {