1
2
3
4
5
6
7
8
9
10
11 package de.jaret.util.ui.datechooser;
12
13 import java.text.DateFormat;
14 import java.text.DateFormatSymbols;
15 import java.util.Calendar;
16 import java.util.Date;
17 import java.util.GregorianCalendar;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Vector;
21
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.events.KeyEvent;
24 import org.eclipse.swt.events.KeyListener;
25 import org.eclipse.swt.events.MouseAdapter;
26 import org.eclipse.swt.events.MouseEvent;
27 import org.eclipse.swt.events.MouseListener;
28 import org.eclipse.swt.events.MouseTrackAdapter;
29 import org.eclipse.swt.events.PaintEvent;
30 import org.eclipse.swt.events.PaintListener;
31 import org.eclipse.swt.events.SelectionAdapter;
32 import org.eclipse.swt.events.SelectionEvent;
33 import org.eclipse.swt.graphics.Color;
34 import org.eclipse.swt.graphics.Font;
35 import org.eclipse.swt.graphics.GC;
36 import org.eclipse.swt.graphics.Point;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Canvas;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Display;
43 import org.eclipse.swt.widgets.Event;
44 import org.eclipse.swt.widgets.Label;
45 import org.eclipse.swt.widgets.Listener;
46
47 import de.jaret.util.date.holidayenumerator.HolidayEnumerator;
48 import de.jaret.util.swt.SwtGraphicsHelper;
49
50 /***
51 * The DateChooserPanel is intended to be used as a dropdown for the DateFieldCombo (@see
52 * de.jaret.swt.util.datechooser.DateFieldCombo). However if it seems useful it is possible to be used as a standalone
53 * control for selecting a date.
54 *
55 * It features
56 * <ul>
57 * <li>selectable locale which is used for the determination of the first day of the week and the weekday/months
58 * abbreviations</li>
59 * <li>display of week of the year selectable</li>
60 * <li>keyboard control (cursor keys navigate in the day panel, SHIFT-Cursor-left/right navigate month, ESC cancels, t
61 * sets the date to the current date)</li>
62 * <li>actions by the users can be watched by a
63 *
64 * @see de.jaret.swt.util.datechooser.IDateChooserListener (intermdiate change, cancel, selection)</li>
65 * <li>optional a
66 * @see de.jaret.util.date.HolidayEnumerator can be set for highlighting holidays in the day panel</li>
67 * </ul>
68 * TODO selectable font
69 * @author Peter Kliem
70 * @version $Id: DateChooserPanel.java 576 2007-10-03 12:57:38Z olk $
71 */
72 public class DateChooserPanel extends Composite implements MouseListener {
73 /*** currently selected date. */
74 protected Date _date;
75
76 /*** date format symbols instance. */
77 protected static DateFormatSymbols _dateFormatSymbols;
78
79 /*** calendar instance. */
80 protected static Calendar _calendar;
81
82 /*** default color for marking selected date in the panel. */
83 protected static final Color DEFAULTMARKERCOLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
84
85 /*** default color for drawing holidays. */
86 protected static final Color DEFAULTHOLIDAYCOLOR = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
87
88 /*** default color for drawing special days. */
89 protected static final Color DEFAULTSPECIALDAYCOLOR = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW);
90
91 /*** actual color for the background marking. */
92 protected Color _markerColor = DEFAULTMARKERCOLOR;
93 /*** actual color for the foreground of holidays. */
94 protected Color _holidayColor = DEFAULTHOLIDAYCOLOR;
95 /*** actual color for the foreground of special days. */
96 protected Color _specialDayColor = DEFAULTSPECIALDAYCOLOR;
97
98 /***
99 * true: a columnn showing the number of the week in the year should be displayed.
100 */
101 protected boolean _displayWeeks = false;
102
103 /*** true: a single click will select. */
104 protected boolean _oneClickSelection;
105
106 /*** holiday enumerator. */
107 protected HolidayEnumerator _holidayEnumerator;
108
109 /*** provider for additional day information. */
110 protected IAdditionalDayInformationProvider _dayInformationProvider;
111
112 /*** label displaying the month. */
113 protected Label _monthLabel;
114
115 /*** label displaying teh current date. */
116 protected Label _todayLabel;
117
118 /*** increment month button. */
119 protected Button _incMonthButton;
120
121 /*** decrement month button. */
122 protected Button _decMonthButton;
123
124 /*** the daygrid canvas. */
125 protected DayGrid _dayGrid;
126
127 /*** listener list. */
128 protected List<IDateChooserListener> _listenerList;
129
130 /*** locale for the panel. */
131 protected Locale _locale;
132
133 /*** font for bold weekday headings. */
134 private Font _weekdayFont;
135 /*** font for the smaller weeknumbers. */
136 private Font _weekNumberFont;
137
138 /***
139 * Constructor for the DateChooserPanel.
140 *
141 * @param parent Composite parent
142 * @param style style bits
143 * @param oneClickSelection if true, a single mouse click will be considered a valid selection. Otherwise a
144 * selection will need a double click.
145 * @param displayWeeks if true the panel will display a week of the year column
146 * @param locale Locale to be used
147 */
148 public DateChooserPanel(Composite parent, int style, boolean oneClickSelection, boolean displayWeeks, Locale locale) {
149 super(parent, style);
150 _oneClickSelection = oneClickSelection;
151 _displayWeeks = displayWeeks;
152 _locale = locale;
153
154
155 _dateFormatSymbols = new DateFormatSymbols(_locale);
156 _calendar = new GregorianCalendar(_locale);
157
158
159 createControls();
160
161
162 setDate(new Date());
163
164
165 addKeyListener(new KeyListener() {
166 public void keyPressed(KeyEvent event) {
167 handleKeyPressed(event);
168 }
169
170 public void keyReleased(KeyEvent arg0) {
171 }
172 });
173
174
175 Listener listener = new Listener() {
176 public void handleEvent(Event event) {
177 switch (event.type) {
178 case SWT.MouseWheel:
179 int count = -event.count / 3;
180 if ((event.stateMask & SWT.SHIFT) != 0) {
181 rollMonth(count);
182 } else {
183 rollDay(count);
184 }
185 break;
186 default:
187 throw new RuntimeException("unsupported event");
188
189 }
190 }
191 };
192
193 addListener(SWT.MouseWheel, listener);
194 }
195
196 /***
197 * Constructor for the DateChooserPanel. OneClickselection defaults to <code>false</code>, displayWeeks defaults
198 * to <code>true</code>. The Locale used is the default locale.
199 *
200 * @param parent Composite parent
201 * @param style style bits
202 */
203 public DateChooserPanel(Composite parent, int style) {
204 this(parent, style, false, true, Locale.getDefault());
205 }
206
207 /***
208 * {@inheritDoc}
209 */
210 public void dispose() {
211 super.dispose();
212 if (_weekdayFont != null) {
213 _weekdayFont.dispose();
214 }
215 if (_weekNumberFont != null) {
216 _weekNumberFont.dispose();
217 }
218 }
219
220 /***
221 * {@inheritDoc} Propagate the change to the elements.
222 */
223 public void setBackground(Color color) {
224 super.setBackground(color);
225 _monthLabel.setBackground(color);
226 _todayLabel.setBackground(color);
227 _dayGrid.setBackground(color);
228 }
229
230 /***
231 * Handles the key events of the panel.
232 *
233 * @param event KeyEvent to be processed
234 */
235 private void handleKeyPressed(KeyEvent event) {
236 if ((event.stateMask & SWT.SHIFT) != 0) {
237 switch (event.keyCode) {
238 case SWT.ARROW_RIGHT:
239 incMonth();
240 break;
241 case SWT.ARROW_LEFT:
242 decMonth();
243 break;
244
245 default:
246
247 break;
248 }
249 } else {
250 switch (event.keyCode) {
251 case SWT.ESC:
252 fireChoosingCanceled();
253 break;
254 case SWT.CR:
255 fireDateChosen(getDate());
256 break;
257 case SWT.ARROW_RIGHT:
258 incDay();
259 break;
260 case SWT.ARROW_LEFT:
261 decDay();
262 break;
263 case SWT.ARROW_DOWN:
264 incWeek();
265 break;
266 case SWT.ARROW_UP:
267 decWeek();
268 break;
269 case 't':
270 case 'T':
271 today();
272 break;
273
274 default:
275
276 break;
277 }
278
279 }
280 }
281
282 /***
283 * Increase month.
284 */
285 private void incMonth() {
286 _calendar.add(Calendar.MONTH, 1);
287 intermediateChange();
288 }
289
290 /***
291 * Decrease month.
292 *
293 */
294 private void decMonth() {
295 _calendar.add(Calendar.MONTH, -1);
296 intermediateChange();
297 }
298
299 /***
300 * Add or subtract a number of month.
301 *
302 * @param count number of month to add/substract
303 */
304 private void rollMonth(int count) {
305 _calendar.add(Calendar.MONTH, count);
306 intermediateChange();
307 }
308
309 /***
310 * Increase day.
311 *
312 */
313 private void incDay() {
314 _calendar.add(Calendar.DAY_OF_MONTH, 1);
315 intermediateChange();
316 }
317
318 /***
319 * Decrease day.
320 *
321 */
322 private void decDay() {
323 _calendar.add(Calendar.DAY_OF_MONTH, -1);
324 intermediateChange();
325 }
326
327 /***
328 * Add or substract a number of days.
329 *
330 * @param count number of days
331 */
332 private void rollDay(int count) {
333 _calendar.add(Calendar.DAY_OF_MONTH, count);
334 intermediateChange();
335 }
336
337 /***
338 * Iincrease week.
339 *
340 */
341 private void incWeek() {
342 _calendar.add(Calendar.DAY_OF_MONTH, 7);
343 intermediateChange();
344 }
345
346 /***
347 * Decrease week.
348 *
349 */
350 private void decWeek() {
351 _calendar.add(Calendar.DAY_OF_MONTH, -7);
352 intermediateChange();
353 }
354
355 /***
356 * Set the selected date to today.
357 *
358 */
359 private void today() {
360 setDate(new Date());
361 fireIntermediateChange(getDate());
362 }
363
364 /***
365 * intermediate change: update monthlabel etc.
366 */
367 private void intermediateChange() {
368 updateMonthLabel();
369 redraw();
370 fireIntermediateChange(getDate());
371 forceFocus();
372 }
373
374 /***
375 * Set the currently selected date. A value of <code>null</code> will be transformed to the current date.
376 *
377 * @param date Date to be displayed
378 */
379 public void setDate(Date date) {
380
381 if (date == null) {
382 date = new Date();
383 }
384 if (!date.equals(_date)) {
385 _date = date;
386 _calendar.setTime(_date);
387 updateMonthLabel();
388 redraw();
389 }
390 }
391
392 /***
393 * Get the selected Date.
394 *
395 * @return the currently selected date.
396 */
397 public Date getDate() {
398 _date = _calendar.getTime();
399 return _date;
400 }
401
402 /***
403 * {@inheritDoc} Also redraws the grid.
404 */
405 public void redraw() {
406 super.redraw();
407 _dayGrid.redraw();
408 }
409
410 /***
411 * Create the controls that compose the datechooserpanel.
412 */
413 private void createControls() {
414 GridLayout gridLayout = new GridLayout();
415 gridLayout.numColumns = 3;
416 setLayout(gridLayout);
417
418
419 _decMonthButton = new Button(this, SWT.ARROW | SWT.LEFT);
420 GridData gd = new GridData();
421 _decMonthButton.setLayoutData(gd);
422 _decMonthButton.addSelectionListener(new SelectionAdapter() {
423
424 public void widgetSelected(SelectionEvent arg0) {
425 decMonth();
426 }
427
428 });
429
430 _monthLabel = new Label(this, SWT.CENTER);
431 _monthLabel.setText(getMonthText());
432 gd = new GridData(GridData.FILL_HORIZONTAL);
433 _monthLabel.setLayoutData(gd);
434 _monthLabel.setBackground(getBackground());
435
436 _incMonthButton = new Button(this, SWT.ARROW | SWT.RIGHT);
437 gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
438 _incMonthButton.setLayoutData(gd);
439 _incMonthButton.addSelectionListener(new SelectionAdapter() {
440
441 public void widgetSelected(SelectionEvent arg0) {
442 incMonth();
443 }
444 });
445
446
447 _dayGrid = new DayGrid(this, SWT.NULL);
448 gd = new GridData(GridData.FILL_BOTH);
449 gd.horizontalSpan = 3;
450 _dayGrid.setLayoutData(gd);
451 _dayGrid.addMouseListener(this);
452 _dayGrid.setBackground(getBackground());
453
454
455 _todayLabel = new Label(this, SWT.NULL);
456 gd = new GridData(GridData.FILL_HORIZONTAL);
457 gd.horizontalSpan = 3;
458 _todayLabel.setLayoutData(gd);
459 _todayLabel.setBackground(getBackground());
460
461
462 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, _locale);
463 _todayLabel.setText(df.format(new Date()));
464
465 _todayLabel.addMouseListener(new MouseAdapter() {
466 @Override
467 public void mouseDown(MouseEvent e) {
468 today();
469 }
470 });
471
472 }
473
474 /***
475 * Upate the month label.
476 *
477 */
478 private void updateMonthLabel() {
479 _monthLabel.setText(getMonthText());
480 }
481
482 /***
483 * Assemble text for the month label (month + year).
484 *
485 * @return text for the label
486 */
487 private String getMonthText() {
488 int month = _calendar.get(Calendar.MONTH);
489 int year = _calendar.get(Calendar.YEAR);
490 String monthShort = _dateFormatSymbols.getShortMonths()[month];
491 return monthShort + " " + year;
492 }
493
494 /***
495 * The DayGrid is a private member class extending Canvas. It draws the grid of days and the headings. Whenever the
496 * date in the surrounding DateChooserPanel is changed the method <code>updateInternals</code> has to be called to
497 * update all calculated fields.
498 *
499 * @author Peter Kliem
500 * @version $Id: DateChooserPanel.java 576 2007-10-03 12:57:38Z olk $
501 */
502 class DayGrid extends Canvas {
503
504 /***
505 * Construct a day grid.
506 *
507 * @param parent parent composite
508 * @param style style bits
509 */
510 public DayGrid(Composite parent, int style) {
511 super(parent, style);
512 addPaintListener(new PaintListener() {
513 public void paintControl(PaintEvent event) {
514 onPaint(event);
515 }
516
517 });
518 addListener(SWT.Traverse, new Listener() {
519 public void handleEvent(Event event) {
520 handleTraverse(event);
521 }
522 });
523 addMouseTrackListener(new MouseTrackAdapter() {
524 public void mouseHover(MouseEvent event) {
525
526
527
528
529 Date date = dateForLocation(event.x, event.y);
530 if (date == null) {
531 setToolTipText(null);
532 } else {
533 setToolTipText(getTooltipText(date));
534 }
535
536 }
537
538 });
539 }
540
541 /***
542 * Create the tooltip text for a date.
543 *
544 * @param date date
545 * @return the tooltip text or <code>null</code>
546 */
547 protected String getTooltipText(Date date) {
548 if (date == null) {
549 return null;
550 }
551 if (_dayInformationProvider != null) {
552 String text = _dayInformationProvider.getToolTipText(date);
553 if (text != null) {
554 return text;
555 }
556 }
557 if (_holidayEnumerator != null) {
558 String text = _holidayEnumerator.getDayName(date);
559 if (text != null) {
560 return text;
561 }
562 }
563 return null;
564 }
565
566 /***
567 * {@inheritDoc}
568 */
569 public Point computeSize(int arg0, int arg1, boolean arg2) {
570
571 return new Point(200, 150);
572 }
573
574 void handleTraverse(Event event) {
575
576
577 }
578
579 int width;
580
581 int height;
582
583 int columnWidth;
584
585 int rowHeight;
586
587 int posOfFirstInMonth;
588
589 int daysInMonth;
590
591 int day;
592
593 int month;
594
595 int weekColumnWidth;
596
597 /***
598 * Do any calculations necessary to support drawing.
599 */
600 public void updateInternals() {
601
602 width = getClientArea().width;
603 height = getClientArea().height;
604
605 /***
606 * Calculation of the outline of the month and the day to display. Some of these are only necessary if the
607 * month has changed. This optimization is an open todo. TODO move some calculations
608 */
609 daysInMonth = _calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
610 day = _calendar.get(Calendar.DAY_OF_MONTH);
611 month = _calendar.get(Calendar.MONTH);
612
613
614
615 Calendar tmpCalendar = (Calendar) _calendar.clone();
616 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
617 posOfFirstInMonth = getWeekdayPos(tmpCalendar.get(Calendar.DAY_OF_WEEK));
618
619
620 weekColumnWidth = _displayWeeks ? width / 8 : 0;
621 columnWidth = (width - weekColumnWidth) / 7;
622 rowHeight = height / 7;
623
624 }
625
626 /***
627 * Retrieve the font to use for the weekday labels.
628 *
629 * @param gc GC
630 * @return the font
631 */
632 protected Font getWeekdayFont(GC gc) {
633 if (_weekdayFont == null) {
634 _weekdayFont = new Font(Display.getCurrent(), gc.getFont().getFontData()[0].getName(), gc.getFont()
635 .getFontData()[0].getHeight(), SWT.BOLD);
636 }
637 return _weekdayFont;
638 }
639
640 /***
641 * Retrieve the font to use for the week number labels.
642 *
643 * @param gc GC
644 * @return the font
645 */
646 protected Font getWeekNumberFont(GC gc) {
647 if (_weekNumberFont == null) {
648 _weekNumberFont = new Font(Display.getCurrent(), gc.getFont().getFontData()[0].getName(), (int) (gc
649 .getFont().getFontData()[0].getHeight() * 0.9), SWT.NORMAL);
650 }
651 return _weekNumberFont;
652 }
653
654 /***
655 * The paint method. TODO clipping rect optimizations
656 *
657 * @param event the pain tevent
658 */
659 private void onPaint(PaintEvent event) {
660
661 updateInternals();
662
663
664 GC gc = event.gc;
665 Font oldFont = gc.getFont();
666 gc.setFont(getWeekdayFont(gc));
667
668 for (int weekday = 1; weekday < 8; weekday++) {
669 int pos = getWeekdayPos(weekday);
670 boolean isWeekend = false;
671 if (weekday == Calendar.SATURDAY || weekday == Calendar.SUNDAY) {
672 isWeekend = true;
673 }
674 Color color = isWeekend ? Display.getCurrent().getSystemColor(SWT.COLOR_RED) : Display.getCurrent()
675 .getSystemColor(SWT.COLOR_BLACK);
676 drawCell(gc, pos, 0, getWeekdayString(weekday), color, false);
677 }
678 gc.setFont(oldFont);
679
680 int[] weeks = new int[6];
681 Calendar tmpCalendar = new GregorianCalendar();
682 tmpCalendar.setTime(_date);
683 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
684 tmpCalendar.add(Calendar.DAY_OF_MONTH, -posOfFirstInMonth);
685 for (int dy = 0; dy < 6; dy++) {
686 weeks[dy] = tmpCalendar.get(Calendar.WEEK_OF_YEAR);
687 for (int dx = 0; dx < 7; dx++) {
688 int paintDay = tmpCalendar.get(Calendar.DAY_OF_MONTH);
689 int paintMonth = tmpCalendar.get(Calendar.MONTH);
690
691 Color color = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
692 if (paintMonth != month) {
693 color = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);
694 } else if (_holidayEnumerator != null) {
695 if (_holidayEnumerator.isHoliday(tmpCalendar.getTime())) {
696 color = _holidayColor;
697 } else if (_holidayEnumerator.isSpecialDay(tmpCalendar.getTime())) {
698 color = _specialDayColor;
699 }
700 }
701 Font normalFont = gc.getFont();
702
703 if (_dayInformationProvider != null && _dayInformationProvider.renderBold(tmpCalendar.getTime())) {
704
705 gc.setFont(getWeekdayFont(gc));
706 } else {
707 gc.setFont(normalFont);
708 }
709 drawCell(gc, dx, dy + 1, Integer.toString(paintDay), color, paintDay == day && paintMonth == month);
710 tmpCalendar.add(Calendar.DAY_OF_MONTH, 1);
711 gc.setFont(normalFont);
712 }
713 }
714 oldFont = gc.getFont();
715 gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY));
716 gc.setFont(getWeekNumberFont(gc));
717 for (int dy = 0; dy < 6; dy++) {
718 int y = (dy + 1) * rowHeight;
719 int rx = columnWidth - (int) (columnWidth * 0.2);
720 SwtGraphicsHelper.drawStringRightAlignedVCenter(gc, Integer.toString(weeks[dy]), rx, y + rowHeight / 2);
721 }
722 gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
723
724 gc.setFont(oldFont);
725
726 }
727
728 /***
729 * Draw a cell on the panel.
730 *
731 * @param gc GC
732 * @param pos x
733 * @param row y
734 * @param string String to paint
735 * @param foreground foreground color
736 * @param mark is marked
737 */
738 private void drawCell(GC gc, int pos, int row, String string, Color foreground, boolean mark) {
739 int x = pos * columnWidth + weekColumnWidth;
740 int y = row * rowHeight;
741 Color oldFG = gc.getForeground();
742 Color oldBG = gc.getBackground();
743 gc.setForeground(foreground);
744 if (mark) {
745 gc.setBackground(_markerColor);
746 gc.fillRectangle(x, y, columnWidth - 1, rowHeight - 1);
747 }
748 SwtGraphicsHelper.drawStringCenteredVCenter(gc, string, x, x + columnWidth, y + rowHeight / 2);
749 gc.setForeground(oldFG);
750 gc.setBackground(oldBG);
751 }
752
753 /***
754 * Calculate the day at position x,y.
755 *
756 * @param x x coordinate
757 * @param y ycoordinate
758 * @return the day (first = 1) or -1 if no valid day could be determined
759 */
760 protected int dayForLocation(int x, int y) {
761 int row = y / rowHeight - 1;
762 int col = (x - weekColumnWidth) / columnWidth;
763
764 int day = row * 7 + col + 1;
765 day -= posOfFirstInMonth;
766 if (day < 1 || day > _calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) {
767 day = -1;
768 }
769 return day;
770 }
771
772 /***
773 * Calculate the date for a given location.
774 *
775 * @param x x coordinate
776 * @param y y coordinate
777 * @return the date for the location
778 */
779 protected Date dateForLocation(int x, int y) {
780 int row = y / rowHeight - 1;
781 int col = (x - weekColumnWidth) / columnWidth;
782
783 int day = row * 7 + col + 1;
784 day -= posOfFirstInMonth;
785 Calendar tmpCalendar = new GregorianCalendar();
786 tmpCalendar.setTime(getDate());
787 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1);
788 tmpCalendar.add(Calendar.DAY_OF_MONTH, day - 1);
789 return tmpCalendar.getTime();
790 }
791
792 /***
793 * Retrieve short weekday representation.
794 *
795 * @param weekday coded weekday
796 * @return short string representaion
797 */
798 private String getWeekdayString(int weekday) {
799 return _dateFormatSymbols.getShortWeekdays()[weekday];
800 }
801
802 /***
803 * @param weekday coded weekday (1-7)
804 * @return column position in the day grid (0-6)
805 */
806 private int getWeekdayPos(int weekday) {
807 int firstDay = _calendar.getFirstDayOfWeek();
808 int pos = weekday - firstDay;
809 if (pos < 0) {
810 pos += 7;
811 }
812 return pos;
813 }
814
815 }
816
817 /***
818 * {@inheritDoc}
819 */
820 public void mouseDoubleClick(MouseEvent event) {
821 boolean success = setDateByLocation(event.x, event.y);
822 if (success) {
823 fireDateChosen(getDate());
824 }
825 }
826
827 /***
828 * {@inheritDoc}
829 */
830 public void mouseDown(MouseEvent event) {
831 boolean success = setDateByLocation(event.x, event.y);
832 if (_oneClickSelection && success) {
833 fireDateChosen(getDate());
834 } else {
835 fireIntermediateChange(getDate());
836 }
837 }
838
839 /***
840 * {@inheritDoc}
841 */
842 public void mouseUp(MouseEvent event) {
843
844 }
845
846 /***
847 * Sets the calendar day for a given location. This will succeed if a valid day (i.e. a day in the current month is
848 * selected).
849 *
850 * @param x x coordinate
851 * @param y y coordinate
852 * @return true if a valid day could be selected
853 */
854 protected boolean setDateByLocation(int x, int y) {
855 int day = _dayGrid.dayForLocation(x, y);
856 if (day > 0) {
857 _calendar.set(Calendar.DAY_OF_MONTH, day);
858 _dayGrid.redraw();
859 return true;
860 } else {
861 return false;
862 }
863 }
864
865 /***
866 * Add a DateChooserListener to be informed about changes.
867 *
868 * @param listener the DateChooserListener to be added
869 */
870 public synchronized void addDateChooserListener(IDateChooserListener listener) {
871 if (_listenerList == null) {
872 _listenerList = new Vector<IDateChooserListener>();
873 }
874 _listenerList.add(listener);
875 }
876
877 /***
878 * Remove a DateChooserListener.
879 *
880 * @param listener the DateChooserListener to be removed
881 */
882 public synchronized void remDateChooserListener(IDateChooserListener listener) {
883 if (_listenerList == null) {
884 return;
885 }
886 _listenerList.remove(listener);
887 }
888
889 /***
890 * Inform listeners about a chosing action.
891 *
892 * @param date date chosen
893 */
894 protected void fireDateChosen(Date date) {
895 if (_listenerList != null) {
896 for (IDateChooserListener listener : _listenerList) {
897 listener.dateChosen(date);
898 }
899 }
900 }
901
902 /***
903 * Inform listeners about an intermediate date change.
904 *
905 * @param date date currently selected
906 */
907 protected void fireIntermediateChange(Date date) {
908 if (_listenerList != null) {
909 for (IDateChooserListener listener : _listenerList) {
910 listener.dateIntermediateChange(date);
911 }
912 }
913 }
914
915 /***
916 * Inform listeners about cancellation f the choosing.
917 */
918 protected void fireChoosingCanceled() {
919 if (_listenerList != null) {
920 for (IDateChooserListener listener : _listenerList) {
921 listener.choosingCanceled();
922 }
923 }
924 }
925
926 /***
927 * Retrieve the HolidayEnumerator.
928 *
929 * @return Returns the HolidayEnumerator.
930 */
931 public HolidayEnumerator getHolidayEnumerator() {
932 return _holidayEnumerator;
933 }
934
935 /***
936 * Set the HolidayEnumerator. A value of <code>null</code> is valid meaning no HolidayEnumerator should be used.
937 *
938 * @param holidayEnumerator The HolidayEnumerator to set.
939 */
940 public void setHolidayEnumerator(HolidayEnumerator holidayEnumerator) {
941 _holidayEnumerator = holidayEnumerator;
942 redraw();
943 }
944
945 /***
946 * Retrieve the additional information provider.
947 *
948 * @return the information provider
949 */
950 public IAdditionalDayInformationProvider getAdditionalDayInformationProvider() {
951 return _dayInformationProvider;
952 }
953
954 /***
955 * Set an additional provider for day information.
956 *
957 * @param informationProvider the information provider
958 */
959 public void setAdditionalDayInformationProvider(IAdditionalDayInformationProvider informationProvider) {
960 _dayInformationProvider = informationProvider;
961 redraw();
962 }
963
964 /***
965 * @return true if weeks should be displayed
966 */
967 public boolean isDisplayWeeks() {
968 return _displayWeeks;
969 }
970
971 /***
972 * Set whether a column showing the week of the year should be displayed.
973 *
974 * @param displayWeeks if set to true a column with the number of the week in the year is displayed.
975 */
976 public void setDisplayWeeks(boolean displayWeeks) {
977 _displayWeeks = displayWeeks;
978 redraw();
979 }
980
981 /***
982 * @return true if a single click will select the date
983 */
984 public boolean isOneClickSelection() {
985 return _oneClickSelection;
986 }
987
988 /***
989 * Set whether a single or a double click will select the date.
990 *
991 * @param oneClickSelection if set to true one click will select the date. If set to false the date selection
992 * requires a double click.
993 */
994 public void setOneClickSelection(boolean oneClickSelection) {
995 _oneClickSelection = oneClickSelection;
996 }
997
998 /***
999 * Retrieve the color used for painting the background of the marked day.
1000 *
1001 * @return the marker color
1002 */
1003 public Color getMarkerColor() {
1004 return _markerColor;
1005 }
1006
1007 /***
1008 * Set the color to paint the background of the marked day.
1009 *
1010 * @param markerColor color for the marker
1011 */
1012 public void setMarkerColor(Color markerColor) {
1013 _markerColor = markerColor;
1014 }
1015
1016 /***
1017 * Retrieve the color used for painting the foreground of a holiday.
1018 *
1019 * @return the holiday color
1020 */
1021 public Color getHolidayColor() {
1022 return _holidayColor;
1023 }
1024
1025 /***
1026 * Set the color to paint the foreground of holidays.
1027 *
1028 * @param holidayColor holiday color
1029 */
1030 public void setHolidayColor(Color holidayColor) {
1031 _holidayColor = holidayColor;
1032 }
1033
1034 /***
1035 * Retrieve the color used for painting the foreground of a special day.
1036 *
1037 * @return the special day color
1038 */
1039 public Color getSpecialDayColor() {
1040 return _specialDayColor;
1041 }
1042
1043 /***
1044 * Set the color to paint the foreground of special days.
1045 *
1046 * @param specialDayColor color for special days
1047 */
1048 public void setSpecialDayColor(Color specialDayColor) {
1049 _specialDayColor = specialDayColor;
1050 }
1051 }