/* * ----------------------------------------------------------------------- * Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (StyleProcessor.java) is part of project Time4J. * * Time4J is free software: You can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Time4J is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Time4J. If not, see <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.format.expert; import net.time4j.Moment; import net.time4j.PlainDate; import net.time4j.PlainTime; import net.time4j.PlainTimestamp; import net.time4j.engine.AttributeQuery; import net.time4j.engine.ChronoDisplay; import net.time4j.engine.ChronoElement; import net.time4j.engine.Chronology; import net.time4j.engine.DisplayStyle; import net.time4j.format.Attributes; import net.time4j.format.CalendarText; import net.time4j.format.DisplayMode; import net.time4j.format.LocalizedPatternSupport; import net.time4j.tz.TZID; import net.time4j.tz.Timezone; import net.time4j.tz.TransitionStrategy; import java.io.IOException; import java.util.Locale; import java.util.Set; /** * <p>Stil-Formatierung einer chronologischen Entität. </p> * * @param <T> generic type of entity values * @author Meno Hochschild * @since 3.26/4.22 */ final class StyleProcessor<T> implements FormatProcessor<T> { //~ Instanzvariablen ---------------------------------------------- private final ChronoFormatter<T> formatter; private final DisplayStyle dateStyle; private final DisplayStyle timeStyle; //~ Konstruktoren ----------------------------------------------------- StyleProcessor( DisplayStyle dateStyle, DisplayStyle timeStyle ) { this( null, // will be later set in quickPath()-method dateStyle, timeStyle ); } private StyleProcessor( ChronoFormatter<T> formatter, DisplayStyle dateStyle, DisplayStyle timeStyle ) { super(); if ((dateStyle == null) || (timeStyle == null)) { throw new NullPointerException("Missing display style."); } this.dateStyle = dateStyle; this.timeStyle = timeStyle; this.formatter = formatter; } //~ Methoden ---------------------------------------------------------- @Override public void print( ChronoDisplay formattable, Appendable buffer, AttributeQuery attributes, Set<ElementPosition> positions, // optional boolean quickPath ) throws IOException { Set<ElementPosition> newPositions = this.formatter.print(formattable, buffer, attributes, positions != null); if (positions != null) { positions.addAll(newPositions); } } @Override public void parse( CharSequence text, ParseLog status, AttributeQuery attributes, ParsedEntity<?> parsedResult, boolean quickPath ) { ChronoFormatter<T> cf; if (quickPath) { cf = this.formatter; } else { AttributeQuery internal = this.formatter.getAttributes(); TransitionStrategy strategy = attributes.get( Attributes.TRANSITION_STRATEGY, internal.get(Attributes.TRANSITION_STRATEGY, Timezone.DEFAULT_CONFLICT_STRATEGY)); TZID tzid = attributes.get( Attributes.TIMEZONE_ID, internal.get(Attributes.TIMEZONE_ID, null)); Timezone tz = ((tzid == null) ? null : Timezone.of(tzid).with(strategy)); cf = createFormatter( this.formatter.getChronology(), this.dateStyle, this.timeStyle, attributes.get(Attributes.LANGUAGE, this.formatter.getLocale()), attributes.get(Attributes.FOUR_DIGIT_YEAR, Boolean.FALSE).booleanValue(), tz); } T result = cf.parse(text, status, attributes); if (!status.isError() && (result != null)) { parsedResult.setResult(result); } } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof StyleProcessor) { StyleProcessor<?> that = (StyleProcessor) obj; if (this.dateStyle.equals(that.dateStyle) && this.timeStyle.equals(that.timeStyle)) { if (this.formatter == null) { return (that.formatter == null); } else { return this.formatter.equals(that.formatter); } } } return false; } @Override public int hashCode() { return ((this.formatter == null) ? 0 : this.formatter.hashCode()); } @Override public String toString() { StringBuilder sb = new StringBuilder(64); sb.append(this.getClass().getName()); sb.append("[date-style="); sb.append(this.dateStyle); sb.append(",time-style="); sb.append(this.timeStyle); sb.append(",delegate="); sb.append(this.formatter); sb.append(']'); return sb.toString(); } @Override public ChronoElement<T> getElement() { return null; } @Override public FormatProcessor<T> withElement(ChronoElement<T> element) { return this; } @Override public boolean isNumerical() { return false; } @Override public FormatProcessor<T> quickPath( ChronoFormatter<?> formatter, AttributeQuery attributes, int reserved ) { TransitionStrategy strategy = attributes.get(Attributes.TRANSITION_STRATEGY, Timezone.DEFAULT_CONFLICT_STRATEGY); TZID tzid = attributes.get(Attributes.TIMEZONE_ID, null); Locale locale = attributes.get(Attributes.LANGUAGE, Locale.ROOT); ChronoFormatter<T> cf = createFormatter( formatter.getChronology(), this.dateStyle, this.timeStyle, locale, attributes.get(Attributes.FOUR_DIGIT_YEAR, Boolean.FALSE).booleanValue(), (tzid == null) ? null : Timezone.of(tzid).with(strategy)); return new StyleProcessor<>(cf, this.dateStyle, this.timeStyle); } @SuppressWarnings("unchecked") private static <T> ChronoFormatter<T> createFormatter( Chronology<?> chronology, DisplayStyle dateStyle, DisplayStyle timeStyle, Locale locale, boolean fourDigitYear, Timezone tz // optional ) { String pattern; if (chronology.equals(PlainDate.axis())) { pattern = CalendarText.patternForDate((DisplayMode) dateStyle, locale); } else if (chronology.equals(PlainTime.axis())) { pattern = CalendarText.patternForTime((DisplayMode) timeStyle, locale); } else if (chronology.equals(PlainTimestamp.axis())) { pattern = CalendarText.patternForTimestamp((DisplayMode) dateStyle, (DisplayMode) timeStyle, locale); } else if (chronology.equals(Moment.axis())) { pattern = CalendarText.patternForMoment((DisplayMode) dateStyle, (DisplayMode) timeStyle, locale); } else if (LocalizedPatternSupport.class.isAssignableFrom(chronology.getChronoType())) { assert (dateStyle == timeStyle); pattern = chronology.getFormatPattern(dateStyle, locale); } else { throw new UnsupportedOperationException("Localized format patterns not available: " + chronology); } if (fourDigitYear && pattern.contains("yy") && !pattern.contains("yyy")) { pattern = pattern.replace("yy", "yyyy"); } ChronoFormatter<?> cf = ChronoFormatter.ofPattern(pattern, PatternType.CLDR, locale, chronology); if (tz != null) { cf = cf.with(tz); } return (ChronoFormatter<T>) cf; } }