Search code examples
javaswingcalendarlocalejcalendar

How to set custom week-start in JCalendar?


I am having trouble setting custom first-day-of-week, in JCalendar. The first-day-of-week does change if I change locale. However changing the first-day-of-week in the underlying calendar, has no effect.

Here is a short demonstration code:

public class TestJChooser extends JFrame {

    /**
     *
     */
    public TestJChooser() {

        setLayout(new BorderLayout(5,5));
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        Locale locale = Locale.forLanguageTag("de-DE");

        Calendar calendar = Calendar.getInstance(locale);
        calendar.setFirstDayOfWeek(Calendar.TUESDAY);

        JCalendar jCal = new JCalendar(calendar);
        jCal.setLocale(locale);
        jCal.setPreferredSize(new Dimension(500, 400));
        jCal.getDayChooser().setDayBordersVisible(true);
        jCal.setTodayButtonVisible(true);
        getContentPane().add(jCal,BorderLayout.CENTER);

        pack();
        setVisible(true);

    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        new TestJChooser();

    }
}

Changing the value of

   calendar.setFirstDayOfWeek(Calendar.TUESDAY);

Does not change the first day of the week in JCalendar, nor the weekend day.


Solution

  • To achieve the functionality I needed with com.toedter.calendar.JDateChooser I had to extend it.

    First a demo: set Sunday as the first day of the week (although it is set to Monday by the locale) . The test class:

        public class TestJXChooser extends JFrame {
    
            /**
             *
             */
            public TestJXChooser(){
    
                setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
    
                getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
                getContentPane().setLayout(new BorderLayout(5,5));
    
                //set locale and calendar
                Locale locale = Locale.forLanguageTag("de-DE"); 
    
                Calendar cal = Calendar.getInstance(locale);
                cal.setTime(new Date());
                //set first day of week
                int firstWeekDay = Calendar.SUNDAY;
                cal.setFirstDayOfWeek(firstWeekDay);
    
                //-- Toedter JCalendar
    
                JCalendar jCalendar = new JCalendarExt(null, locale, true, true, false);
                jCalendar.setCalendar(cal);
                jCalendar.setPreferredSize(new Dimension(120, 160));
                jCalendar.getDayChooser().setDayBordersVisible(true);
                jCalendar.setTodayButtonVisible(true);
                jCalendar.setWeekOfYearVisible(false);
    
                getContentPane().add(jCalendar,BorderLayout.CENTER);
    
                //-- Toedter JDateChooser
                JCalendar jCalendar2 = new JCalendarExt(null, locale, true, true, false);
                jCalendar2.setCalendar(cal);
                JDateChooser dateChooser = new JDateChooser(jCalendar2, null , "dd.mm.yyyy",null);
                dateChooser.setLocale(locale);
    
                getContentPane().add(dateChooser,BorderLayout.SOUTH);
    
                pack();
                setVisible(true);
    
            }
    
            /**
             * @param args
             */
            public static void main(String[] args) {
    
                new TestJXChooser();
    
            }
    
        }
    

    The result can be seen in the image.

    set Sunday as the first day of the week
    The second image demonstrates setting the first-day-of-week to Tuesday.

    setting the first-day-of-week to Tuesday
    Two classes were extended. The class extending JCalendar:

        /**
         * Extended to gain control on week-first-day.
         * It also enables the option to display in different color the
         * last-day-of-week, rather than <code>JCalendar</code> default which is
         * always display Sunday in a different color.
         *
         * @version
         * $Log: JCalendarExt.java,v $
         *
         *
         * @author Ofer Yuval
         * 27 Nov 2015
         *
         */
        public class JCalendarExt extends JCalendar {
    
            /**
             *
             * @param date
             * @param locale
             * @param monthSpinner
             * @param weekOfYearVisible
             * @param colorWeekend
             *      <br>When false, week-first-day will be painted in red, as in  <code>JDayChooser</code>.
             *      <br>When true, week-last-day will be painted in red.
             */
    
            public JCalendarExt(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible,
                    boolean colorWeekend) {
    
                super(date, locale, monthSpinner, weekOfYearVisible);
    
                remove(dayChooser);
    
                //add the extended date chooser
                dayChooser = new JDayChooserExt(weekOfYearVisible) ;
                dayChooser.addPropertyChangeListener(this);
                ((JDayChooserExt) dayChooser).setColorWeekend(colorWeekend);
    
                monthChooser.setDayChooser(dayChooser);
                yearChooser.setDayChooser(dayChooser);
    
                add(dayChooser, BorderLayout.CENTER);
    
            }
    
            @Override
            public void setCalendar(Calendar c) {
    
                getDayChooser().setCalendar(c);
                super.setCalendar(c);
            }
    
        }
    

    And the class extending JDayChooser:

        /**
         *
         * @version
         * $Log: JDayChooserExt.java,v $
         *
         *
         * @author Ofer Yuval
         * 27 Nov 2015
         *
         */
        public class JDayChooserExt extends JDayChooser {
    
            /**
             * When false, week-first-day will be painted in red, as in  <code>JDayChooser</code>.
             * When true, week-last-day will be painted in red.
             */
            private boolean isColorWeekend = false;
    
            /**
             * @param weekOfYearVisible
             */
            public JDayChooserExt(boolean weekOfYearVisible) {
    
                super(weekOfYearVisible);
            }
    
            /**
             * Initializes the locale specific names for the days of the week.
             */
            @Override
            protected void init() {
    
                JButton testButton = new JButton();
                oldDayBackgroundColor = testButton.getBackground();
                selectedColor = new Color(160, 160, 160);
                drawDayNames();
                drawDays();
    
            }
    
            /**
             * Draws the day names of the day columns.
             */
            private void drawDayNames() {
    
                DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
                dayNames = dateFormatSymbols.getShortWeekdays();
    
                int Day = calendar.getFirstDayOfWeek();//firstDayOfWeek;
    
                int coloredDay = (isColorWeekend ) ?  Day -1 : Day;
                if(coloredDay <= 0) {
                    coloredDay += 7;
                }
    
    
                for (int i = 0; i < 7; i++) {
                    if ((maxDayCharacters > 0) && (maxDayCharacters < 5)) {
                        if (dayNames[Day].length() >= maxDayCharacters) {
                            dayNames[Day] = dayNames[Day]
                                    .substring(0, maxDayCharacters);
                        }
                    }
    
                    days[i].setText(dayNames[Day]);
    
                    if (Day == coloredDay) {
                        days[i].setForeground(sundayForeground);
                    } else {
                        days[i].setForeground(weekdayForeground);
                    }
    
                    if (Day < 7) {
                        Day++;
                    } else {
                        Day -= 6;
                    }
                }
            }
    
            /**
             * @param isColorWeekend the isColorWeekend to set
             */
            public void setColorWeekend(boolean isColorWeekend) {
                this.isColorWeekend = isColorWeekend;
            }
    
    
            // ///////////////////////////////////////////////////////////
            // ////////////// DecoratorButton class //////////////////////
            // ///////////////////////////////////////////////////////////
    
            class DecoratorButton extends JButton {
                private static final long serialVersionUID = -5306477668406547496L;
    
                public DecoratorButton() {
                    setBackground(decorationBackgroundColor);
                    setContentAreaFilled(decorationBackgroundVisible);
                    setBorderPainted(decorationBordersVisible);
                }
    
                @Override
                public void addMouseListener(MouseListener l) {
                }
    
                @Override
                public boolean isFocusable() {
                    return false;
                }
    
                @Override
                public void paint(Graphics g) {
                    if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
                        // this is a hack to get the background painted
                        // when using Windows Look & Feel
                        if (decorationBackgroundVisible) {
                            g.setColor(decorationBackgroundColor);
                        } else {
                            g.setColor(days[7].getBackground());
                        }
                        g.fillRect(0, 0, getWidth(), getHeight());
                        if (isBorderPainted()) {
                            setContentAreaFilled(true);
                        } else {
                            setContentAreaFilled(false);
                        }
                    }
                    super.paint(g);
                }
            };
        }