/*
* LabelFormatterDate.java of project jchart2d. A label formatter that uses formatted
* dates.
* Copyright (C) 2005 - 2011 Achim Westermann, created on 20.04.2005, 11:56:36
*
* This library 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.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* If you modify or optimize the code in a useful way please let me know.
* Achim.Westermann@gmx.de
*
*/
package info.monitorenter.gui.chart.labelformatters;
import info.monitorenter.gui.chart.IAxisLabelFormatter;
import info.monitorenter.util.Range;
import info.monitorenter.util.SimpleDateFormatAnalyzer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* An ILabelFormatter instance that uses a {@link java.text.DateFormat} to
* format the labels.
* <p>
* <b>Caution: <br>
* It only makes sense to use this class if the data of the corresponding axis
* may be interpreted as long number of milliseconds since the standard base
* time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. </b>
* <p>
* <b>Caution: <br>
* This implementation is not completely conform with the constraint: <code>
* instance.parse(instance.format(value)) == value
* </code>
* </b> This only works for subsequent call: one call to format contains the
* next value to return from parse to be the same as the format. That value is
* cached as date / time formatting produces truncation of the internal value
* (e.g. if no year is displayed). <br>
* Use: <br>
*
* <pre>
*
* Chart2D chart = new <Constructor>
* Axis axis = new AxisSimple();
* axis.setFormatter(new LabelFormatterDate(DateFormat.getDateInstance()));
* chart.setAxisX(axis);
*
* </pre>
*
* to use this class.
* <p>
*
* @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
*
* @version $Revision: 1.11 $
*
* @see java.util.Date
*/
public class LabelFormatterDate extends ALabelFormatter implements IAxisLabelFormatter {
/** Generated <code>serialVersionUID</code>. */
private static final long serialVersionUID = -7201853569619240987L;
/** The cached maximum amount of characters that will be used. */
private int m_cachedMaxAmountChars = Integer.MAX_VALUE;
/** The date formatter that is used. */
private SimpleDateFormat m_dateFormat;
/**
* The last value that was formatted - needed for the parse - format contract.
*/
private double m_lastFormatted = 0;
/**
* Default constructor that uses the local datetime (
* <code>{@link DateFormat#getDateTimeInstance(int, int)}</code>) with
* <code>{@link DateFormat#SHORT}</code> style.
* <p>
*
*/
public LabelFormatterDate() {
this((SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT));
}
/**
* Creates a formatter that uses the given date format.
* <p>
*
* @param dateFormat
* the date format to use.
*/
public LabelFormatterDate(final SimpleDateFormat dateFormat) {
super();
this.m_dateFormat = dateFormat;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final LabelFormatterDate other = (LabelFormatterDate) obj;
if (this.m_cachedMaxAmountChars != other.m_cachedMaxAmountChars) {
return false;
}
if (this.m_dateFormat == null) {
if (other.m_dateFormat != null) {
return false;
}
} else if (!this.m_dateFormat.equals(other.m_dateFormat)) {
return false;
}
if (Double.doubleToLongBits(this.m_lastFormatted) != Double
.doubleToLongBits(other.m_lastFormatted)) {
return false;
}
return true;
}
/**
* @see info.monitorenter.gui.chart.IAxisLabelFormatter#format(double)
*/
public String format(final double value) {
this.m_lastFormatted = value;
return this.m_dateFormat.format(new Date((long) value));
}
/**
* Returns the date formatter that is used.
* <p>
*
* @return the date formatter that is used.
*/
final SimpleDateFormat getDateFormate() {
return this.m_dateFormat;
}
/**
* @see info.monitorenter.gui.chart.IAxisLabelFormatter#getMaxAmountChars()
*/
@Override
public int getMaxAmountChars() {
final Range range = this.getAxis().getRange();
final double dRange = range.getExtent();
if (this.m_cachedMaxAmountChars == Integer.MAX_VALUE) {
this.m_cachedMaxAmountChars = this.m_dateFormat.format(new Date((long) dRange)).length();
}
return this.m_cachedMaxAmountChars;
}
/**
* @see info.monitorenter.gui.chart.IAxisLabelFormatter#getMinimumValueShiftForChange()
*/
public double getMinimumValueShiftForChange() {
double ret = 0;
if (SimpleDateFormatAnalyzer.displaysMillisecond(this.m_dateFormat)) {
ret = 1;
} else if (SimpleDateFormatAnalyzer.displaysSecond(this.m_dateFormat)) {
ret = 1000;
} else if (SimpleDateFormatAnalyzer.displaysMinute(this.m_dateFormat)) {
ret = 60000;
} else if (SimpleDateFormatAnalyzer.displaysHour(this.m_dateFormat)) {
ret = 360000;
} else if (SimpleDateFormatAnalyzer.displaysDay(this.m_dateFormat)) {
ret = 24 * 360000;
} else if (SimpleDateFormatAnalyzer.displaysMonth(this.m_dateFormat)) {
ret = 31 * 24 * 360000;
} else {
ret = 12 * 31 * 24 * 60000;
}
return ret;
}
/**
* @see info.monitorenter.gui.chart.IAxisLabelFormatter#getNextEvenValue(double,
* boolean)
*/
public double getNextEvenValue(final double value, final boolean ceiling) {
final Date d = new Date((long) value);
final Calendar calendar = Calendar.getInstance();
calendar.setTime(d);
if (ceiling) {
if (!SimpleDateFormatAnalyzer.displaysMillisecond(this.m_dateFormat)) {
calendar.set(Calendar.MILLISECOND, 0);
if (!SimpleDateFormatAnalyzer.displaysSecond(this.m_dateFormat)) {
calendar.set(Calendar.SECOND, 0);
if (!SimpleDateFormatAnalyzer.displaysMinute(this.m_dateFormat)) {
calendar.set(Calendar.MINUTE, 0);
if (!SimpleDateFormatAnalyzer.displaysHour(this.m_dateFormat)) {
calendar.set(Calendar.HOUR, 0);
if (!SimpleDateFormatAnalyzer.displaysDay(this.m_dateFormat)) {
calendar.set(Calendar.DAY_OF_YEAR, 0);
if (!SimpleDateFormatAnalyzer.displaysMonth(this.m_dateFormat)) {
calendar.set(Calendar.MONTH, 0);
if (!SimpleDateFormatAnalyzer.displaysYear(this.m_dateFormat)) {
calendar.set(Calendar.YEAR, 0);
}
}
}
}
}
}
}
} else {
if (!SimpleDateFormatAnalyzer.displaysMillisecond(this.m_dateFormat)) {
calendar.set(Calendar.MILLISECOND, 1000);
if (!SimpleDateFormatAnalyzer.displaysSecond(this.m_dateFormat)) {
calendar.set(Calendar.SECOND, 60);
if (!SimpleDateFormatAnalyzer.displaysMinute(this.m_dateFormat)) {
calendar.set(Calendar.MINUTE, 60);
if (!SimpleDateFormatAnalyzer.displaysHour(this.m_dateFormat)) {
calendar.set(Calendar.HOUR, 24);
if (!SimpleDateFormatAnalyzer.displaysDay(this.m_dateFormat)) {
calendar.set(Calendar.DAY_OF_YEAR, 365);
if (!SimpleDateFormatAnalyzer.displaysMonth(this.m_dateFormat)) {
calendar.set(Calendar.MONTH, 12);
if (!SimpleDateFormatAnalyzer.displaysYear(this.m_dateFormat)) {
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
}
}
}
}
}
}
}
}
return calendar.getTimeInMillis();
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.m_cachedMaxAmountChars;
result = prime * result + ((this.m_dateFormat == null) ? 0 : this.m_dateFormat.hashCode());
long temp;
temp = Double.doubleToLongBits(this.m_lastFormatted);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
/**
* @see info.monitorenter.gui.chart.IAxisLabelFormatter#parse(java.lang.String)
*/
public Number parse(final String formatted) throws NumberFormatException {
return new Double(this.m_lastFormatted);
}
/**
* Sets the date formatter to use.
* <p>
*
* @param df
* the date formatter to use.
*/
final void setDateFormate(final SimpleDateFormat df) {
this.m_dateFormat = df;
}
}