001: /*
002: * JDayChooser.java - A bean for choosing a day
003: * Copyright (C) 2002 Kai Toedter
004: * kai@toedter.com
005: * www.toedter.com
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020: */
021: package com.toedter.calendar;
022:
023: import java.awt.Color;
024: import java.awt.Font;
025: import java.awt.GridLayout;
026: import java.awt.Insets;
027: import java.awt.event.ActionEvent;
028: import java.awt.event.ActionListener;
029: import java.awt.event.FocusEvent;
030: import java.awt.event.FocusListener;
031: import java.awt.event.KeyEvent;
032: import java.awt.event.KeyListener;
033: import java.awt.event.MouseListener;
034: import java.text.DateFormatSymbols;
035: import java.util.Calendar;
036: import java.util.Date;
037: import java.util.Locale;
038:
039: import javax.swing.JButton;
040: import javax.swing.JFrame;
041: import javax.swing.JPanel;
042:
043: /**
044: * JCalendar is a bean for choosing a day.
045: *
046: *@author Kai Toedter
047: *@version 1.1.3 07/16/02
048: */
049: public class JDayChooser extends JPanel implements ActionListener,
050: KeyListener, FocusListener {
051: private static final long serialVersionUID = 3761409733051103536L;
052:
053: /**
054: * Default JDayChooser constructor.
055: */
056: public JDayChooser() {
057: locale = Locale.getDefault();
058: days = new JButton[49];
059: selectedDay = null;
060: Calendar calendar = Calendar.getInstance(locale);
061: today = (Calendar) calendar.clone();
062:
063: setLayout(new GridLayout(7, 7));
064:
065: for (int y = 0; y < 7; y++) {
066: for (int x = 0; x < 7; x++) {
067: int index = x + 7 * y;
068: if (y == 0) {
069: // Create a button that doesn't react on clicks or focus changes
070: // Thanks to Thomas Schaefer for the focus hint :)
071: days[index] = new JButton() {
072: private static final long serialVersionUID = 3257562914834428721L;
073:
074: public void addMouseListener(MouseListener l) {
075: }
076:
077: // This method has been deprecated by 1.4
078: // and will be replaced by isFocusable in future versions
079: public boolean isFocusTraversable() {
080: return false;
081: }
082: };
083: days[index].setBackground(new Color(180, 180, 200));
084: } else {
085: days[index] = new JButton("x");
086: days[index].addActionListener(this );
087: days[index].addKeyListener(this );
088: days[index].addFocusListener(this );
089: }
090:
091: days[index].setMargin(new Insets(0, 0, 0, 0));
092: days[index].setFocusPainted(false);
093: add(days[index]);
094: }
095: }
096: init();
097: setDay(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
098: initialized = true;
099: }
100:
101: /**
102: * Initilizes the locale specific names for the days of the week.
103: */
104: protected void init() {
105: colorRed = new Color(164, 0, 0);
106: colorBlue = new Color(0, 0, 164);
107: JButton testButton = new JButton();
108: oldDayBackgroundColor = testButton.getBackground();
109: selectedColor = new Color(160, 160, 160);
110:
111: calendar = Calendar.getInstance(locale);
112: int firstDayOfWeek = calendar.getFirstDayOfWeek();
113: DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(
114: locale);
115: dayNames = dateFormatSymbols.getShortWeekdays();
116: int day = firstDayOfWeek;
117: for (int i = 0; i < 7; i++) {
118: days[i].setText(dayNames[day]);
119: if (day == 1) {
120: days[i].setForeground(colorRed);
121: } else {
122: days[i].setForeground(colorBlue);
123: }
124:
125: if (day < 7) {
126: day++;
127: } else {
128: day -= 6;
129: }
130:
131: }
132: drawDays();
133: }
134:
135: /**
136: * Hides and shows the day buttons.
137: */
138: protected void drawDays() {
139: Calendar tmpCalendar = (Calendar) calendar.clone();
140: int firstDayOfWeek = tmpCalendar.getFirstDayOfWeek();
141: tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
142:
143: int firstDay = tmpCalendar.get(Calendar.DAY_OF_WEEK)
144: - firstDayOfWeek;
145: if (firstDay < 0) {
146: firstDay += 7;
147: }
148:
149: int i;
150:
151: for (i = 0; i < firstDay; i++) {
152: days[i + 7].setVisible(false);
153: days[i + 7].setText("");
154: }
155:
156: tmpCalendar.add(Calendar.MONTH, 1);
157: Date firstDayInNextMonth = tmpCalendar.getTime();
158: tmpCalendar.add(Calendar.MONTH, -1);
159:
160: Date day = tmpCalendar.getTime();
161: int n = 0;
162: Color foregroundColor = getForeground();
163: while (day.before(firstDayInNextMonth)) {
164: days[i + n + 7].setText(Integer.toString(n + 1));
165: days[i + n + 7].setVisible(true);
166: if (tmpCalendar.get(Calendar.DAY_OF_YEAR) == today
167: .get(Calendar.DAY_OF_YEAR)
168: && tmpCalendar.get(Calendar.YEAR) == today
169: .get(Calendar.YEAR)) {
170: days[i + n + 7].setForeground(colorRed);
171: } else {
172: days[i + n + 7].setForeground(foregroundColor);
173: }
174:
175: if (n + 1 == this .day) {
176: days[i + n + 7].setBackground(selectedColor);
177: selectedDay = days[i + n + 7];
178: } else {
179: days[i + n + 7].setBackground(oldDayBackgroundColor);
180: }
181:
182: n++;
183: tmpCalendar.add(Calendar.DATE, 1);
184: day = tmpCalendar.getTime();
185: }
186:
187: for (int k = n + i + 7; k < 49; k++) {
188: days[k].setVisible(false);
189: days[k].setText("");
190: }
191: }
192:
193: /**
194: * Returns the locale.
195: *
196: *@return The locale value
197: *@see #setLocale
198: */
199: public Locale getLocale() {
200: return locale;
201: }
202:
203: /**
204: * Sets the locale.
205: *
206: *@param l The new locale value
207: *@see #getLocale
208: */
209: public void setLocale(Locale l) {
210: if (!initialized) {
211: super .setLocale(l);
212: } else {
213: locale = l;
214: init();
215: }
216: }
217:
218: /**
219: * Sets the day. This is a bound property.
220: *
221: *@param d the day
222: *@see #getDay
223: */
224: public void setDay(int d) {
225: if (d < 1) {
226: d = 1;
227: }
228:
229: Calendar tmpCalendar = (Calendar) calendar.clone();
230: tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
231: tmpCalendar.add(Calendar.MONTH, 1);
232: tmpCalendar.add(Calendar.DATE, -1);
233: int maxDaysInMonth = tmpCalendar.get(Calendar.DATE);
234:
235: if (d > maxDaysInMonth) {
236: d = maxDaysInMonth;
237: }
238:
239: int oldDay = day;
240: day = d;
241:
242: if (selectedDay != null) {
243: selectedDay.setBackground(oldDayBackgroundColor);
244: selectedDay.repaint();
245: // Bug: needed for Swing 1.0.3
246: }
247:
248: for (int i = 7; i < 49; i++) {
249: if (days[i].getText().equals(Integer.toString(day))) {
250: selectedDay = days[i];
251: selectedDay.setBackground(selectedColor);
252: break;
253: }
254: }
255: firePropertyChange("day", oldDay, day);
256: }
257:
258: /**
259: * Returns the selected day.
260: *
261: *@return The day value
262: *@see #setDay
263: */
264: public int getDay() {
265: return day;
266: }
267:
268: /**
269: * Sets a specific month. This is needed for correct graphical representation
270: * of the days.
271: *
272: *@param month the new month
273: */
274: public void setMonth(int month) {
275: calendar.set(Calendar.MONTH, month);
276: setDay(day);
277: drawDays();
278: }
279:
280: /**
281: * Sets a specific year. This is needed for correct graphical representation
282: * of the days.
283: *
284: *@param year the new year
285: */
286: public void setYear(int year) {
287: calendar.set(Calendar.YEAR, year);
288: drawDays();
289: }
290:
291: /**
292: * Sets a specific calendar. This is needed for correct graphical
293: * representation of the days.
294: *
295: *@param c the new calendar
296: */
297: public void setCalendar(Calendar c) {
298: calendar = c;
299: drawDays();
300: }
301:
302: /**
303: * Sets the font property.
304: *
305: *@param font the new font
306: */
307: public void setFont(Font font) {
308: if (days != null) {
309: for (int i = 0; i < 49; i++) {
310: days[i].setFont(font);
311: }
312: }
313: }
314:
315: /**
316: * Sets the foregroundColor color.
317: *
318: *@param fg the new foregroundColor
319: */
320: public void setForeground(Color fg) {
321: super .setForeground(fg);
322: if (days != null) {
323: for (int i = 7; i < 49; i++) {
324: days[i].setForeground(fg);
325: }
326: drawDays();
327: }
328: }
329:
330: /**
331: * Returns "JDayChooser".
332: *
333: *@return The name value
334: */
335: public String getName() {
336: return "JDayChooser";
337: }
338:
339: /**
340: * JDayChooser is the ActionListener for all day buttons.
341: *
342: *@param e Description of the Parameter
343: */
344: public void actionPerformed(ActionEvent e) {
345: JButton button = (JButton) e.getSource();
346: String buttonText = button.getText();
347: int day = new Integer(buttonText).intValue();
348: setDay(day);
349: }
350:
351: /**
352: * JDayChooser is the FocusListener for all day buttons. (Added by Thomas
353: * Schaefer)
354: *
355: *@param e Description of the Parameter
356: */
357: public void focusGained(FocusEvent e) {
358: JButton button = (JButton) e.getSource();
359: String buttonText = button.getText();
360: if (buttonText != null && !buttonText.equals("")) {
361: actionPerformed(new ActionEvent(e.getSource(), 0, null));
362: }
363: }
364:
365: /**
366: * Does nothing.
367: *
368: *@param e Description of the Parameter
369: */
370: public void focusLost(FocusEvent e) {
371: }
372:
373: /**
374: * JDayChooser is the KeyListener for all day buttons. (Added by Thomas
375: * Schaefer)
376: *
377: *@param e Description of the Parameter
378: */
379: public void keyPressed(KeyEvent e) {
380: int offset = e.getKeyCode() == KeyEvent.VK_UP ? -7 : e
381: .getKeyCode() == KeyEvent.VK_DOWN ? +7
382: : e.getKeyCode() == KeyEvent.VK_LEFT ? -1 : e
383: .getKeyCode() == KeyEvent.VK_RIGHT ? +1 : 0;
384:
385: if (offset != 0) {
386: for (int i = getComponentCount() - 1; i >= 0; --i) {
387: if (getComponent(i) == selectedDay) {
388: i += offset;
389: if (i > 7 && i < days.length && days[i].isVisible()) {
390: days[i].requestFocus();
391: //int day = new Integer(days[i].getText()).intValue();
392: //setDay( day );
393: }
394: break;
395: }
396: }
397: }
398: }
399:
400: /**
401: * Does nothing.
402: *
403: *@param e Description of the Parameter
404: */
405: public void keyTyped(KeyEvent e) {
406: }
407:
408: /**
409: * Does nothing.
410: *
411: *@param e Description of the Parameter
412: */
413: public void keyReleased(KeyEvent e) {
414: }
415:
416: /**
417: * Enable or disable the JDayChooser.
418: *
419: *@param enabled The new enabled value
420: */
421: public void setEnabled(boolean enabled) {
422: super .setEnabled(enabled);
423: for (short i = 0; i < days.length; i++) {
424: if (days[i] != null) {
425: days[i].setEnabled(enabled);
426: }
427: }
428: }
429:
430: /**
431: * Creates a JFrame with a JDayChooser inside and can be used for testing.
432: *
433: *@param s The command line arguments
434: */
435: public static void main(String[] s) {
436: JFrame frame = new JFrame("JDayChooser");
437: frame.getContentPane().add(new JDayChooser());
438: frame.pack();
439: frame.setVisible(true);
440: }
441:
442: private JButton days[];
443: private JButton selectedDay;
444: private int day;
445: private Color oldDayBackgroundColor;
446: private Color selectedColor;
447: private Color colorRed;
448: private Color colorBlue;
449: private String dayNames[];
450: private Calendar calendar;
451: private Calendar today;
452: private Locale locale;
453: private boolean initialized = false;
454: }
|