View Javadoc
1   /*******************************************************************************
2    * JDateButton: JavaFX Date Button
3    * Copyright 2012,2014 Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   * ------------------------------------------------------------
17   * SubVersion Revision Information:
18   * $URL: https://svn.code.sf.net/p/jdatebutton/code/tags/v2.1.0-b3/jdatebutton-javafx/src/main/java/net/sourceforge/jdatebutton/javafx/JDateDialog.java $
19   * $Revision: 34 $
20   * $Author: tonywasher $
21   * $Date: 2015-12-01 16:21:13 +0000 (Tue, 01 Dec 2015) $
22   ******************************************************************************/
23  package net.sourceforge.jdatebutton.javafx;
24  
25  import java.time.DayOfWeek;
26  import java.time.LocalDate;
27  import java.time.format.TextStyle;
28  import java.util.Calendar;
29  import java.util.Locale;
30  import java.util.ResourceBundle;
31  
32  import javafx.beans.value.ChangeListener;
33  import javafx.beans.value.ObservableValue;
34  import javafx.collections.ObservableList;
35  import javafx.event.ActionEvent;
36  import javafx.event.EventHandler;
37  import javafx.scene.Node;
38  import javafx.scene.Scene;
39  import javafx.scene.control.Button;
40  import javafx.scene.control.Label;
41  import javafx.scene.control.Tooltip;
42  import javafx.scene.input.KeyCode;
43  import javafx.scene.input.KeyEvent;
44  import javafx.scene.input.MouseEvent;
45  import javafx.scene.layout.BorderPane;
46  import javafx.scene.layout.GridPane;
47  import javafx.scene.layout.HBox;
48  import javafx.scene.layout.Priority;
49  import javafx.scene.layout.Region;
50  import javafx.stage.Modality;
51  import javafx.stage.Stage;
52  import javafx.stage.StageStyle;
53  
54  /**
55   * Dialog class providing a dialog allowing selection of a date.
56   * <p>
57   * It will rebuild the dialog according to the currently set locale and date format whenever it is
58   * made visible
59   */
60  public class JDateDialog
61          extends Stage {
62      /**
63       * StyleSheet.
64       */
65      private static final String CSS_STYLE = JDateDialog.class.getResource("JDateDialog.css").toExternalForm();
66  
67      /**
68       * Resource Bundle.
69       */
70      private static final ResourceBundle NLS_BUNDLE = ResourceBundle.getBundle(JDateDialog.class.getName());
71  
72      /**
73       * ToolTip for Current Day.
74       */
75      public static final String NLS_CURRENTDAY = NLS_BUNDLE.getString("CurrentDay");
76  
77      /**
78       * ToolTip for Selected Day.
79       */
80      public static final String NLS_SELECTEDDAY = NLS_BUNDLE.getString("SelectedDay");
81  
82      /**
83       * ToolTip for Next Month.
84       */
85      public static final String NLS_NEXTMONTH = NLS_BUNDLE.getString("NextMonth");
86  
87      /**
88       * ToolTip for Previous Month.
89       */
90      public static final String NLS_PREVMONTH = NLS_BUNDLE.getString("PreviousMonth");
91  
92      /**
93       * ToolTip for Next Year.
94       */
95      public static final String NLS_NEXTYEAR = NLS_BUNDLE.getString("NextYear");
96  
97      /**
98       * ToolTip for Previous Year.
99       */
100     public static final String NLS_PREVYEAR = NLS_BUNDLE.getString("PreviousYear");
101 
102     /**
103      * Null Date selection text.
104      */
105     public static final String NLS_NULLSELECT = NLS_BUNDLE.getString("NullSelect");
106 
107     /**
108      * The month array.
109      */
110     private final PanelMonth theDaysPanel;
111 
112     /**
113      * The navigation.
114      */
115     private final PanelNavigation theNavigation;
116 
117     /**
118      * The Null Select.
119      */
120     private final Button theNullButton;
121 
122     /**
123      * Is the Null button active.
124      */
125     private boolean isNullActive = false;
126 
127     /**
128      * The Date Configuration.
129      */
130     private final JDateConfig theConfig;
131 
132     /**
133      * Should we build names?
134      */
135     private boolean doBuildNames = true;
136 
137     /**
138      * The container box.
139      */
140     private final BorderPane theContainer;
141 
142     /**
143      * Have we selected a date?
144      */
145     private boolean haveSelected = false;
146 
147     /**
148      * Constructor.
149      * @param pConfig the configuration for the dialog
150      */
151     public JDateDialog(final JDateConfig pConfig) {
152         /* Non-Modal and undecorated */
153         super(StageStyle.UNDECORATED);
154         initModality(Modality.NONE);
155 
156         /* Store the DateConfig */
157         theConfig = pConfig;
158 
159         /* Build the panels */
160         theDaysPanel = new PanelMonth(this);
161         theNavigation = new PanelNavigation(this);
162 
163         /* Build the Null Select */
164         theNullButton = new Button(NLS_NULLSELECT);
165         theNullButton.setMaxWidth(Double.MAX_VALUE);
166         theNullButton.addEventFilter(ActionEvent.ACTION, new ButtonHandler());
167 
168         /* Add listener to shut dialog on loss of focus */
169         focusedProperty().addListener(new ChangeListener<Boolean>() {
170             @Override
171             public void changed(final ObservableValue<? extends Boolean> observable,
172                                 final Boolean oldValue,
173                                 final Boolean newValue) {
174                 if (!newValue) {
175                     closeNonModal();
176                 }
177             }
178         });
179 
180         /* Create the scene */
181         theContainer = new BorderPane();
182         theContainer.setTop(theNavigation);
183         theContainer.setCenter(theDaysPanel);
184         Scene myScene = new Scene(theContainer);
185         ObservableList<String> mySheets = myScene.getStylesheets();
186         mySheets.add(CSS_STYLE);
187         setScene(myScene);
188 
189         /* Initialise the month */
190         initialiseMonth();
191 
192         theContainer.setOnKeyPressed(new EventHandler<KeyEvent>() {
193             @Override
194             public void handle(final KeyEvent t) {
195                 if (t.getCode() == KeyCode.ESCAPE) {
196                     closeNonModal();
197                 }
198             }
199         });
200     }
201 
202     /**
203      * Request a rebuild of panel names.
204      */
205     protected void doBuildNames() {
206         doBuildNames = true;
207     }
208 
209     /**
210      * Have we selected a date?
211      * @return true/false
212      */
213     public boolean haveSelected() {
214         return haveSelected;
215     }
216 
217     /**
218      * Obtain Date Configuration.
219      * @return the date configuration
220      */
221     public JDateConfig getDateConfig() {
222         return theConfig;
223     }
224 
225     /**
226      * Build the month.
227      */
228     private void buildMonth() {
229         /* Build the month */
230         theNavigation.buildMonth();
231         theDaysPanel.buildMonth();
232     }
233 
234     /**
235      * Set Selected Date.
236      * @param pDay the Selected day
237      */
238     private void setSelected(final int pDay) {
239         /* Set the selected day */
240         theConfig.setSelectedDay(pDay);
241 
242         /* Note that we have selected */
243         haveSelected = true;
244 
245         /* Close the dialog */
246         close();
247     }
248 
249     /**
250      * Resize the dialog.
251      */
252     private void reSizeDialog() {
253         sizeToScene();
254     }
255 
256     /**
257      * InitialiseMonth.
258      */
259     private void initialiseMonth() {
260         /* Initialise the current month */
261         theConfig.initialiseCurrent();
262 
263         /* Build the day names if required */
264         if (doBuildNames) {
265             theDaysPanel.buildDayNames();
266         }
267         doBuildNames = false;
268 
269         /* Build detail */
270         buildMonth();
271 
272         /* If we need to change the visibility of the null button */
273         if (isNullActive != theConfig.allowNullDateSelection()) {
274             /* Add/Remove the button */
275             if (!isNullActive) {
276                 theContainer.setBottom(theNullButton);
277             } else {
278                 theContainer.setBottom(null);
279             }
280 
281             /* Record status and resize the dialog */
282             isNullActive = theConfig.allowNullDateSelection();
283             reSizeDialog();
284         }
285     }
286 
287     /**
288      * Show the dialog.
289      */
290     public void showDialog() {
291         /* Note that we have not selected */
292         haveSelected = false;
293 
294         /* Initialise the current month and show the dialog */
295         initialiseMonth();
296         show();
297     }
298 
299     /**
300      * Close non-Modal.
301      */
302     private void closeNonModal() {
303         close();
304     }
305 
306     /**
307      * ButtonHandler Handle button presses.
308      */
309     private class ButtonHandler
310             implements EventHandler<ActionEvent> {
311         @Override
312         public void handle(final ActionEvent e) {
313             /* Access the event source */
314             Object src = e.getSource();
315 
316             /* If the button is the Null button */
317             if (theNullButton.equals(src)) {
318                 /* Set the null date */
319                 setSelected(-1);
320             }
321         }
322     }
323 
324     /**
325      * Panel Navigation class allowing navigation between months.
326      */
327     private static final class PanelNavigation
328             extends HBox {
329         /**
330          * The button style.
331          */
332         private static final String STYLE_BUTTON = "-jdd-button";
333 
334         /**
335          * The title style.
336          */
337         private static final String STYLE_TITLE = "-jdd-title";
338 
339         /**
340          * The owning dialog.
341          */
342         private final JDateDialog theDialog;
343 
344         /**
345          * The Date Configuration.
346          */
347         private final JDateConfig theConfig;
348 
349         /**
350          * The Date Label.
351          */
352         private final Label theDateLabel;
353 
354         /**
355          * The Previous Month Button.
356          */
357         private final Button thePrevMonthButton;
358 
359         /**
360          * The Next Month Button.
361          */
362         private final Button theNextMonthButton;
363 
364         /**
365          * The Previous Year Button.
366          */
367         private final Button thePrevYearButton;
368 
369         /**
370          * The Next Year Button.
371          */
372         private final Button theNextYearButton;
373 
374         /**
375          * Constructor.
376          * @param pDialog the owning dialog
377          */
378         private PanelNavigation(final JDateDialog pDialog) {
379             /* Set single space */
380             super(1.0);
381 
382             /* Record the dialog */
383             theDialog = pDialog;
384 
385             /* Store the Date Configuration */
386             theConfig = pDialog.getDateConfig();
387 
388             /* Create the label */
389             theDateLabel = new Label();
390             theDateLabel.getStyleClass().add(STYLE_TITLE);
391 
392             /* Create the buttons */
393             thePrevMonthButton = new Button();
394             theNextMonthButton = new Button();
395             thePrevYearButton = new Button();
396             theNextYearButton = new Button();
397 
398             /* Set the icons */
399             thePrevMonthButton.setGraphic(ArrowIcon.LEFT.getArrow());
400             theNextMonthButton.setGraphic(ArrowIcon.RIGHT.getArrow());
401             thePrevYearButton.setGraphic(ArrowIcon.DOUBLELEFT.getArrow());
402             theNextYearButton.setGraphic(ArrowIcon.DOUBLERIGHT.getArrow());
403 
404             /* Add ToopTips */
405             theNextMonthButton.setTooltip(new Tooltip(NLS_NEXTMONTH));
406             thePrevMonthButton.setTooltip(new Tooltip(NLS_PREVMONTH));
407             theNextYearButton.setTooltip(new Tooltip(NLS_NEXTYEAR));
408             thePrevYearButton.setTooltip(new Tooltip(NLS_PREVYEAR));
409 
410             /* Listen for button events */
411             NavigateListener myListener = new NavigateListener();
412             thePrevMonthButton.addEventFilter(ActionEvent.ACTION, myListener);
413             theNextMonthButton.addEventFilter(ActionEvent.ACTION, myListener);
414             thePrevYearButton.addEventFilter(ActionEvent.ACTION, myListener);
415             theNextYearButton.addEventFilter(ActionEvent.ACTION, myListener);
416 
417             /* Restrict the margins */
418             thePrevMonthButton.getStyleClass().add(STYLE_BUTTON);
419             theNextMonthButton.getStyleClass().add(STYLE_BUTTON);
420             thePrevYearButton.getStyleClass().add(STYLE_BUTTON);
421             theNextYearButton.getStyleClass().add(STYLE_BUTTON);
422 
423             /* Create the struts */
424             Region myStrut1 = new Region();
425             Region myStrut2 = new Region();
426             setHgrow(myStrut1, Priority.ALWAYS);
427             setHgrow(myStrut2, Priority.ALWAYS);
428 
429             /* Add these elements into the HBox */
430             ObservableList<Node> myChildren = getChildren();
431             myChildren.add(thePrevYearButton);
432             myChildren.add(thePrevMonthButton);
433             myChildren.add(myStrut1);
434             myChildren.add(theDateLabel);
435             myChildren.add(myStrut2);
436             myChildren.add(theNextMonthButton);
437             myChildren.add(theNextYearButton);
438         }
439 
440         /**
441          * Build month details.
442          */
443         private void buildMonth() {
444             /* Obtain the active month */
445             LocalDate myBase = theConfig.getCurrentMonth();
446             Locale myLocale = theConfig.getLocale();
447 
448             /* Determine the display for the label */
449             String myMonth = myBase.getMonth().getDisplayName(TextStyle.FULL, myLocale);
450             String myYear = Integer.toString(myBase.getYear());
451 
452             /* Set the label */
453             theDateLabel.setText(myMonth
454                                  + ", "
455                                  + myYear);
456 
457             /* Access boundary dates */
458             LocalDate myEarliest = theConfig.getEarliestDate();
459             LocalDate myLatest = theConfig.getLatestDate();
460 
461             /* Enable/Disable buttons as required */
462             thePrevMonthButton.setDisable(JDateConfig.isSameMonth(myEarliest, myBase));
463             thePrevYearButton.setDisable(JDateConfig.isSameYear(myEarliest, myBase));
464             theNextMonthButton.setDisable(JDateConfig.isSameMonth(myLatest, myBase));
465             theNextYearButton.setDisable(JDateConfig.isSameYear(myLatest, myBase));
466         }
467 
468         /**
469          * Action Listener for buttons.
470          */
471         private class NavigateListener
472                 implements EventHandler<ActionEvent> {
473             @Override
474             public void handle(final ActionEvent e) {
475                 /* Access the event source */
476                 Object src = e.getSource();
477 
478                 /* If the button is previous month */
479                 if (thePrevMonthButton.equals(src)) {
480                     /* Adjust the month */
481                     theConfig.previousMonth();
482                     theDialog.buildMonth();
483                 } else if (theNextMonthButton.equals(src)) {
484                     /* Adjust the month */
485                     theConfig.nextMonth();
486                     theDialog.buildMonth();
487                 } else if (thePrevYearButton.equals(src)) {
488                     /* Adjust the month */
489                     theConfig.previousYear();
490                     theDialog.buildMonth();
491                 } else if (theNextYearButton.equals(src)) {
492                     /* Adjust the month */
493                     theConfig.nextYear();
494                     theDialog.buildMonth();
495                 }
496             }
497         }
498     }
499 
500     /**
501      * Month Panel.
502      */
503     private static final class PanelMonth
504             extends GridPane {
505         /**
506          * The panel style.
507          */
508         private static final String STYLE_PANEL = "-jdd-month";
509 
510         /**
511          * The header style.
512          */
513         private static final String STYLE_HEADER = "-jdd-hdr";
514 
515         /**
516          * Number of days in week.
517          */
518         private static final int DAYS_IN_WEEK = 7;
519 
520         /**
521          * Maximum # of weeks in month.
522          */
523         private static final int MAX_WEEKS_IN_MONTH = 6;
524 
525         /**
526          * Tile Width.
527          */
528         private static final int WIDTH_TILE = 22;
529 
530         /**
531          * The Dialog.
532          */
533         private final JDateDialog theDialog;
534 
535         /**
536          * The Date Configuration.
537          */
538         private final JDateConfig theConfig;
539 
540         /**
541          * The Array of Days.
542          */
543         private final DayOfWeek[] theDaysOfWk = new DayOfWeek[DAYS_IN_WEEK];
544 
545         /**
546          * The Array of Day Names.
547          */
548         private final Label[] theHdrs = new Label[DAYS_IN_WEEK];
549 
550         /**
551          * The Array of Day Labels.
552          */
553         private final PanelDay[][] theDays = new PanelDay[MAX_WEEKS_IN_MONTH][DAYS_IN_WEEK];
554 
555         /**
556          * The Active number of rows.
557          */
558         private int theNumRows = MAX_WEEKS_IN_MONTH;
559 
560         /**
561          * Constructor.
562          * @param pDialog the owning dialog
563          */
564         private PanelMonth(final JDateDialog pDialog) {
565             /* Store parameters */
566             theDialog = pDialog;
567 
568             /* Store the Date Configuration */
569             theConfig = pDialog.getDateConfig();
570 
571             /* Define style of GridPane */
572             getStyleClass().add(STYLE_PANEL);
573 
574             /* Add the Names to the layout */
575             for (int iCol = 0; iCol < DAYS_IN_WEEK; iCol++) {
576                 Label myDay = new Label();
577                 myDay.setPrefWidth(WIDTH_TILE);
578                 theHdrs[iCol] = myDay;
579                 add(myDay, iCol, 0);
580             }
581 
582             /* Add the Days to the layout */
583             for (int iRow = 0; iRow < MAX_WEEKS_IN_MONTH; iRow++) {
584                 for (int iCol = 0; iCol < DAYS_IN_WEEK; iCol++) {
585                     PanelDay myDay = new PanelDay(theDialog);
586                     theDays[iRow][iCol] = myDay;
587                     add(myDay, iCol, iRow + 1);
588                 }
589             }
590 
591             /* Build the Day Names */
592             buildDayNames();
593         }
594 
595         /**
596          * Is the DayOfWeek a Weekend day.
597          * @param pDoW the day of the week
598          * @return true/false
599          */
600         private static boolean isWeekend(final DayOfWeek pDoW) {
601             switch (pDoW) {
602                 case SATURDAY:
603                 case SUNDAY:
604                     return true;
605                 default:
606                     return false;
607             }
608         }
609 
610         /**
611          * obtain column number for DayOfWeek.
612          * @param pDoW the day of the week
613          * @return the column number
614          */
615         private int getDayColumn(final DayOfWeek pDoW) {
616             for (int i = 0; i < DAYS_IN_WEEK; i++) {
617                 if (theDaysOfWk[i] == pDoW) {
618                     return i;
619                 }
620             }
621             return -1;
622         }
623 
624         /**
625          * Build the month.
626          */
627         private void buildMonth() {
628             /* Obtain the active month */
629             LocalDate myCurr = theConfig.getCurrentMonth();
630 
631             /* Access the interesting days of the month */
632             int iCurrent = theConfig.getCurrentDay();
633             int iSelected = theConfig.getSelectedDay();
634             int iEarliest = theConfig.getEarliestDay();
635             int iLatest = theConfig.getLatestDay();
636 
637             /* Move to the start of the week */
638             DayOfWeek myWeekDay = myCurr.getDayOfWeek();
639             int iStart = getDayColumn(myWeekDay);
640             if (iStart > 0) {
641                 myCurr = myCurr.minusDays(iStart);
642             }
643 
644             /* Loop through initial columns */
645             int iCol = 0;
646             for (int iDay = myCurr.getDayOfMonth(); iCol < iStart; iCol++, iDay++, myCurr = myCurr.plusDays(1)) {
647                 /* Access the label */
648                 PanelDay myLabel = theDays[0][iCol];
649 
650                 /* Reset the day and set no day */
651                 myLabel.resetDay(false);
652                 myLabel.setDay(iDay, false);
653             }
654 
655             /* Loop through the days of the month */
656             int iRow = 0;
657             int iMonth = myCurr.getMonthValue();
658             for (int iDay = 1; iMonth == myCurr.getMonthValue(); iCol++, iDay++, myCurr = myCurr.plusDays(1)) {
659                 /* Reset column if necessary */
660                 if (iCol >= DAYS_IN_WEEK) {
661                     iRow++;
662                     iCol = 0;
663                 }
664 
665                 /* Access the label */
666                 PanelDay myLabel = theDays[iRow][iCol];
667 
668                 /* Reset the day */
669                 myLabel.resetDay(true);
670 
671                 if (iSelected == iDay) {
672                     myLabel.setSelected();
673                 } else if (iCurrent == iDay) {
674                     myLabel.setCurrent();
675                 } else if (isWeekend(myCurr.getDayOfWeek())) {
676                     myLabel.setWeekend();
677                 }
678 
679                 /* Determine whether the day is select-able */
680                 boolean isSelectable = true;
681                 if ((iEarliest > 0)
682                     && (iDay < iEarliest)) {
683                     isSelectable = false;
684                 } else if ((iLatest > 0)
685                            && (iDay > iLatest)) {
686                     isSelectable = false;
687                 }
688 
689                 /* Set text */
690                 myLabel.setDay(iDay, isSelectable);
691             }
692 
693             /* Loop through remaining columns in row */
694             for (int iDay = 1; iCol < DAYS_IN_WEEK; iCol++, iDay++) {
695                 /* Access the label */
696                 PanelDay myLabel = theDays[iRow][iCol];
697 
698                 /* Reset the day and set no day */
699                 myLabel.resetDay(false);
700                 myLabel.setDay(iDay, false);
701             }
702 
703             /* Resize to the number of rows */
704             reSizeRows(iRow + 1);
705         }
706 
707         /**
708          * build Day names.
709          */
710         private void buildDayNames() {
711             /* Get todays date */
712             Locale myLocale = theConfig.getLocale();
713             Calendar myDate = Calendar.getInstance(myLocale);
714             int myStart = myDate.getFirstDayOfWeek();
715             if (myStart == Calendar.SUNDAY) {
716                 myStart += DAYS_IN_WEEK;
717             }
718 
719             /* Build the array of the days of the week */
720             DayOfWeek myDoW = DayOfWeek.of(myStart - 1);
721             for (int iDay = 0; iDay < DAYS_IN_WEEK; iDay++, myDoW = myDoW.plus(1)) {
722                 /* Store the day into the array */
723                 theDaysOfWk[iDay] = myDoW;
724             }
725 
726             /* Loop through the labels */
727             for (int iCol = 0; iCol < DAYS_IN_WEEK; iCol++) {
728                 /* Access the label */
729                 Label myLabel = theHdrs[iCol];
730 
731                 /* Reset classes */
732                 ObservableList<String> myStyles = myLabel.getStyleClass();
733                 myStyles.clear();
734                 myStyles.add(STYLE_HEADER);
735 
736                 /* Access the required name */
737                 myDoW = theDaysOfWk[iCol];
738                 TextStyle myStyle = theConfig.showNarrowDays()
739                                                                ? TextStyle.NARROW
740                                                                : TextStyle.SHORT;
741                 String myName = myDoW.getDisplayName(myStyle, myLocale);
742 
743                 /* Set the name */
744                 myLabel.setText(myName);
745 
746                 /* Set weekend if required */
747                 if (isWeekend(myDoW)) {
748                     myStyles.add(PanelDay.STYLE_WEEKEND);
749                 }
750             }
751         }
752 
753         /**
754          * ReSize the number of visible rows.
755          * @param iNumRows number of visible rows
756          */
757         private void reSizeRows(final int iNumRows) {
758             /* Access the children */
759             ObservableList<Node> myNodes = getChildren();
760 
761             /* Hide any visible rows that should now be hidden */
762             while (iNumRows < theNumRows) {
763                 /* Decrement number of rows */
764                 theNumRows--;
765 
766                 /* Loop through remaining rows */
767                 for (PanelDay myDay : theDays[theNumRows]) {
768                     /* Remove from panel */
769                     myNodes.remove(myDay);
770                 }
771             }
772 
773             /* Show any hidden rows that should now be visible */
774             while (iNumRows > theNumRows) {
775                 /* Increment number of rows */
776                 theNumRows++;
777 
778                 /* Loop through remaining rows */
779                 int iCol = 0;
780                 for (PanelDay myDay : theDays[theNumRows - 1]) {
781                     /* Add to panel */
782                     add(myDay, iCol++, theNumRows);
783                 }
784             }
785 
786             /* RePack the Dialog */
787             theDialog.sizeToScene();
788         }
789     }
790 
791     /**
792      * Panel class representing a single day in the panel.
793      */
794     private static final class PanelDay
795             extends Label {
796         /**
797          * The panel style.
798          */
799         private static final String STYLE_PANEL = "-jdd-day";
800 
801         /**
802          * The inactive style.
803          */
804         private static final String STYLE_INACTIVE = "-jdd-inactive";
805 
806         /**
807          * The selected style.
808          */
809         private static final String STYLE_SELECTED = "-jdd-selected";
810 
811         /**
812          * The current style.
813          */
814         private static final String STYLE_CURRENT = "-jdd-current";
815 
816         /**
817          * The weekend style.
818          */
819         private static final String STYLE_WEEKEND = "-jdd-weekend";
820 
821         /**
822          * The Dialog.
823          */
824         private final JDateDialog theDialog;
825 
826         /**
827          * The day of the month.
828          */
829         private int theDay = -1;
830 
831         /**
832          * Is the item Select-able?
833          */
834         private boolean isSelectable = false;
835 
836         /**
837          * Constructor.
838          * @param pDialog the owning dialog
839          */
840         protected PanelDay(final JDateDialog pDialog) {
841             /* Store parameters */
842             theDialog = pDialog;
843 
844             /* Set width */
845             setPrefWidth(PanelMonth.WIDTH_TILE);
846             addEventFilter(MouseEvent.MOUSE_CLICKED, new MouseEventHandler());
847         }
848 
849         /**
850          * Reset a Day Label.
851          * @param isActive true/false
852          */
853         private void resetDay(final boolean isActive) {
854             setTooltip(null);
855             getStyleClass().clear();
856             getStyleClass().add(STYLE_PANEL);
857             if (!isActive) {
858                 getStyleClass().add(STYLE_INACTIVE);
859             }
860         }
861 
862         /**
863          * Set day for label.
864          * @param pDay the Day number
865          * @param pSelectable is the day select-able
866          */
867         private void setDay(final int pDay,
868                             final boolean pSelectable) {
869             /* Record the day */
870             theDay = pDay;
871             isSelectable = pSelectable;
872 
873             /* Set the text for the item */
874             if (pDay > 0) {
875                 setText(Integer.toString(theDay));
876             } else {
877                 setText("");
878             }
879 
880             /* Enable/Disable the label */
881             setDisable(!isSelectable);
882         }
883 
884         /**
885          * Set weekend.
886          */
887         private void setWeekend() {
888             getStyleClass().add(STYLE_WEEKEND);
889         }
890 
891         /**
892          * Set selected day.
893          */
894         private void setSelected() {
895             getStyleClass().add(STYLE_SELECTED);
896             setTooltip(new Tooltip(NLS_SELECTEDDAY));
897         }
898 
899         /**
900          * Set current day.
901          */
902         private void setCurrent() {
903             getStyleClass().add(STYLE_CURRENT);
904             setTooltip(new Tooltip(NLS_CURRENTDAY));
905         }
906 
907         /**
908          * Mouse event handler.
909          */
910         private class MouseEventHandler
911                 implements EventHandler<MouseEvent> {
912             @Override
913             public void handle(final MouseEvent event) {
914                 theDialog.setSelected(theDay);
915             }
916         }
917     }
918 }