001 /* 002 * Copyright (c) Holger Pfaff - http://pfaff.ws 003 * 004 * This software maybe used for any purpose provided the 005 * above copyright notice is retained. It is supplied as is. 006 * No warranty expressed or implied - Use at your own risk. 007 */ 008 009 import java.text.*; 010 import java.util.*; 011 import java.awt.*; 012 import java.awt.event.*; 013 014 /** 015 * (#)Cal.java 016 * @author Holger Pfaff 017 * @version 3.2 19-Mar-2004<br><br> 018 * 019 * A universal calendar widget to enter/display a date optionally time 020 * 021 */ 022 023 public class Cal extends Awt implements ActionListener { 024 025 /** 026 * bitmask for showing date 027 */ 028 public static final int DATE = 1 << 0; 029 030 /** 031 * bitmask for showing time 032 */ 033 public static final int TIME = 1 << 1; 034 035 /** 036 * currend mode: TIME, DATE, DATE|TIME 037 */ 038 protected int mode = 0; 039 040 /** 041 * holds current date/time 042 */ 043 protected GregorianCalendar cl = new GregorianCalendar(); 044 045 /** 046 * dateformat used for this widget 047 */ 048 protected DateFormat df = null; 049 050 /** 051 * timeformat used for this widget 052 */ 053 protected DateFormat tf = null; 054 055 /** 056 * knobs for day of month selection 057 */ 058 protected Knob[] days = new Knob[42]; 059 060 /** 061 * date panel 062 */ 063 protected Container datp = new BorderPanel(BULK); 064 065 /** 066 * day panel 067 */ 068 protected Container dayp = new BorderPanel(BULK); 069 070 /** 071 * time panel 072 */ 073 protected Container timp = new BorderPanel(BULK); 074 075 /** 076 * date label - disply current date set 077 */ 078 protected Caption datl = new Caption("", CENTER); 079 080 /** 081 * time label - disply current time set 082 */ 083 protected Caption timl = new Caption("", CENTER); 084 085 /** 086 * default constructor - creates date date/time widget 087 */ 088 public Cal() { 089 this(DATE|TIME); 090 } 091 092 /** 093 * constructor - creates specified widget 094 * 095 * @param m mode bits: TIME DATE DATE|TIME 096 */ 097 public Cal(int m) { 098 this(m, new Date()); 099 } 100 101 /** 102 * constructor - creates specified widget with specified initial date/time 103 * 104 * @param m mode bits: TIME DATE DATE|TIME 105 * @param d date for initialization 106 */ 107 public Cal(int m, Date d) { 108 this(m, d, Locale.getDefault()); 109 } 110 111 /** 112 * constructor - creates specified widget with specified initial date/time 113 * and specified locale (language) 114 * 115 * @param m mode bits: TIME DATE DATE|TIME 116 * @param d date for initialization 117 * @param l locale to use 118 */ 119 public Cal(int m, Date d, Locale l) { 120 setLayout(new BorderLayout()); 121 122 df = DateFormat.getDateInstance(DateFormat.LONG, l); 123 tf = DateFormat.getTimeInstance(DateFormat.SHORT, l); 124 125 cl.setTimeZone(correctTZ(cl.getTimeZone())); 126 df.setTimeZone(correctTZ(df.getTimeZone())); 127 tf.setTimeZone(correctTZ(tf.getTimeZone())); 128 129 datp.setLayout(new ColumnLayout(7, ColumnLayout.HORZ, Awt.C, ColumnLayout.ALL, ColumnLayout.NONE)); 130 dayp.setLayout(new ColumnLayout(7, ColumnLayout.ALL, Awt.C, ColumnLayout.ALL, ColumnLayout.ALL)); 131 timp.setLayout(new ColumnLayout(5, ColumnLayout.HORZ, Awt.C, ColumnLayout.ALL, ColumnLayout.NONE)); 132 133 addKnob("<<<", "X-" + Calendar.YEAR, datp); // year decr 134 addKnob("<<", "X-" + Calendar.MONTH, datp); // month decr 135 addKnob("<", "X-" + Calendar.DAY_OF_MONTH, datp); // day decr 136 datp.add(datl); 137 addKnob(">", "X" + Calendar.DAY_OF_MONTH, datp); // day incr 138 addKnob(">>", "X" + Calendar.MONTH, datp); // month incr 139 addKnob(">>>", "X" + Calendar.YEAR, datp); // year incr 140 141 addKnob("<<", "X-" + Calendar.HOUR, timp); // hour decr 142 addKnob("<", "X-" + Calendar.MINUTE, timp); // minute decr 143 timp.add(timl); 144 addKnob(">", "X" + Calendar.MINUTE, timp); // minute incr 145 addKnob(">>", "X" + Calendar.HOUR, timp); // hour incr 146 147 148 String[] wd = new DateFormatSymbols(l).getShortWeekdays(); 149 for(int i = 0; i < 7 ; ++i) { 150 dayp.add(new Caption("" + Esc + Bold + wd[i + 1], Caption.CENTER)); 151 } 152 153 Insets in = new Insets(5,13,5,13); 154 155 for(int i = 0; i < 42; ++i) { 156 days[i] = new Knob(); 157 days[i].setInnerInsets(in); 158 days[i].setActionCommand("" + i); 159 days[i].addActionListener(this); 160 dayp.add(days[i]); 161 } 162 163 setMode(m); 164 setDate(d); 165 } 166 167 /** 168 * used internally to create shifting knobs 169 * 170 * @param l label for this knob 171 * @param a action cmd for this knob 172 * @param p container to add knob to 173 */ 174 private void addKnob(String l, String a, Container p) { 175 Knob k = new Knob(l); 176 k.setActionCommand(a); 177 k.addActionListener(this); 178 p.add(k); 179 } 180 181 /** 182 * implement actionlistener to catch knobs pressed 183 */ 184 public void actionPerformed(ActionEvent e) { 185 if(e.getActionCommand().charAt(0) == 'X') { 186 int i = Integer.parseInt(e.getActionCommand().substring(1)); 187 add(Math.abs(i), i/Math.abs(i)); 188 } else { 189 int i = Integer.parseInt(e.getActionCommand()); 190 set(Calendar.DAY_OF_MONTH, Integer.parseInt(days[i].getLabel())); 191 } 192 notifyActionListeners(new ActionEvent(this, 0, "")); 193 } 194 195 /** 196 * increment/decrement current date/time 197 * 198 * @param f field to change within calendar 199 * @param v value to add/remove 200 */ 201 public void add(int f, int v) { 202 cl.add(f, v); set(); 203 } 204 205 /** 206 * set current date/time 207 * 208 * @param f field to set within calendar 209 * @param v value to set 210 */ 211 public void set(int f, int v) { 212 cl.set(f, v); set(); 213 } 214 215 /** 216 * set current date/time 217 * 218 * @param d date to set 219 */ 220 public void setDate(Date d) { 221 cl.setTime(d); set(); 222 } 223 224 /** 225 * set current date/time from string using specified date format 226 * 227 * @param d date to set 228 * @param df date format to use 229 */ 230 public void setDate(String d, String df) { 231 setDate(d, new SimpleDateFormat(df)); 232 } 233 234 /** 235 * set current date/time from string using specified date format 236 * 237 * @param d date to set 238 * @param df date format to use 239 */ 240 public void setDate(String d, DateFormat df) { 241 try { 242 df.setTimeZone(correctTZ(df.getTimeZone())); 243 setDate(df.parse(d)); 244 } catch(Exception x) { 245 } 246 } 247 248 /** 249 * get this widget's current date/time 250 */ 251 public Date getDate() { 252 return cl.getTime(); 253 } 254 255 /** 256 * get this widget's current time as seconds from 1970 257 */ 258 public long getTime() { 259 return getDate().getTime() / 1000; 260 } 261 262 /** 263 * set current date/time 264 * 265 * @param c date/time to use 266 */ 267 public void setDate(Calendar c) { 268 setDate(c.getTime()); 269 } 270 271 /** 272 * set current date/time 273 * 274 * @param c date/time to use 275 */ 276 public void setCalendar(Calendar c) { 277 setDate(c); 278 } 279 280 /** 281 * get this widget's date/time as Calendar object 282 */ 283 public Calendar getCalendar() { 284 return cl; 285 } 286 287 /** 288 * internally called if something has changed 289 */ 290 protected void set() { 291 String tl = "" + Esc + Bold + tf.format(cl.getTime()); 292 String dl = "" + Esc + Bold + df.format(cl.getTime()); 293 294 if(tf.equals(timl.getLabel()) == false) { 295 timl.setLabel(tl); 296 } 297 298 if(dl.equals(datl.getLabel()) == false) { 299 datl.setLabel(dl); 300 GregorianCalendar c = new GregorianCalendar(cl.get(Calendar.YEAR), cl.get(Calendar.MONTH), 1, 12, 00); 301 int fwd = c.get(Calendar.DAY_OF_WEEK) - c.getMinimum(Calendar.DAY_OF_WEEK); 302 for(int i = 0; i < 42; ++i) { 303 days[i].setVisible(i >= fwd && c.get(Calendar.MONTH) == cl.get(Calendar.MONTH)); 304 days[i].setActive(c.get(Calendar.DAY_OF_MONTH) == cl.get(Calendar.DAY_OF_MONTH)); 305 days[i].setLabel("" + c.get(Calendar.DAY_OF_MONTH)); 306 if(i >= fwd) c.add(Calendar.DAY_OF_MONTH, 1); 307 } 308 } 309 validateTree(); 310 } 311 312 /** 313 * set this widget mode - TIME, DATE or DATE|TIME 314 * 315 * @param m mode bits: TIME DATE DATE|TIME 316 */ 317 public void setMode(int m) { 318 mode = m; removeAll(); 319 if((m & DATE) > 0) { 320 add(datp, BorderLayout.NORTH); 321 add(dayp, BorderLayout.CENTER); 322 } 323 if((m & TIME) > 0) { 324 add(timp, BorderLayout.SOUTH); 325 } 326 } 327 328 /** 329 * get this widget's mode 330 */ 331 public int getMode() { 332 return mode; 333 } 334 335 /** 336 * get this widget's date/time using the specified date format 337 * 338 * @param df date format to use 339 */ 340 public String toString(String df) { 341 return df.equals("time") ? "" + getTime() : toString(new SimpleDateFormat(df)); 342 } 343 344 /** 345 * get this widget's date/time using the specified date format 346 * 347 * @param df date format to use 348 */ 349 public String toString(DateFormat df) { 350 return df.format(getDate()); 351 } 352 353 /** 354 * Java treats MET as "Middle Eastern Time" not as "Middle European time" as expected. 355 * For now just change MET to ECT 356 */ 357 protected TimeZone correctTZ(TimeZone tz) { 358 return tz.equals(TimeZone.getTimeZone("MET")) ? TimeZone.getTimeZone("ECT") : tz; 359 } 360 361 /** 362 * get this widget's required size 363 */ 364 public Dimension measure() { 365 return getLayout().preferredLayoutSize(this); 366 } 367 } 368