org.jopendocument.dom.style.data.DateStyle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jOpenDocument Show documentation
Show all versions of jOpenDocument Show documentation
jOpenDocument is a free library for developers looking to use
Open Document files without OpenOffice.org.
The newest version!
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2013 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
package org.jopendocument.dom.style.data;
import org.jopendocument.dom.ODPackage;
import org.jopendocument.dom.ODValueType;
import org.jopendocument.dom.StyleProperties;
import org.jopendocument.dom.XMLVersion;
import org.jopendocument.dom.spreadsheet.CellStyle;
import org.jopendocument.util.convertor.NumberConvertor;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.Namespace;
// from section 16.27.10 in v1.2-cs01-part1
public class DateStyle extends DataStyle {
// see http://download.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
private static final Calendar BUDDHIST_CAL = Calendar.getInstance(new Locale("th", "TH"));
private static final Calendar JAPANESE_CAL = Calendar.getInstance(new Locale("ja", "JP", "JP"));
private static final Calendar GREGORIAN_CAL = new GregorianCalendar();
static final DataStyleDesc DESC = new DataStyleDesc(DateStyle.class, XMLVersion.OD, "date-style", "N") {
@Override
public DateStyle create(ODPackage pkg, Element e) {
return new DateStyle(pkg, e);
}
};
static final boolean isShort(final Element elem) {
// in OOo the default is short
return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
}
public static final Locale getLocale(final Element elem) {
final Locale res;
final String country = elem.getAttributeValue("country", elem.getNamespace());
final String lang = elem.getAttributeValue("language", elem.getNamespace());
if (lang != null) {
res = new Locale(lang, country == null ? "" : country);
} else {
res = Locale.getDefault();
}
return res;
}
private static final Calendar getCalendar(final Element elem, Calendar defaultCal) {
final Calendar res;
final String cal = elem.getAttributeValue("calendar", elem.getNamespace());
if (cal == null) {
res = defaultCal;
} else if ("buddhist".equals(cal)) {
res = BUDDHIST_CAL;
} else if ("gengou".equals(cal)) {
res = JAPANESE_CAL;
} else if ("gregorian".equals(cal)) {
res = GREGORIAN_CAL;
} else {
throw new IllegalArgumentException("Unsupported calendar : " + cal);
}
return res;
}
static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) {
if (decPlaces > 0) {
final DecimalFormat decFormat = new DecimalFormat();
decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
decFormat.setMinimumIntegerDigits(0);
decFormat.setMaximumIntegerDigits(0);
decFormat.setMinimumFractionDigits(decPlaces);
decFormat.setMaximumFractionDigits(decPlaces);
// .12 or .578
return decFormat.format(seconds);
} else {
return "";
}
}
public DateStyle(final ODPackage pkg, Element elem) {
super(pkg, elem, ODValueType.DATE);
}
@Override
protected Object convertNonNull(Object o) {
if (o instanceof Number)
return getEpoch().getDate(NumberConvertor.toBigDecimal((Number) o));
else
return null;
}
private final void format(final StringBuilder res, final StringBuilder pattern, final Locale styleLocale, final Calendar currentCalendar, final Date d) {
if (pattern.length() > 0) {
final SimpleDateFormat fmt = new SimpleDateFormat(pattern.toString(), styleLocale);
pattern.setLength(0);
fmt.setCalendar((Calendar) currentCalendar.clone());
res.append(fmt.format(d));
}
}
@Override
public String format(Object o, CellStyle defaultStyle, boolean lenient) {
final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
final Namespace numberNS = this.getElement().getNamespace();
final Locale styleLocale = getLocale(getElement());
final Calendar styleCalendar = Calendar.getInstance(styleLocale);
final StringBuilder res = new StringBuilder();
Calendar currentCalendar = styleCalendar;
final StringBuilder sb = new StringBuilder();
@SuppressWarnings("unchecked")
final List children = this.getElement().getChildren();
for (final Element elem : children) {
if (elem.getNamespace().equals(numberNS)) {
final Calendar calendarLocaleElem = getCalendar(elem, styleCalendar);
if (!calendarLocaleElem.equals(currentCalendar)) {
format(res, sb, styleLocale, currentCalendar, d);
currentCalendar = calendarLocaleElem;
}
if (elem.getName().equals("text")) {
DataStyle.addStringLiteral(sb, elem.getText());
} else if (elem.getName().equals("era")) {
sb.append(isShort(elem) ? "G" : "GGGG");
} else if (elem.getName().equals("year")) {
sb.append(isShort(elem) ? "yy" : "yyyy");
} else if (elem.getName().equals("quarter")) {
final Calendar cal = (Calendar) currentCalendar.clone();
cal.setTime(d);
final double quarterLength = cal.getActualMaximum(Calendar.MONTH) / 4.0;
final int quarter = (int) (cal.get(Calendar.MONTH) / quarterLength + 1);
assert quarter >= 1 && quarter <= 4;
// TODO localize and honor short/long style
reportError("Quarters are not localized", lenient);
DataStyle.addStringLiteral(sb, isShort(elem) ? "Q" + quarter : "Q" + quarter);
} else if (elem.getName().equals("month")) {
final Attribute possessive = elem.getAttribute("possessive-form", numberNS);
if (possessive != null)
reportError("Ignoring " + possessive, lenient);
if (!StyleProperties.parseBoolean(elem.getAttributeValue("textual", numberNS), false))
sb.append(isShort(elem) ? "M" : "MM");
else
sb.append(isShort(elem) ? "MMM" : "MMMM");
} else if (elem.getName().equals("week-of-year")) {
sb.append("w");
} else if (elem.getName().equals("day")) {
sb.append(isShort(elem) ? "d" : "dd");
} else if (elem.getName().equals("day-of-week")) {
sb.append(isShort(elem) ? "E" : "EEEE");
} else if (elem.getName().equals("am-pm")) {
sb.append("a");
} else if (elem.getName().equals("hours")) {
// see 16.27.22 : If a element is contained in a date or time
// style, hours are displayed using values from 1 to 12 only.
if (getElement().getChild("am-pm", numberNS) == null)
sb.append(isShort(elem) ? "H" : "HH");
else
sb.append(isShort(elem) ? "h" : "hh");
} else if (elem.getName().equals("minutes")) {
sb.append(isShort(elem) ? "m" : "mm");
} else if (elem.getName().equals("seconds")) {
sb.append(isShort(elem) ? "s" : "ss");
final int decPlaces = StyleProperties.parseInt(elem.getAttributeValue("decimal-places", numberNS), 0);
if (decPlaces > 0) {
// use styleLocale since hasn't @calendar
final Calendar cal = Calendar.getInstance(styleLocale);
cal.setTime(d);
final BigDecimal secondFractions = new BigDecimal(cal.get(Calendar.MILLISECOND)).movePointLeft(3);
assert secondFractions.compareTo(BigDecimal.ONE) < 0;
final String fractionPart = formatSecondFraction(styleLocale, secondFractions, decPlaces);
DataStyle.addStringLiteral(sb, fractionPart);
}
}
}
}
format(res, sb, styleLocale, currentCalendar, d);
return res.toString();
}
}