001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------------------- 028 * MonthDateFormat.java 029 * -------------------- 030 * (C) Copyright 2005-present, by David Gilbert and Contributors. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart.axis; 038 039import java.text.DateFormat; 040import java.text.DateFormatSymbols; 041import java.text.FieldPosition; 042import java.text.NumberFormat; 043import java.text.ParsePosition; 044import java.text.SimpleDateFormat; 045import java.util.Arrays; 046import java.util.Calendar; 047import java.util.Date; 048import java.util.GregorianCalendar; 049import java.util.Locale; 050import java.util.TimeZone; 051import org.jfree.chart.util.Args; 052 053/** 054 * A formatter that formats dates to show the initial letter(s) of the month 055 * name and, as an option, the year for the first or last month of each year. 056 */ 057public class MonthDateFormat extends DateFormat { 058 059 /** The symbols used for the months. */ 060 private String[] months; 061 062 /** Flags that control which months will have the year appended. */ 063 private boolean[] showYear; 064 065 /** The year formatter. */ 066 private DateFormat yearFormatter; 067 068 /** 069 * Creates a new instance for the default time zone. 070 */ 071 public MonthDateFormat() { 072 this(TimeZone.getDefault()); 073 } 074 075 /** 076 * Creates a new instance for the specified time zone. 077 * 078 * @param zone the time zone ({@code null} not permitted). 079 */ 080 public MonthDateFormat(TimeZone zone) { 081 this(zone, Locale.getDefault(), 1, true, false); 082 } 083 084 /** 085 * Creates a new instance for the specified time zone. 086 * 087 * @param locale the locale used to obtain the month 088 * names ({@code null} not permitted). 089 */ 090 public MonthDateFormat(Locale locale) { 091 this(TimeZone.getDefault(), locale, 1, true, false); 092 } 093 094 /** 095 * Creates a new instance for the specified time zone. 096 * 097 * @param zone the time zone ({@code null} not permitted). 098 * @param chars the maximum number of characters to use from the month 099 * names (that are obtained from the date symbols of the 100 * default locale). If this value is <= 0, the entire 101 * month name is used in each case. 102 */ 103 public MonthDateFormat(TimeZone zone, int chars) { 104 this(zone, Locale.getDefault(), chars, true, false); 105 } 106 107 /** 108 * Creates a new instance for the specified time zone. 109 * 110 * @param locale the locale ({@code null} not permitted). 111 * @param chars the maximum number of characters to use from the month 112 * names (that are obtained from the date symbols of the 113 * default locale). If this value is <= 0, the entire 114 * month name is used in each case. 115 */ 116 public MonthDateFormat(Locale locale, int chars) { 117 this(TimeZone.getDefault(), locale, chars, true, false); 118 } 119 120 /** 121 * Creates a new formatter. 122 * 123 * @param zone the time zone used to extract the month and year from dates 124 * passed to this formatter ({@code null} not permitted). 125 * @param locale the locale used to determine the month names 126 * ({@code null} not permitted). 127 * @param chars the maximum number of characters to use from the month 128 * names, or zero to indicate that the entire month name 129 * should be used. 130 * @param showYearForJan a flag that controls whether or not the year is 131 * appended to the symbol for the first month of 132 * each year. 133 * @param showYearForDec a flag that controls whether or not the year is 134 * appended to the symbol for the last month of 135 * each year. 136 */ 137 public MonthDateFormat(TimeZone zone, Locale locale, int chars, 138 boolean showYearForJan, boolean showYearForDec) { 139 this(zone, locale, chars, new boolean[] {showYearForJan, false, false, 140 false, false, false, false, false, false, false, false, false, 141 showYearForDec}, new SimpleDateFormat("yy")); 142 } 143 144 /** 145 * Creates a new formatter. 146 * 147 * @param zone the time zone used to extract the month and year from dates 148 * passed to this formatter ({@code null} not permitted). 149 * @param locale the locale used to determine the month names 150 * ({@code null} not permitted). 151 * @param chars the maximum number of characters to use from the month 152 * names, or zero to indicate that the entire month name 153 * should be used. 154 * @param showYear an array of flags that control whether or not the 155 * year is displayed for a particular month. 156 * @param yearFormatter the year formatter. 157 */ 158 public MonthDateFormat(TimeZone zone, Locale locale, int chars, 159 boolean[] showYear, DateFormat yearFormatter) { 160 Args.nullNotPermitted(locale, "locale"); 161 DateFormatSymbols dfs = new DateFormatSymbols(locale); 162 String[] monthsFromLocale = dfs.getMonths(); 163 this.months = new String[12]; 164 for (int i = 0; i < 12; i++) { 165 if (chars > 0) { 166 this.months[i] = monthsFromLocale[i].substring(0, 167 Math.min(chars, monthsFromLocale[i].length())); 168 } 169 else { 170 this.months[i] = monthsFromLocale[i]; 171 } 172 } 173 this.calendar = new GregorianCalendar(zone); 174 this.showYear = showYear; 175 this.yearFormatter = yearFormatter; 176 177 // the following is never used, but it seems that DateFormat requires 178 // it to be non-null. It isn't well covered in the spec, refer to 179 // bug parade 5061189 for more info. 180 this.numberFormat = NumberFormat.getNumberInstance(); 181 } 182 183 /** 184 * Formats the given date. 185 * 186 * @param date the date. 187 * @param toAppendTo the string buffer. 188 * @param fieldPosition the field position. 189 * 190 * @return The formatted date. 191 */ 192 @Override 193 public StringBuffer format(Date date, StringBuffer toAppendTo, 194 FieldPosition fieldPosition) { 195 this.calendar.setTime(date); 196 int month = this.calendar.get(Calendar.MONTH); 197 toAppendTo.append(this.months[month]); 198 if (this.showYear[month]) { 199 toAppendTo.append(this.yearFormatter.format(date)); 200 } 201 return toAppendTo; 202 } 203 204 /** 205 * Parses the given string (not implemented). 206 * 207 * @param source the date string. 208 * @param pos the parse position. 209 * 210 * @return {@code null}, as this method has not been implemented. 211 */ 212 @Override 213 public Date parse(String source, ParsePosition pos) { 214 return null; 215 } 216 217 /** 218 * Tests this formatter for equality with an arbitrary object. 219 * 220 * @param obj the object. 221 * 222 * @return A boolean. 223 */ 224 @Override 225 public boolean equals(Object obj) { 226 if (obj == this) { 227 return true; 228 } 229 if (!(obj instanceof MonthDateFormat)) { 230 return false; 231 } 232 if (!super.equals(obj)) { 233 return false; 234 } 235 MonthDateFormat that = (MonthDateFormat) obj; 236 if (!Arrays.equals(this.months, that.months)) { 237 return false; 238 } 239 if (!Arrays.equals(this.showYear, that.showYear)) { 240 return false; 241 } 242 if (!this.yearFormatter.equals(that.yearFormatter)) { 243 return false; 244 } 245 return true; 246 } 247}