1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package fr.ifremer.quadrige3.ui.swing.component.date;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 import fr.ifremer.quadrige3.ui.swing.component.date.constraints.DateSelectionConstraint;
54
55 import javax.swing.*;
56 import javax.swing.event.ChangeEvent;
57 import javax.swing.event.ChangeListener;
58 import javax.swing.event.TableModelEvent;
59 import javax.swing.event.TableModelListener;
60 import javax.swing.table.DefaultTableCellRenderer;
61 import javax.swing.table.JTableHeader;
62 import javax.swing.table.TableColumn;
63 import javax.swing.table.TableModel;
64 import java.awt.BorderLayout;
65 import java.awt.Component;
66 import java.awt.Dimension;
67 import java.awt.GridLayout;
68 import java.awt.event.*;
69 import java.text.DateFormat;
70 import java.time.LocalDate;
71 import java.time.ZoneId;
72 import java.util.*;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public class JLocalDatePanel extends JComponent {
91
92 private static final long serialVersionUID = -2299249311312882915L;
93
94
95 public static final String COMMIT_DATE = "commit";
96
97 private final Set<ActionListener> actionListeners;
98 private final Set<DateSelectionConstraint> dateConstraints;
99
100 private boolean showYearButtons;
101 private boolean doubleClickAction;
102
103 private final InternalCalendarModel internalModel;
104 private final InternalController internalController;
105 private final InternalView internalView;
106
107
108
109
110 public JLocalDatePanel() {
111 this(createModel());
112 }
113
114
115
116
117
118
119 public JLocalDatePanel(LocalDateModel model) {
120 actionListeners = new HashSet<>();
121 dateConstraints = new HashSet<>();
122
123 showYearButtons = false;
124 doubleClickAction = false;
125
126 internalModel = new InternalCalendarModel(model);
127 internalController = new InternalController();
128 internalView = new InternalView();
129
130 setLayout(new GridLayout(1, 1));
131 add(internalView);
132 }
133
134
135
136
137
138
139 protected static LocalDateModel createModel() {
140 return new LocalDateModel();
141 }
142
143
144
145
146
147
148 public void addActionListener(ActionListener actionListener) {
149 actionListeners.add(actionListener);
150 }
151
152
153
154
155
156
157 public void removeActionListener(ActionListener actionListener) {
158 actionListeners.remove(actionListener);
159 }
160
161
162
163
164 private void fireActionPerformed() {
165 for (ActionListener actionListener : actionListeners) {
166 actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, COMMIT_DATE));
167 }
168 }
169
170
171
172
173
174
175 public void setShowYearButtons(boolean showYearButtons) {
176 this.showYearButtons = showYearButtons;
177 internalView.updateShowYearButtons();
178 }
179
180
181
182
183
184
185 public boolean isShowYearButtons() {
186 return this.showYearButtons;
187 }
188
189
190
191
192
193
194 public void setDoubleClickAction(boolean doubleClickAction) {
195 this.doubleClickAction = doubleClickAction;
196 }
197
198
199
200
201
202
203 public boolean isDoubleClickAction() {
204 return doubleClickAction;
205 }
206
207
208
209
210
211
212 public LocalDateModel getModel() {
213 return internalModel.getModel();
214 }
215
216
217
218
219
220
221 public void addDateSelectionConstraint(DateSelectionConstraint constraint) {
222 dateConstraints.add(constraint);
223 }
224
225
226
227
228
229
230 public void removeDateSelectionConstraint(DateSelectionConstraint constraint) {
231 dateConstraints.remove(constraint);
232 }
233
234
235
236
237 public void removeAllDateSelectionConstraints() {
238 dateConstraints.clear();
239 }
240
241
242
243
244
245
246 public Set<DateSelectionConstraint> getDateSelectionConstraints() {
247 return Collections.unmodifiableSet(dateConstraints);
248 }
249
250
251
252
253
254
255
256 protected boolean checkConstraints(LocalDateModel model) {
257 for (DateSelectionConstraint constraint : dateConstraints) {
258 if (!constraint.isValidSelection(new DateModel(Date.from(model.getSafeLocalDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())))) {
259 return false;
260 }
261 }
262 return true;
263 }
264
265 private static ComponentTextDefaults getTexts() {
266 return ComponentTextDefaults.getInstance();
267 }
268
269 private static ComponentIconDefaults getIcons() {
270 return ComponentIconDefaults.getInstance();
271 }
272
273 private AbstractComponentColor colors;
274
275
276
277
278
279
280 public AbstractComponentColor getColors() {
281 if (colors == null) {
282 try {
283 colors = ComponentColorDefaults.getInstance().clone();
284 } catch (CloneNotSupportedException e) {
285 colors = ComponentColorDefaults.getInstance();
286 }
287 }
288 return colors;
289 }
290
291 private static ComponentFormatDefaults getFormats() {
292 return ComponentFormatDefaults.getInstance();
293 }
294
295
296 @Override
297 public void setVisible(boolean aFlag) {
298 super.setVisible(aFlag);
299
300 if (aFlag) {
301 internalView.updateTodayLabel();
302 }
303 }
304
305
306 @Override
307 public void setEnabled(boolean enabled) {
308 internalView.setEnabled(enabled);
309
310 super.setEnabled(enabled);
311 }
312
313
314
315
316
317
318 public LocalDate getLocalDate() {
319 return getModel().getLocalDate();
320 }
321
322
323
324
325
326
327 public void setLocalDate(LocalDate date) {
328 getModel().setLocalDate(date);
329 }
330
331
332
333
334
335
336 private class InternalView extends JPanel {
337
338 private static final long serialVersionUID = -6844493839307157682L;
339
340 private static final int DEFAULT_WIDTH = 280;
341 private static final int DEFAULT_HEIGHT = 200;
342
343 private JPanel centerPanel;
344 private JPanel northCenterPanel;
345 private JPanel northPanel;
346 private JPanel southPanel;
347 private JPanel previousButtonPanel;
348 private JPanel nextButtonPanel;
349 private JTable dayTable;
350 private JTableHeader dayTableHeader;
351 private InternalTableCellRenderer dayTableCellRenderer;
352 private JLabel monthLabel;
353 private JLabel todayLabel;
354 private JLabel noneLabel;
355 private JPopupMenu monthPopupMenu;
356 private JMenuItem[] monthPopupMenuItems;
357 private JButton nextMonthButton;
358 private JButton previousMonthButton;
359 private JButton previousYearButton;
360 private JButton nextYearButton;
361 private JSpinner yearSpinner;
362
363
364
365
366 private void updateShowYearButtons() {
367 if (showYearButtons) {
368 getNextButtonPanel().add(getNextYearButton());
369 getPreviousButtonPanel().removeAll();
370 getPreviousButtonPanel().add(getPreviousYearButton());
371 getPreviousButtonPanel().add(getPreviousMonthButton());
372 } else {
373 getNextButtonPanel().remove(getNextYearButton());
374 getPreviousButtonPanel().remove(getPreviousYearButton());
375 }
376 }
377
378
379
380
381 private void updateMonthLabel() {
382 monthLabel.setText(getTexts().getText(ComponentTextDefaults.Key.getMonthKey(internalModel.getModel().getMonth() - 1)));
383 }
384
385 InternalView() {
386 initialise();
387 }
388
389
390
391
392 private void initialise() {
393 this.setLayout(new BorderLayout());
394 this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
395 this.setPreferredSize(getSize());
396 this.setOpaque(false);
397 this.add(getNorthPanel(), BorderLayout.NORTH);
398 this.add(getSouthPanel(), BorderLayout.SOUTH);
399 this.add(getCenterPanel(), BorderLayout.CENTER);
400 }
401
402
403
404
405
406
407 private JPanel getNorthPanel() {
408 if (northPanel == null) {
409 northPanel = new JPanel();
410 northPanel.setLayout(new BorderLayout());
411 northPanel.setName("");
412 northPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
413 northPanel.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_MONTH_SELECTOR));
414 northPanel.add(getPreviousButtonPanel(), BorderLayout.WEST);
415 northPanel.add(getNextButtonPanel(), BorderLayout.EAST);
416 northPanel.add(getNorthCenterPanel(), BorderLayout.CENTER);
417 }
418 return northPanel;
419 }
420
421
422
423
424
425
426 private JPanel getNorthCenterPanel() {
427 if (northCenterPanel == null) {
428 northCenterPanel = new JPanel();
429 northCenterPanel.setLayout(new BorderLayout());
430 northCenterPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
431 northCenterPanel.setOpaque(false);
432 northCenterPanel.add(getMonthLabel(), BorderLayout.CENTER);
433 northCenterPanel.add(getYearSpinner(), BorderLayout.EAST);
434 }
435 return northCenterPanel;
436 }
437
438
439
440
441
442
443 private JLabel getMonthLabel() {
444 if (monthLabel == null) {
445 monthLabel = new JLabel();
446 monthLabel.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_MONTH_SELECTOR));
447 monthLabel.setHorizontalAlignment(SwingConstants.CENTER);
448 monthLabel.addMouseListener(internalController);
449 updateMonthLabel();
450 }
451 return monthLabel;
452 }
453
454
455
456
457
458
459 private JSpinner getYearSpinner() {
460 if (yearSpinner == null) {
461 yearSpinner = new JSpinner();
462 yearSpinner.setModel(internalModel);
463 }
464 return yearSpinner;
465 }
466
467
468
469
470
471
472 private JPanel getSouthPanel() {
473 if (southPanel == null) {
474 southPanel = new JPanel();
475 southPanel.setLayout(new BorderLayout());
476 southPanel.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_TODAY_SELECTOR));
477 southPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
478 southPanel.add(getTodayLabel(), BorderLayout.WEST);
479 southPanel.add(getNoneLabel(), BorderLayout.EAST);
480 }
481 return southPanel;
482 }
483
484
485
486
487
488
489 private JLabel getNoneLabel() {
490 if (noneLabel == null) {
491 noneLabel = new JLabel();
492 noneLabel.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_TODAY_SELECTOR_ENABLED));
493 noneLabel.setHorizontalAlignment(SwingConstants.CENTER);
494 noneLabel.addMouseListener(internalController);
495
496
497 noneLabel.setIcon(getIcons().getClearIcon());
498 }
499 return noneLabel;
500 }
501
502
503 private void updateTodayLabel() {
504 Calendar now = Calendar.getInstance();
505 DateFormat df = getFormats().getFormat(ComponentFormatDefaults.Key.TODAY_SELECTOR);
506 todayLabel.setText(getTexts().getText(
507 ComponentTextDefaults.Key.TODAY)
508 + ": "
509 + df.format(now.getTime()));
510 }
511
512
513
514
515
516
517 private JLabel getTodayLabel() {
518 if (todayLabel == null) {
519 todayLabel = new JLabel();
520 todayLabel.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_TODAY_SELECTOR_ENABLED));
521 todayLabel.setHorizontalAlignment(SwingConstants.CENTER);
522 todayLabel.addMouseListener(internalController);
523 updateTodayLabel();
524 }
525 return todayLabel;
526 }
527
528
529
530
531
532
533 private JPanel getCenterPanel() {
534 if (centerPanel == null) {
535 centerPanel = new JPanel();
536 centerPanel.setLayout(new BorderLayout());
537 centerPanel.setOpaque(false);
538 centerPanel.add(getDayTableHeader(), BorderLayout.NORTH);
539 centerPanel.add(getDayTable(), BorderLayout.CENTER);
540 }
541 return centerPanel;
542 }
543
544
545
546
547
548
549 private JTable getDayTable() {
550 if (dayTable == null) {
551 dayTable = new JTable();
552 dayTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
553 dayTable.setModel(internalModel);
554 dayTable.setShowGrid(true);
555 dayTable.setGridColor(getColors().getColor(AbstractComponentColor.Key.BG_GRID));
556 dayTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
557 dayTable.setCellSelectionEnabled(true);
558 dayTable.setRowSelectionAllowed(true);
559 dayTable.setFocusable(false);
560 dayTable.addMouseListener(internalController);
561 for (int i = 0; i < 7; i++) {
562 TableColumn column = dayTable.getColumnModel().getColumn(i);
563 column.setCellRenderer(getDayTableCellRenderer());
564 }
565 dayTable.addComponentListener(new ComponentListener() {
566
567 public void componentResized(ComponentEvent e) {
568
569 final double w = e.getComponent().getSize().getWidth();
570 final double h = e.getComponent().getSize().getHeight();
571
572
573 final float sw = (float) (w / 18);
574 final float sh = (float) (h / 9);
575 float fs = Math.min(sw, sh);
576 dayTable.setFont(dayTable.getFont().deriveFont(fs));
577
578
579 final int r = (int) Math.floor(h / 6);
580 dayTable.setRowHeight(r);
581 }
582
583 public void componentMoved(ComponentEvent e) {
584
585 }
586
587 public void componentShown(ComponentEvent e) {
588
589 }
590
591 public void componentHidden(ComponentEvent e) {
592
593 }
594
595 });
596 }
597 return dayTable;
598 }
599
600 private InternalTableCellRenderer getDayTableCellRenderer() {
601 if (dayTableCellRenderer == null) {
602 dayTableCellRenderer = new InternalTableCellRenderer();
603 }
604 return dayTableCellRenderer;
605 }
606
607 private JTableHeader getDayTableHeader() {
608 if (dayTableHeader == null) {
609 dayTableHeader = getDayTable().getTableHeader();
610 dayTableHeader.setResizingAllowed(false);
611 dayTableHeader.setReorderingAllowed(false);
612 dayTableHeader.setDefaultRenderer(getDayTableCellRenderer());
613 }
614 return dayTableHeader;
615 }
616
617
618
619
620
621
622 private JPanel getPreviousButtonPanel() {
623 if (previousButtonPanel == null) {
624 previousButtonPanel = new JPanel();
625 GridLayout layout = new GridLayout(1, 2);
626 layout.setHgap(3);
627 previousButtonPanel.setLayout(layout);
628 previousButtonPanel.setName("");
629 previousButtonPanel.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_MONTH_SELECTOR));
630 if (isShowYearButtons()) {
631 previousButtonPanel.add(getPreviousYearButton());
632 }
633 previousButtonPanel.add(getPreviousMonthButton());
634 }
635 return previousButtonPanel;
636 }
637
638
639
640
641
642
643 private JPanel getNextButtonPanel() {
644 if (nextButtonPanel == null) {
645 nextButtonPanel = new JPanel();
646 GridLayout layout = new GridLayout(1, 2);
647 layout.setHgap(3);
648 nextButtonPanel.setLayout(layout);
649 nextButtonPanel.setName("");
650 nextButtonPanel.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_MONTH_SELECTOR));
651 nextButtonPanel.add(getNextMonthButton());
652 if (isShowYearButtons()) {
653 nextButtonPanel.add(getNextYearButton());
654 }
655 }
656 return nextButtonPanel;
657 }
658
659
660
661
662
663
664 private JButton getNextMonthButton() {
665 if (nextMonthButton == null) {
666 nextMonthButton = new JButton();
667 nextMonthButton.setIcon(getIcons().getNextMonthIconEnabled());
668 nextMonthButton.setDisabledIcon(getIcons().getNextMonthIconDisabled());
669 nextMonthButton.setText("");
670 nextMonthButton.setPreferredSize(new Dimension(20, 15));
671 nextMonthButton.setFocusable(false);
672 nextMonthButton.addActionListener(internalController);
673 nextMonthButton.setToolTipText(getTexts().getText(ComponentTextDefaults.Key.MONTH));
674 }
675 return nextMonthButton;
676 }
677
678
679
680
681
682
683 private JButton getNextYearButton() {
684 if (nextYearButton == null) {
685 nextYearButton = new JButton();
686 nextYearButton.setIcon(getIcons().getNextYearIconEnabled());
687 nextYearButton.setDisabledIcon(getIcons().getNextYearIconDisabled());
688 nextYearButton.setText("");
689 nextYearButton.setPreferredSize(new Dimension(20, 15));
690 nextYearButton.setFocusable(false);
691 nextYearButton.addActionListener(internalController);
692 nextYearButton.setToolTipText(getTexts().getText(ComponentTextDefaults.Key.YEAR));
693 }
694 return nextYearButton;
695 }
696
697
698
699
700
701
702 private JButton getPreviousMonthButton() {
703 if (previousMonthButton == null) {
704 previousMonthButton = new JButton();
705 previousMonthButton.setIcon(getIcons().getPreviousMonthIconEnabled());
706 previousMonthButton.setDisabledIcon(getIcons().getPreviousMonthIconDisabled());
707 previousMonthButton.setText("");
708 previousMonthButton.setPreferredSize(new Dimension(20, 15));
709 previousMonthButton.setFocusable(false);
710 previousMonthButton.addActionListener(internalController);
711 previousMonthButton.setToolTipText(getTexts().getText(ComponentTextDefaults.Key.MONTH));
712 }
713 return previousMonthButton;
714 }
715
716
717
718
719
720
721 private JButton getPreviousYearButton() {
722 if (previousYearButton == null) {
723 previousYearButton = new JButton();
724 previousYearButton.setIcon(getIcons().getPreviousYearIconEnabled());
725 previousYearButton.setDisabledIcon(getIcons().getPreviousYearIconDisabled());
726 previousYearButton.setText("");
727 previousYearButton.setPreferredSize(new Dimension(20, 15));
728 previousYearButton.setFocusable(false);
729 previousYearButton.addActionListener(internalController);
730 previousYearButton.setToolTipText(getTexts().getText(ComponentTextDefaults.Key.YEAR));
731 }
732 return previousYearButton;
733 }
734
735
736
737
738
739
740 private JPopupMenu getMonthPopupMenu() {
741 if (monthPopupMenu == null) {
742 monthPopupMenu = new JPopupMenu();
743 JMenuItem[] menuItems = getMonthPopupMenuItems();
744 for (JMenuItem menuItem : menuItems) {
745 monthPopupMenu.add(menuItem);
746 }
747 }
748 return monthPopupMenu;
749 }
750
751 private JMenuItem[] getMonthPopupMenuItems() {
752 if (monthPopupMenuItems == null) {
753 monthPopupMenuItems = new JMenuItem[12];
754 for (int i = 0; i < 12; i++) {
755 JMenuItem mi = new JMenuItem(getTexts().getText(ComponentTextDefaults.Key.getMonthKey(i)));
756 mi.addActionListener(internalController);
757 monthPopupMenuItems[i] = mi;
758 }
759 }
760 return monthPopupMenuItems;
761 }
762
763 @Override
764 public void setEnabled(boolean enabled) {
765 dayTable.setEnabled(enabled);
766 dayTableCellRenderer.setEnabled(enabled);
767 nextMonthButton.setEnabled(enabled);
768 if (nextYearButton != null) {
769 nextYearButton.setEnabled(enabled);
770 }
771 previousMonthButton.setEnabled(enabled);
772 if (previousYearButton != null) {
773 previousYearButton.setEnabled(enabled);
774 }
775 yearSpinner.setEnabled(enabled);
776 if (enabled) {
777 todayLabel.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_TODAY_SELECTOR_ENABLED));
778 } else {
779 todayLabel.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_TODAY_SELECTOR_DISABLED));
780 }
781
782 super.setEnabled(enabled);
783 }
784 }
785
786
787
788
789
790
791
792 private class InternalTableCellRenderer extends DefaultTableCellRenderer {
793
794 private static final long serialVersionUID = -2341614459632756921L;
795
796 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
797
798 if (value == null) {
799 return super.getTableCellRendererComponent(table, null, isSelected, hasFocus, row, column);
800 }
801
802 JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
803 label.setHorizontalAlignment(JLabel.CENTER);
804
805 if (row == -1) {
806 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_HEADER));
807 label.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_GRID_HEADER));
808 label.setHorizontalAlignment(JLabel.CENTER);
809 return label;
810 }
811
812 LocalDate today = LocalDate.now();
813 LocalDate date = LocalDate.of(internalModel.getModel().getYear(), internalModel.getModel().getMonth(), internalModel.getModel().getDay());
814
815 int cellDayValue = (Integer) value;
816 int lastDayOfMonth = date.lengthOfMonth();
817
818
819 if (cellDayValue < 1 || cellDayValue > lastDayOfMonth) {
820 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_OTHER_MONTH));
821 LocalDate outDate = date.withDayOfMonth(1).plusDays(cellDayValue);
822 label.setBackground(checkConstraints(new LocalDateModel(outDate)) ?
823 getColors().getColor(AbstractComponentColor.Key.BG_GRID) :
824 getColors().getColor(AbstractComponentColor.Key.BG_GRID_NOT_SELECTABLE)
825 );
826
827
828 if (cellDayValue > lastDayOfMonth) {
829 label.setText(Integer.toString(cellDayValue - lastDayOfMonth));
830 }
831
832 else {
833 int lastDayLastMonth = date.withDayOfMonth(1).minusDays(1).lengthOfMonth();
834 label.setText(Integer.toString(lastDayLastMonth + cellDayValue));
835 }
836 }
837
838 else {
839 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_THIS_MONTH));
840
841 LocalDate cellDate = date.withDayOfMonth(cellDayValue);
842 label.setBackground(checkConstraints(new LocalDateModel(cellDate)) ?
843 getColors().getColor(AbstractComponentColor.Key.BG_GRID) :
844 getColors().getColor(AbstractComponentColor.Key.BG_GRID_NOT_SELECTABLE)
845 );
846
847
848 if (cellDate.equals(today)) {
849 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_TODAY));
850
851 if (internalModel.getModel().isSelected() && cellDate.equals(date)) {
852 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_TODAY_SELECTED));
853 label.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_GRID_TODAY_SELECTED));
854 }
855 }
856
857 else {
858
859 if (internalModel.getModel().isSelected() && cellDate.equals(date)) {
860 label.setForeground(getColors().getColor(AbstractComponentColor.Key.FG_GRID_SELECTED));
861 label.setBackground(getColors().getColor(AbstractComponentColor.Key.BG_GRID_SELECTED));
862 }
863 }
864 }
865
866 return label;
867 }
868
869 }
870
871
872
873
874
875
876
877
878 private class InternalController implements ActionListener, MouseListener {
879
880
881
882
883
884 public void actionPerformed(ActionEvent e) {
885 if (!JLocalDatePanel.this.isEnabled()) {
886 return;
887 }
888
889 if (e.getSource() == internalView.getNextMonthButton()) {
890 internalModel.getModel().addMonth(1);
891 } else if (e.getSource() == internalView.getPreviousMonthButton()) {
892 internalModel.getModel().addMonth(-1);
893 } else if (e.getSource() == internalView.getNextYearButton()) {
894 internalModel.getModel().addYear(1);
895 } else if (e.getSource() == internalView.getPreviousYearButton()) {
896 internalModel.getModel().addYear(-1);
897 } else {
898 for (int month = 0; month < internalView.getMonthPopupMenuItems().length; month++) {
899 if (e.getSource() == internalView.getMonthPopupMenuItems()[month]) {
900 internalModel.getModel().setMonth(month + 1);
901 }
902 }
903 }
904 }
905
906
907
908
909
910
911
912 public void mouseClicked(MouseEvent e) {
913 if (!JLocalDatePanel.this.isEnabled()) {
914 return;
915 }
916
917 if (e.getSource() == internalView.getMonthLabel()) {
918 internalView.getMonthPopupMenu().setLightWeightPopupEnabled(false);
919 internalView.getMonthPopupMenu().show((Component) e.getSource(), e.getX(), e.getY());
920 } else if (e.getSource() == internalView.getTodayLabel()) {
921 internalModel.getModel().setLocalDate(LocalDate.now());
922 } else if (e.getSource() == internalView.getDayTable()) {
923 int row = internalView.getDayTable().getSelectedRow();
924 int col = internalView.getDayTable().getSelectedColumn();
925 if (row >= 0 && row <= 5) {
926 Integer date = (Integer) internalModel.getValueAt(row, col);
927
928
929 int oldDay = internalModel.getModel().getDay();
930 internalModel.getModel().setDay(date);
931 if (!checkConstraints(internalModel.getModel())) {
932
933 internalModel.getModel().setDay(oldDay);
934 return;
935 }
936
937 internalModel.getModel().setSelected(true);
938
939 if (doubleClickAction && e.getClickCount() == 2) {
940 fireActionPerformed();
941 }
942 if (!doubleClickAction) {
943 fireActionPerformed();
944 }
945 }
946 } else if (e.getSource() == internalView.getNoneLabel()) {
947 internalModel.getModel().setSelected(false);
948
949 if (doubleClickAction && e.getClickCount() == 2) {
950 fireActionPerformed();
951 }
952 if (!doubleClickAction) {
953 fireActionPerformed();
954 }
955 }
956
957 e.consume();
958 }
959
960 public void mousePressed(MouseEvent e) {
961 }
962
963 public void mouseEntered(MouseEvent e) {
964 }
965
966 public void mouseExited(MouseEvent e) {
967 }
968
969 public void mouseReleased(MouseEvent e) {
970 }
971
972 }
973
974
975
976
977
978
979
980
981 protected class InternalCalendarModel implements TableModel, SpinnerModel, ChangeListener {
982
983 private final LocalDateModel model;
984 private final Set<ChangeListener> spinnerChangeListeners;
985 private final Set<TableModelListener> tableModelListeners;
986
987 protected InternalCalendarModel(LocalDateModel model) {
988 this.spinnerChangeListeners = new HashSet<>();
989 this.tableModelListeners = new HashSet<>();
990 this.model = model;
991 model.addChangeListener(this);
992 }
993
994 public LocalDateModel getModel() {
995 return model;
996 }
997
998
999
1000
1001 public void addChangeListener(ChangeListener e) {
1002 spinnerChangeListeners.add(e);
1003 }
1004
1005
1006
1007
1008 public void removeChangeListener(ChangeListener e) {
1009 spinnerChangeListeners.remove(e);
1010 }
1011
1012
1013
1014
1015 public Object getNextValue() {
1016 return Integer.toString(model.getYear() + 1);
1017 }
1018
1019
1020
1021
1022 public Object getPreviousValue() {
1023 return Integer.toString(model.getYear() - 1);
1024 }
1025
1026
1027
1028
1029 public void setValue(Object text) {
1030 String year = (String) text;
1031 model.setYear(Integer.parseInt(year));
1032 }
1033
1034
1035
1036
1037 public Object getValue() {
1038 return Integer.toString(model.getYear());
1039 }
1040
1041
1042
1043
1044 public void addTableModelListener(TableModelListener e) {
1045 tableModelListeners.add(e);
1046 }
1047
1048
1049
1050
1051 public void removeTableModelListener(TableModelListener e) {
1052 tableModelListeners.remove(e);
1053 }
1054
1055
1056
1057
1058 public int getColumnCount() {
1059 return 7;
1060 }
1061
1062
1063
1064
1065 public int getRowCount() {
1066 return 6;
1067 }
1068
1069
1070
1071
1072 public String getColumnName(int columnIndex) {
1073 ComponentTextDefaults.Key key = ComponentTextDefaults.Key.getDowKey((2 + columnIndex) % 7);
1074 return getTexts().getText(key);
1075 }
1076
1077 private int[] lookup = null;
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090 private int[] lookup() {
1091 if (lookup == null) {
1092 lookup = new int[8];
1093 lookup[(0) % 7] = 0;
1094 lookup[(1) % 7] = 1;
1095 lookup[(2) % 7] = 2;
1096 lookup[(3) % 7] = 3;
1097 lookup[(4) % 7] = 4;
1098 lookup[(5) % 7] = 5;
1099 lookup[(6) % 7] = 6;
1100 }
1101 return lookup;
1102 }
1103
1104
1105
1106
1107
1108
1109
1110
1111 public Object getValueAt(int rowIndex, int columnIndex) {
1112 int series = columnIndex + rowIndex * 7 + 1;
1113
1114 LocalDate startOfMonth = model.getSafeLocalDate().withDayOfMonth(1);
1115 int dowForFirst = startOfMonth.getDayOfWeek().getValue();
1116 int daysBefore = lookup()[dowForFirst - 1];
1117
1118 return series - daysBefore;
1119 }
1120
1121
1122
1123
1124 @SuppressWarnings({"rawtypes"})
1125 public Class getColumnClass(int e) {
1126 return Integer.class;
1127 }
1128
1129
1130
1131
1132 public boolean isCellEditable(int e, int arg1) {
1133 return false;
1134 }
1135
1136
1137
1138
1139 public void setValueAt(Object e, int arg1, int arg2) {
1140 }
1141
1142
1143
1144
1145
1146
1147
1148 private void fireValueChanged() {
1149
1150 for (ChangeListener cl : spinnerChangeListeners) {
1151 cl.stateChanged(new ChangeEvent(this));
1152 }
1153
1154
1155 internalView.updateMonthLabel();
1156
1157
1158 for (TableModelListener tl : tableModelListeners) {
1159 tl.tableChanged(new TableModelEvent(this));
1160 }
1161 }
1162
1163
1164
1165
1166 public void stateChanged(ChangeEvent e) {
1167 fireValueChanged();
1168 }
1169
1170 }
1171
1172 }