1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.cosylab.gui.components;
21
22 import java.awt.BorderLayout;
23 import java.awt.CardLayout;
24 import java.awt.Color;
25 import java.awt.Component;
26 import java.awt.Dimension;
27 import java.awt.Font;
28 import java.awt.Graphics;
29 import java.awt.Graphics2D;
30 import java.awt.GridBagConstraints;
31 import java.awt.GridBagLayout;
32 import java.awt.Point;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.ItemEvent;
36 import java.awt.event.ItemListener;
37 import java.awt.event.KeyEvent;
38 import java.awt.event.KeyListener;
39 import java.awt.event.MouseEvent;
40 import java.awt.event.MouseListener;
41 import java.awt.event.WindowAdapter;
42 import java.awt.event.WindowEvent;
43 import java.beans.PropertyChangeEvent;
44 import java.beans.PropertyChangeListener;
45 import java.text.DateFormatSymbols;
46 import java.util.ArrayList;
47 import java.util.Calendar;
48 import java.util.Date;
49 import java.util.GregorianCalendar;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Timer;
53 import java.util.TimerTask;
54
55 import javax.swing.DefaultComboBoxModel;
56 import javax.swing.JComboBox;
57 import javax.swing.JComponent;
58 import javax.swing.JFrame;
59 import javax.swing.JLabel;
60 import javax.swing.JList;
61 import javax.swing.JMenuItem;
62 import javax.swing.JPanel;
63 import javax.swing.JPopupMenu;
64 import javax.swing.ListCellRenderer;
65 import javax.swing.SwingUtilities;
66 import javax.swing.border.LineBorder;
67 import javax.swing.event.ListSelectionEvent;
68 import javax.swing.plaf.basic.BasicComboBoxEditor;
69
70
71 import com.cosylab.gui.components.util.ColorHelper;
72 import com.cosylab.gui.components.util.CosyUIElements;
73 import com.cosylab.gui.components.util.PaintHelper;
74 import com.cosylab.util.DateSpan;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public class DateSpanSelector extends JPanel
95 {
96 private static final long serialVersionUID = -501052522043801432L;
97 private static final Color EXTENDED_SELECTION_COLOR = Color.red;
98
99 private class YearButton extends ArrowButton {
100
101 private static final long serialVersionUID = -6687714559622460070L;
102 private int orientation;
103 public YearButton(int orientation){
104 super(orientation);
105 this.orientation = orientation;
106 }
107 @Override
108 public void paintComponent(Graphics g) {
109 ((Graphics2D)g).addRenderingHints(PaintHelper.getAntialiasingHints());
110 super.paintComponent(g);
111
112 int maxHeight = getBounds().height;
113 int maxWidth = getBounds().width;
114 int top=1;
115 int bottom=1;
116 int left=1;
117 int right=1;
118 top = Math.min(maxWidth, maxHeight) / 4;
119 bottom = Math.min(maxWidth, maxHeight) / 4;
120 left = Math.min(maxWidth, maxHeight) / 4;
121 right = Math.min(maxWidth, maxHeight) / 4;
122
123 g.setColor(getForeground());
124 if (orientation == RIGHT) {
125 int middle = 2*(maxWidth - right)/3;
126 middle = left+(maxWidth-right-left)/2;
127 int[] ys = { top, maxHeight / 2, maxHeight / 2, top, maxHeight / 2, maxHeight - bottom, maxHeight / 2,maxHeight / 2, maxHeight - bottom};
128 int[] xs = { left, middle, middle, middle, maxWidth-right, middle, middle, middle, left };
129 g.fillPolygon(xs, ys, 9);
130 } else if (orientation == LEFT) {
131
132 int middle = 2*(maxWidth - right)/3;
133 middle = left+(maxWidth-right-left)/2;
134 int[] ys = { top, maxHeight / 2, maxHeight / 2, top, maxHeight / 2, maxHeight - bottom, maxHeight / 2,maxHeight / 2, maxHeight - bottom};
135 int[] xs = { maxWidth-right, middle, middle, middle, left, middle, middle, middle, maxWidth-right };
136 g.fillPolygon(xs, ys, 9);
137 }
138
139 }
140 }
141
142
143
144
145 private class DatePanel extends JComponent implements ItemListener,
146 MouseListener, KeyListener
147 {
148 private static final long serialVersionUID = 3649761076701751548L;
149
150
151
152
153 private class DateCell extends ResizableTextLabel
154 {
155 private static final long serialVersionUID = -6558819543510561495L;
156 private int date;
157 private boolean adjustFont;
158 private boolean paintForward;
159 private boolean paintBackward;
160
161
162
163
164 public DateCell()
165 {
166 super(" ");
167 setResizable(true);
168 setColumns(2);
169 setOpaque(true);
170 setHorizontalAlignment(JLabel.CENTER);
171 setMinimumSize(new Dimension(30, 10));
172 setEnhanced(true);
173 setFocusable(true);
174 }
175
176
177
178
179
180
181
182
183
184 public void setDate(int newDate)
185 {
186 if ((newDate < 1) || (newDate > 31)) {
187 throw new IllegalArgumentException(
188 "Date value out of bounds: " + newDate);
189 }
190
191 date = newDate;
192
193 if (newDate < 10) {
194 setText(" " + String.valueOf(newDate));
195 } else {
196 setText(String.valueOf(newDate));
197 }
198 }
199
200
201
202
203
204
205 public int getDate()
206 {
207 return date;
208 }
209 protected void resize()
210 {
211 if (adjustFont){
212 super.resize();
213 unifyFontSize();
214 }
215 }
216
217 public boolean isAdjustFont() {
218 return adjustFont;
219 }
220
221 public void setAdjustFont(boolean adjustFont) {
222 this.adjustFont = adjustFont;
223 }
224
225 @Override
226 protected void paintComponent(Graphics g) {
227 super.paintComponent(g);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 int maxHeight = getBounds().height;
265 int maxWidth = getBounds().width/4;
266
267 if ((isPaintForward())){
268 int refX = (3*getBounds().width)/4;
269 int refY = 0;
270 int[] ys = { refY, refY+(maxHeight-refY)/2, refY+maxHeight};
271 int[] xs = { refX, refX+maxWidth, refX};
272 g.setColor(EXTENDED_SELECTION_COLOR);
273 g.fillPolygon(xs, ys, 3);
274 }
275 else if (isPaintBackward()){
276 int refX = 0;
277 int refY = 0;
278 int[] ys = {refY+0, refY+maxHeight, refY+maxHeight/2 };
279 int[] xs = {refX+maxWidth, refX+maxWidth, refX+0 };
280 g.setColor(EXTENDED_SELECTION_COLOR);
281 g.fillPolygon(xs, ys, 3);
282 }
283 }
284
285 public boolean isPaintForward() {
286 return paintForward;
287 }
288
289 public void setPaintForward(boolean paintForward) {
290 this.paintForward = paintForward;
291 }
292
293 public boolean isPaintBackward() {
294 return paintBackward;
295 }
296
297 public void setPaintBackward(boolean paintBackward) {
298 this.paintBackward = paintBackward;
299 }
300 }
301 private class DayNameCell extends ResizableTextLabel
302 {
303 private static final long serialVersionUID = -6558819541235431495L;
304 private boolean adjustFont;
305
306 public DayNameCell(String string) {
307 super(string);
308 }
309
310 protected void resize()
311 {
312 if (adjustFont){
313 super.resize();
314 unifyFontSize();
315 }
316 }
317
318 public boolean isAdjustFont() {
319 return adjustFont;
320 }
321
322 public void setAdjustFont(boolean adjustFont) {
323 this.adjustFont = adjustFont;
324 }
325 }
326
327 private Calendar currentDate;
328 private Calendar displayMonthDate;
329 private Calendar selectionFinishDate;
330 private Calendar selectionStartDate;
331
332
333 private Color dayNameBackground = new Color(218,226,234);
334
335 private Color dayNameForeground = ColorHelper.getControlDarkShadow();
336 private Color othersForeground = ColorHelper.getControlDarkShadow();
337
338 private Color sundayBackground = new Color(218,226,234);
339 private Color sundayForeground = ColorHelper.getControlText();
340 private Color sundaySelection = ColorHelper.getCosyControlShadow();
341 private List<DateCell> dateCells;
342 private List<DayNameCell> dayNameCells;
343
344 private Timer switchTimer = null;
345 private boolean selecting;
346 private int switching;
347
348
349
350
351 public DatePanel()
352 {
353 super();
354 setBackground(ColorHelper.getWindowBackground());
355 currentDate = GregorianCalendar.getInstance();
356 displayMonthDate = GregorianCalendar.getInstance();
357 displayMonthDate.set(Calendar.DATE, 15);
358 normalizeToMiddleOfDay(displayMonthDate);
359 populateDateList();
360 pupulateDayNamesList();
361 init();
362 }
363
364 private void pupulateDayNamesList() {
365 if (dayNameCells == null) {
366 dayNameCells = new ArrayList<DayNameCell>();
367 }
368 DayNameCell dateLabel = null;
369 for (int i = 0; i < 7; i++) {
370 dateLabel = new DayNameCell(DAYS[i]);
371 if (i==0) dateLabel.setAdjustFont(true);
372 dateLabel.setOpaque(true);
373 dateLabel.setBackground(dayNameBackground);
374 dateLabel.setForeground(dayNameForeground);
375 dateLabel.setResizable(true);
376 dateLabel.setColumns(3);
377 dateLabel.setHorizontalAlignment(JLabel.CENTER);
378 Font f = dateLabel.getFont();
379 dateLabel.setFont(f.deriveFont(f.getStyle() ^ Font.BOLD));
380 dayNameCells.add(dateLabel);
381 }
382
383 }
384
385
386
387
388 public void init()
389 {
390 removeAll();
391 setLayout(new CosyUIElements.FillingGridLayout(0, 7));
392 setOpaque(true);
393
394
395
396 for (int i = 0; i < 7; i++) {
397 add(dayNameCells.get(i));
398 }
399
400
401 for (int i = 0; i < 42; i++) {
402 add(dateCells.get(i));
403 }
404 }
405
406
407
408
409
410
411
412
413
414 public void itemStateChanged(ItemEvent e)
415 {
416 Calendar monthDate = (Calendar)((JComboBox)e.getSource())
417 .getSelectedItem();
418
419 if ((displayMonthDate.get(Calendar.YEAR) == monthDate.get(
420 Calendar.YEAR))
421 && (displayMonthDate.get(Calendar.MONTH) == monthDate.get(
422 Calendar.MONTH))) {
423 return;
424 }
425
426 displayMonthDate.set(Calendar.YEAR, monthDate.get(Calendar.YEAR));
427 displayMonthDate.set(Calendar.MONTH, monthDate.get(Calendar.MONTH));
428
429 if (selecting) {
430 ensureSelection();
431 selectionFinishDate.set(Calendar.YEAR,
432 monthDate.get(Calendar.YEAR));
433 selectionFinishDate.set(Calendar.MONTH,
434 monthDate.get(Calendar.MONTH));
435 }
436
437 populateDateList();
438 }
439
440
441
442
443 public void keyPressed(KeyEvent e)
444 {
445 if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
446 selecting = true;
447
448 return;
449 }
450
451 int date = ((DateCell)e.getSource()).getDate();
452
453 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
454 displayMonthDate = Calendar.getInstance();
455 normalizeToMiddleOfDay(displayMonthDate);
456 date = displayMonthDate.get(Calendar.DAY_OF_MONTH);
457 } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
458 date++;
459 } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
460 date--;
461 } else if (e.getKeyCode() == KeyEvent.VK_UP) {
462 date -= 7;
463 } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
464 date += 7;
465 } else {
466 return;
467 }
468
469 if (date > displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)) {
470 date = date
471 - displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH);
472 displayMonthDate.add(Calendar.MONTH, 1);
473 } else if (date < 1) {
474 displayMonthDate.add(Calendar.MONTH, -1);
475 date = displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)
476 + date;
477 }
478
479 if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK) {
480 ensureSelection();
481 selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
482 displayMonthDate.get(Calendar.MONTH), date);
483 } else {
484 ensureSelection();
485 selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
486 displayMonthDate.get(Calendar.MONTH), date);
487 selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
488 displayMonthDate.get(Calendar.MONTH), date);
489
490 selectionStopped();
491 }
492
493 Calendar datec = createCopy(displayMonthDate);
494 datec.set(Calendar.DAY_OF_MONTH, 1);
495 normalizeToBeginningOfDay(datec);
496 monthCombo.setSelectedItem(datec);
497
498 populateDateList();
499 }
500
501
502
503
504 public void keyReleased(KeyEvent arg0)
505 {
506 if (arg0.getKeyCode() == KeyEvent.VK_SHIFT) {
507 selectionStopped();
508 }
509 }
510
511
512
513
514 public void keyTyped(KeyEvent arg0)
515 {
516 }
517
518
519
520
521
522
523
524
525
526
527 public void mouseClicked(MouseEvent e)
528 {
529 if (e.getButton()== MouseEvent.BUTTON3){
530 getPopup().show(e.getComponent(),
531 e.getX(), e.getY());
532 return;
533 }
534 if (!this.isEnabled()) return;
535 int date = ((DateCell)e.getSource()).getDate();
536 int monthOffset = 0;
537
538 if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
539 monthOffset++;
540 } else if ((date > 15) && !((DateCell)e.getSource()).isEnabled()) {
541 monthOffset--;
542 }
543
544 ensureSelection();
545 selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
546 displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
547 selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
548 displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
549
550 selectionStopped();
551 populateDateList();
552 }
553
554
555
556
557
558
559
560
561 public void mouseEntered(MouseEvent e)
562 {
563 if (switching != 0) {
564 switchTimer.cancel();
565 switching = 0;
566 }
567
568 if (selecting) {
569 int date = ((DateCell)e.getSource()).getDate();
570 int monthOffset = 0;
571
572 if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
573 monthOffset++;
574 } else if ((date > 15)
575 && !((DateCell)e.getSource()).isEnabled()) {
576 monthOffset--;
577 }
578
579 ensureSelection();
580 selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
581 displayMonthDate.get(Calendar.MONTH) + monthOffset, date,
582 12, 0, 0);
583 populateDateList();
584 }
585 }
586
587
588
589
590
591
592
593
594
595
596 public void mouseExited(MouseEvent e)
597 {
598 if (selecting) {
599 Component eventSource = (Component)e.getSource();
600 Point eventPoint = e.getPoint();
601 int offset = eventSource.getWidth() + 1;
602 eventPoint = SwingUtilities.convertPoint(eventSource,
603 eventPoint, this);
604
605 if (eventPoint.x >= ((getLocation().x + getWidth()) - offset)) {
606 switching = 1;
607 } else if (eventPoint.x <= (getLocation().x + offset)) {
608 switching = -1;
609 }
610
611 if (switching != 0) {
612 switchTimer = new Timer();
613 switchTimer.schedule(new TimerTask() {
614 public void run()
615 {
616 if (selecting && (switching != 0)) {
617 switchMonths();
618 }
619 }
620
621 private void switchMonths()
622 {
623 displayMonthDate.add(Calendar.MONTH, switching);
624 ensureSelection();
625 selectionFinishDate.add(Calendar.MONTH,
626 switching);
627 populateDateList();
628
629 Calendar date = createCopy(displayMonthDate);
630 date.set(Calendar.DAY_OF_MONTH, 1);
631 normalizeToBeginningOfDay(date);
632 monthCombo.setSelectedItem(date);
633 monthCombo.repaint();
634 }
635 }, 300, 400);
636 }
637 }
638 }
639
640
641
642
643
644
645
646
647
648 public void mousePressed(MouseEvent e)
649 {
650 if (e.getButton()== MouseEvent.BUTTON3){
651 return;
652 }
653 if (!this.isEnabled()) return;
654 selecting = true;
655
656 int date = ((DateCell)e.getSource()).getDate();
657 int monthOffset = 0;
658
659 if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
660 monthOffset++;
661 } else if ((date > 15) && !((DateCell)e.getSource()).isEnabled()) {
662 monthOffset--;
663 }
664
665 ensureSelection();
666 selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
667 displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
668 selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
669 displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
670
671 populateDateList();
672 }
673
674
675
676
677
678
679
680
681
682
683 public void mouseReleased(MouseEvent e)
684 {
685 if (e.getButton()== MouseEvent.BUTTON3){
686 return;
687 }
688 if (!this.isEnabled()) return;
689 selectionStopped();
690 }
691
692 private void populateDateList()
693 {
694 currentDate = GregorianCalendar.getInstance();
695 DateCell dateCell = null;
696
697 if (dateCells == null) {
698 dateCells = new ArrayList<DateCell>();
699
700 for (int i = 0; i < 42; i++) {
701 dateCell = new DateCell();
702 if (i==0) dateCell.setAdjustFont(true);
703 dateCell.addMouseListener(this);
704 dateCell.addKeyListener(this);
705 dateCells.add(dateCell);
706 }
707 }
708
709 int dayInMonth = displayMonthDate.get(Calendar.DAY_OF_MONTH);
710 displayMonthDate.add(Calendar.DATE, 1 - dayInMonth);
711
712 int firstDayOfMonth = displayMonthDate.get(Calendar.DAY_OF_WEEK)
713 - 2;
714
715 if (firstDayOfMonth < 0) {
716 firstDayOfMonth += 7;
717 }
718
719 int lastDayOfMonth = (firstDayOfMonth
720 + displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)) - 1;
721 displayMonthDate.add(Calendar.DATE, -firstDayOfMonth);
722 for (int i = 0; i < 42; i++) {
723 dateCell = dateCells.get(i);
724 dateCell.setEnabled(true);
725 dateCell.setDate(displayMonthDate.get(Calendar.DAY_OF_MONTH));
726
727 if ((i < firstDayOfMonth) || (i > lastDayOfMonth)) {
728 dateCell.setForeground(othersForeground);
729 dateCell.setEnabled(false);
730 } else {
731 dateCell.setForeground(getForeground());
732 }
733
734 if (displayMonthDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
735 dateCell.setBackground(sundayBackground);
736 dateCell.setForeground(sundayForeground);
737 } else {
738 dateCell.setBackground(getBackground());
739 }
740
741 if ((displayMonthDate.get(Calendar.YEAR) == currentDate.get(
742 Calendar.YEAR))
743 && (displayMonthDate.get(Calendar.MONTH) == currentDate.get(
744 Calendar.MONTH))
745 && (displayMonthDate.get(Calendar.DATE) == currentDate.get(
746 Calendar.DATE))) {
747 dateCell.setBorder(new LineBorder(Color.BLACK));
748 } else {
749 dateCell.setBorder(null);
750 }
751
752 if (selectionFinishDate!=null && selectionStartDate!=null && (((displayMonthDate.getTimeInMillis() >= selectionStartDate
753 .getTimeInMillis())
754 && (displayMonthDate.getTimeInMillis() <= selectionFinishDate
755 .getTimeInMillis()))
756 || ((displayMonthDate.getTimeInMillis() <= selectionStartDate
757 .getTimeInMillis())
758 && (displayMonthDate.getTimeInMillis() >= selectionFinishDate
759 .getTimeInMillis())))) {
760 if (displayMonthDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
761 dateCell.setBackground(sundaySelection);
762 } else {
763 dateCell.setBackground(ColorHelper.getTextHighlight());
764 }
765 }
766
767 if (displayMonthDate.equals(selectionFinishDate)) {
768 if (!monthCombo.isPopupVisible()) {
769 dateCell.requestFocusInWindow();
770 }
771 }
772
773
774 if (selectionFinishDate!=null && selectionStartDate!=null){
775
776
777 if (i==41
778 && selectionStartDate.getTimeInMillis()<=displayMonthDate.getTimeInMillis()
779 && selectionFinishDate.getTimeInMillis()>displayMonthDate.getTimeInMillis()){
780 dateCell.setPaintForward(true);
781 } else
782 dateCell.setPaintForward(false);
783 if (i==0
784 && selectionStartDate.getTimeInMillis()<displayMonthDate.getTimeInMillis()
785 && selectionFinishDate.getTimeInMillis()>=displayMonthDate.getTimeInMillis()){
786 dateCell.setPaintBackward(true);
787 } else
788 dateCell.setPaintBackward(false);
789 }
790
791
792 displayMonthDate.add(Calendar.DATE, 1);
793 }
794
795 displayMonthDate.add(Calendar.DATE,
796 (firstDayOfMonth + dayInMonth) - 1 - 42);
797 }
798
799
800
801 private void selectionStopped()
802 {
803 selecting = false;
804
805 Calendar start = null;
806 Calendar finish = null;
807
808 ensureSelection();
809 if (selectionStartDate.getTimeInMillis() <= selectionFinishDate
810 .getTimeInMillis()) {
811 start = createCopy(selectionStartDate);
812 finish = createCopy(selectionFinishDate);
813 } else {
814 start = createCopy(selectionFinishDate);
815 finish = createCopy(selectionStartDate);
816 }
817
818 normalizeToBeginningOfDay(start);
819 normalizeToEndOfDay(finish);
820 setSelectedDateSpan(new DateSpan(start.getTime(), finish.getTime()));
821 }
822
823 private void clearSelection() {
824 selectionStartDate=null;
825 selectionFinishDate=null;
826 }
827
828 private void ensureSelection() {
829 if (selectionStartDate==null) {
830 selectionStartDate = GregorianCalendar.getInstance();
831 normalizeToMiddleOfDay(selectionStartDate);
832 }
833
834 if (selectionFinishDate==null) {
835 selectionFinishDate = GregorianCalendar.getInstance();
836 normalizeToMiddleOfDay(selectionFinishDate);
837 }
838 }
839
840 @Override
841 public void setEnabled(boolean enabled) {
842 super.setEnabled(enabled);
843 for (Iterator<DateCell> iterator = dateCells.iterator(); iterator.hasNext();) {
844 DateCell cell = iterator.next();
845 cell.setEnabled(enabled);
846
847 }
848 }
849
850 protected void unifyFontSize() {
851 if (dayNameCells == null || dateCells == null) return;
852
853
854 Font fn= null;
855 for (Iterator<DayNameCell> iterator = dayNameCells.iterator(); iterator.hasNext();) {
856 DayNameCell cell = iterator.next();
857 if (fn==null)fn=cell.getFont();
858 cell.setFont(fn);
859 }
860
861 Font fd = null;
862 for (Iterator<DateCell> iterator = dateCells.iterator(); iterator.hasNext();) {
863 DateCell cell = iterator.next();
864 if (fd==null)fd=cell.getFont();
865 cell.setFont(fd);
866 }
867
868 }
869 }
870
871
872
873
874
875 private class MonthCombo extends SimpleComboBox
876 {
877
878 private static final long serialVersionUID = -848887269904982102L;
879
880
881
882 private class MonthCellRenderer extends JLabel
883 implements ListCellRenderer
884 {
885 private static final long serialVersionUID = -7240298232411247122L;
886
887
888
889
890 public MonthCellRenderer()
891 {
892 super();
893 setHorizontalAlignment(JLabel.CENTER);
894 setOpaque(true);
895 setEditor(new BasicComboBoxEditor());
896 }
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912 public Component getListCellRendererComponent(JList list,
913 Object value, int index, boolean isSelected,
914 boolean cellHasFocus)
915 {
916 if (isSelected) {
917 setBackground(ColorHelper.getControl());
918 } else {
919 setBackground(ColorHelper.getControlHighlight());
920 }
921
922 Calendar date = (Calendar)value;
923 String name = MONTHS[date.get(Calendar.MONTH)] + " "
924 + date.get(Calendar.YEAR);
925 setText(name);
926 return this;
927 }
928 }
929
930
931
932
933 public MonthCombo()
934 {
935 super();
936 setStyle(Style.SWITCH_STYLE_POPUP_ENABLED);
937 setMaximumRowCount(12);
938 setRenderer(new MonthCellRenderer());
939 setBorder(null);
940 populateMonthList();
941 addMouseListener(new MouseListener(){
942 public void mouseClicked(MouseEvent e) {
943 if (e.getButton()==MouseEvent.BUTTON3){
944 getPopup().show(e.getComponent(),
945 e.getX(), e.getY());
946 }
947 }
948 public void mouseEntered(MouseEvent e) {
949 }
950 public void mouseExited(MouseEvent e) {
951 }
952 public void mousePressed(MouseEvent e) {
953 }
954 public void mouseReleased(MouseEvent e) {
955
956 }});
957 }
958
959 private void populateMonthList()
960 {
961 for (int i = 1950; i <= 2050; i++) {
962 for (int j = 1; j <= 12; j++) {
963 ((DefaultComboBoxModel)getModel()).addElement(new GregorianCalendar(
964 i, j, 1));
965 }
966 }
967
968 Calendar date = Calendar.getInstance();
969 date.set(Calendar.DAY_OF_MONTH, 1);
970 normalizeToBeginningOfDay(date);
971 setSelectedItem(date);
972 }
973 }
974
975
976 public static final String[] DAYS;
977
978 public static final String[] MONTHS;
979
980 static {
981 String[] data = new DateFormatSymbols().getShortWeekdays();
982 DAYS = new String[]{data[Calendar.MONDAY],data[Calendar.TUESDAY],
983 data[Calendar.WEDNESDAY],data[Calendar.THURSDAY],data[Calendar.FRIDAY],
984 data[Calendar.SATURDAY],data[Calendar.SUNDAY]};
985 data = new DateFormatSymbols().getMonths();
986 MONTHS = new String[]{
987 data[Calendar.JANUARY],data[Calendar.FEBRUARY],data[Calendar.MARCH],
988 data[Calendar.APRIL],data[Calendar.MAY],data[Calendar.JUNE],
989 data[Calendar.JULY],data[Calendar.AUGUST],data[Calendar.SEPTEMBER],
990 data[Calendar.OCTOBER],data[Calendar.NOVEMBER],data[Calendar.DECEMBER]};
991 }
992
993 private Date selectedDate;
994 private DatePanel datePanel;
995 private DateSpan selectedDateSpan;
996 private MonthCombo monthCombo;
997 private SimpleButton leftYear = null;
998 private SimpleButton rightYear = null;
999 private JPopupMenu popup = null;
1000
1001
1002
1003
1004 public DateSpanSelector()
1005 {
1006 monthCombo = new MonthCombo();
1007
1008 datePanel = new DatePanel();
1009
1010 monthCombo.addItemListener(datePanel);
1011
1012 setPreferredSize(new Dimension(154, 154));
1013 setOpaque(true);
1014 setBackground(ColorHelper.getControl());
1015 setBorder(CosyUIElements.getPlainBorder(false));
1016
1017 setLayout(new GridBagLayout());
1018
1019 JPanel monthPanel = new JPanel(new BorderLayout());
1020
1021 SimpleButton leftYear = getLeftYearButton();
1022 SimpleButton rightYear = getRightYearButton();
1023
1024
1025 monthPanel.add(monthCombo,BorderLayout.CENTER);
1026 monthPanel.add(leftYear,BorderLayout.WEST);
1027 monthPanel.add(rightYear,BorderLayout.EAST);
1028
1029 GridBagConstraints constraints = new GridBagConstraints();
1030 constraints.fill = GridBagConstraints.BOTH;
1031 constraints.gridx = 1;
1032 constraints.gridy = 0;
1033 constraints.weightx = 1;
1034 constraints.weighty = 0;
1035 constraints.anchor = GridBagConstraints.CENTER;
1036 add(monthPanel, constraints);
1037 constraints.gridx = 0;
1038 constraints.gridy = 1;
1039 constraints.weightx = 1;
1040 constraints.weighty = 1;
1041 constraints.gridwidth = 3;
1042 constraints.anchor = GridBagConstraints.CENTER;
1043 add(datePanel, constraints);
1044
1045
1046
1047
1048 }
1049
1050 private SimpleButton getLeftYearButton() {
1051 if (leftYear == null){
1052 leftYear = new YearButton(ArrowButton.LEFT);
1053 leftYear.addActionListener(new ActionListener() {
1054 public void actionPerformed(ActionEvent e){
1055 if (monthCombo.getSelectedIndex() > 12) {
1056 monthCombo.setSelectedIndex(monthCombo
1057 .getSelectedIndex() - 12);
1058 }
1059 }
1060 });
1061
1062 leftYear.setBackground(ColorHelper.getControl());
1063 leftYear.setBorder(null);
1064 leftYear.setPressedBorder(null);
1065 }
1066 return leftYear;
1067 }
1068
1069 private SimpleButton getRightYearButton() {
1070 if (rightYear == null){
1071 rightYear = new YearButton(ArrowButton.RIGHT);
1072 rightYear.addActionListener(new ActionListener() {
1073 public void actionPerformed(ActionEvent e){
1074 if (monthCombo.getSelectedIndex() < (monthCombo
1075 .getItemCount() - 13)) {
1076 monthCombo.setSelectedIndex(monthCombo
1077 .getSelectedIndex() + 12);
1078 }
1079 }
1080 });
1081 rightYear.setBackground(ColorHelper.getControl());
1082 rightYear.setBorder(null);
1083 rightYear.setPressedBorder(null);
1084 }
1085 return rightYear;
1086 }
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097 public static boolean isSameDate(Date date1, Date date2)
1098 {
1099 Calendar c1 = new GregorianCalendar();
1100 Calendar c2 = new GregorianCalendar();
1101 c1.setTime(date1);
1102 c2.setTime(date2);
1103
1104 return (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
1105 && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR));
1106
1107
1108
1109 }
1110
1111 public void setSelectedDateSpan(DateSpan newSpan) {
1112 setSelectedDateSpan(newSpan,false);
1113 }
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 public void setSelectedDateSpan(DateSpan newSpan, boolean shouldScroll)
1126 {
1127 DateSpan oldSpan = selectedDateSpan;
1128 Date oldDate = selectedDate;
1129
1130 if (((newSpan != null) && newSpan.equals(oldSpan))
1131 || (newSpan == null && oldSpan == null)) {
1132 return;
1133 }
1134
1135
1136
1137
1138
1139
1140 selectedDateSpan = newSpan;
1141
1142 if (newSpan!=null && isSameDate(newSpan.getStartingDate(), newSpan.getFinishingDate())) {
1143 selectedDate = newSpan.getFinishingDate();
1144 } else {
1145 selectedDate = null;
1146 }
1147
1148 if (newSpan==null) {
1149 datePanel.clearSelection();
1150 } else {
1151 datePanel.ensureSelection();
1152 datePanel.selectionStartDate.setTime(newSpan.getStartingDate());
1153 normalizeToMiddleOfDay(datePanel.selectionStartDate);
1154 datePanel.selectionFinishDate.setTime(newSpan.getFinishingDate());
1155 normalizeToMiddleOfDay(datePanel.selectionFinishDate);
1156 }
1157
1158 if (shouldScroll) {
1159 Calendar finish = GregorianCalendar.getInstance();
1160 if (newSpan != null) {
1161 finish.setTime(newSpan.getFinishingDate());
1162 }
1163 datePanel.displayMonthDate.set(Calendar.YEAR, finish.get(Calendar.YEAR));
1164 datePanel.displayMonthDate.set(Calendar.MONTH, finish.get(Calendar.MONTH));
1165 Calendar date = createCopy(datePanel.displayMonthDate);
1166 date.set(Calendar.DAY_OF_MONTH, 1);
1167 normalizeToBeginningOfDay(date);
1168 monthCombo.setSelectedItem(date);
1169 monthCombo.repaint();
1170 }
1171
1172 datePanel.populateDateList();
1173
1174 firePropertyChange("selectedDateSpan", oldSpan, selectedDateSpan);
1175 firePropertyChange("selectedDate", oldDate, selectedDate);
1176 }
1177
1178
1179
1180
1181
1182
1183 public DateSpan getSelectedDateSpan()
1184 {
1185 return selectedDateSpan;
1186 }
1187
1188
1189
1190
1191
1192
1193
1194 public static void copyDate(Calendar source, Calendar destination)
1195 {
1196 destination.set(source.get(Calendar.YEAR), source.get(Calendar.MONTH),
1197 source.get(Calendar.DAY_OF_MONTH),
1198 source.get(Calendar.HOUR_OF_DAY), source.get(Calendar.MINUTE),
1199 source.get(Calendar.SECOND));
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209 public static Calendar createCopy(Calendar source)
1210 {
1211 Calendar retVal = Calendar.getInstance();
1212 copyDate(source, retVal);
1213
1214 return retVal;
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224 public static void normalizeToBeginningOfDay(Calendar date)
1225 {
1226 date.set(Calendar.HOUR_OF_DAY, 0);
1227 date.set(Calendar.MINUTE, 0);
1228 date.set(Calendar.SECOND, 0);
1229 date.set(Calendar.MILLISECOND, 0);
1230 }
1231
1232
1233
1234
1235
1236
1237
1238
1239 public static void normalizeToEndOfDay(Calendar date)
1240 {
1241 date.set(Calendar.HOUR_OF_DAY, 23);
1242 date.set(Calendar.MINUTE, 59);
1243 date.set(Calendar.SECOND, 59);
1244 date.set(Calendar.MILLISECOND, 999);
1245 }
1246
1247
1248
1249
1250
1251
1252
1253 public static void normalizeToMiddleOfDay(Calendar date)
1254 {
1255 date.set(Calendar.HOUR_OF_DAY, 12);
1256 date.set(Calendar.MINUTE, 0);
1257 date.set(Calendar.SECOND, 0);
1258 date.set(Calendar.MILLISECOND, 0);
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268 public void setSelectedDate(Date date)
1269 {
1270 Date oldDate = selectedDate;
1271
1272 if (((date != null) && date.equals(oldDate)
1273 || date == null && selectedDate == null)) {
1274 return;
1275 }
1276
1277 if (date == null) {
1278 setSelectedDateSpan(null);
1279 } else {
1280 setSelectedDateSpan(new DateSpan(date, date));
1281 }
1282 }
1283
1284
1285
1286
1287
1288
1289 public Date getSelectedDate()
1290 {
1291 return selectedDate;
1292 }
1293
1294
1295
1296
1297
1298
1299 public boolean isSingleDateSelected()
1300 {
1301 return (selectedDate != null);
1302 }
1303
1304
1305
1306
1307
1308 @Override
1309 public void setEnabled(boolean enabled) {
1310 super.setEnabled(enabled);
1311 monthCombo.setEnabled(enabled);
1312 datePanel.setEnabled(enabled);
1313 getLeftYearButton().setEnabled(enabled);
1314 getRightYearButton().setEnabled(enabled);
1315 }
1316
1317 private JPopupMenu getPopup() {
1318 if (popup == null){
1319
1320 popup = new JPopupMenu("");
1321
1322 JMenuItem todayItem = new JMenuItem("Go to today");
1323 todayItem.addActionListener(new ActionListener(){
1324 public void actionPerformed(ActionEvent e) {
1325
1326 if (getSelectedDateSpan() == null) return;
1327 Calendar start = GregorianCalendar.getInstance();
1328 datePanel.displayMonthDate.set(Calendar.YEAR, start.get(Calendar.YEAR));
1329 datePanel.displayMonthDate.set(Calendar.MONTH, start.get(Calendar.MONTH));
1330 Calendar date = createCopy(datePanel.displayMonthDate);
1331 date.set(Calendar.DAY_OF_MONTH, 1);
1332 normalizeToBeginningOfDay(date);
1333 monthCombo.setSelectedItem(date);
1334 monthCombo.repaint();
1335 datePanel.populateDateList();
1336 }
1337 });
1338 popup.add(todayItem);
1339
1340 JMenuItem selStartItem = new JMenuItem("Go to selection start");
1341 selStartItem.addActionListener(new ActionListener(){
1342 public void actionPerformed(ActionEvent e) {
1343 if (getSelectedDateSpan() == null) return;
1344 Calendar start = GregorianCalendar.getInstance();
1345 start.setTime(getSelectedDateSpan().getStartingDate());
1346 datePanel.displayMonthDate.set(Calendar.YEAR, start.get(Calendar.YEAR));
1347 datePanel.displayMonthDate.set(Calendar.MONTH, start.get(Calendar.MONTH));
1348 Calendar date = createCopy(datePanel.displayMonthDate);
1349 date.set(Calendar.DAY_OF_MONTH, 1);
1350 normalizeToBeginningOfDay(date);
1351 monthCombo.setSelectedItem(date);
1352 monthCombo.repaint();
1353 datePanel.populateDateList();
1354 }
1355 });
1356 popup.add(selStartItem);
1357
1358 JMenuItem selEndItem = new JMenuItem("Go to selection end");
1359 selEndItem.addActionListener(new ActionListener(){
1360 public void actionPerformed(ActionEvent e) {
1361 if (getSelectedDateSpan() == null) return;
1362 Calendar end = GregorianCalendar.getInstance();
1363 end.setTime(getSelectedDateSpan().getFinishingDate());
1364 datePanel.displayMonthDate.set(Calendar.YEAR, end.get(Calendar.YEAR));
1365 datePanel.displayMonthDate.set(Calendar.MONTH, end.get(Calendar.MONTH));
1366 Calendar date = createCopy(datePanel.displayMonthDate);
1367 date.set(Calendar.DAY_OF_MONTH, 1);
1368 normalizeToBeginningOfDay(date);
1369 monthCombo.setSelectedItem(date);
1370 monthCombo.repaint();
1371 datePanel.populateDateList();
1372 }
1373 });
1374 popup.add(selEndItem);
1375
1376 }
1377 return popup;
1378 }
1379
1380
1381
1382
1383
1384
1385 public static void main(String[] args)
1386 {
1387 JPanel pan = new JPanel();
1388 pan.setLayout(new CardLayout(10, 10));
1389 DateSpanSelector selector = new DateSpanSelector();
1390
1391
1392
1393 pan.add(selector, "Date");
1394 selector.addPropertyChangeListener("selectedDateSpan", new PropertyChangeListener(){
1395 public void propertyChange(PropertyChangeEvent evt) {
1396 System.out.println(evt.getNewValue());
1397 }
1398 });
1399 JFrame frame = new JFrame("CalendarSelector Testing Applet");
1400 frame.getContentPane().add(pan);
1401 frame.setSize(300, 300);
1402 frame.addWindowListener(new WindowAdapter() {
1403 public void windowClosing(WindowEvent e)
1404 {
1405 System.exit(0);
1406 }
1407 });
1408 frame.setVisible(true);
1409
1410 try {
1411
1412
1413
1414
1415
1416
1417 Thread.sleep(2000);
1418 selector.setEnabled(true);
1419
1420 } catch (InterruptedException e1) {
1421
1422 e1.printStackTrace();
1423 }
1424
1425
1426 }
1427 }
1428
1429