org.pentaho.mantle.client.dialogs.scheduling.RecurrenceEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.mantle.client.dialogs.scheduling.RecurrenceEditor.java

Source

/*!
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright (c) 2002-2017 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.mantle.client.dialogs.scheduling;

import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import org.pentaho.gwt.widgets.client.controls.DateRangeEditor;
import org.pentaho.gwt.widgets.client.controls.ErrorLabel;
import org.pentaho.gwt.widgets.client.controls.TimePicker;
import org.pentaho.gwt.widgets.client.ui.ICallback;
import org.pentaho.gwt.widgets.client.ui.IChangeHandler;
import org.pentaho.gwt.widgets.client.utils.CronParseException;
import org.pentaho.gwt.widgets.client.utils.CronParser;
import org.pentaho.gwt.widgets.client.utils.CronParser.RecurrenceType;
import org.pentaho.gwt.widgets.client.utils.EnumException;
import org.pentaho.gwt.widgets.client.utils.StringUtils;
import org.pentaho.gwt.widgets.client.utils.TimeUtil;
import org.pentaho.gwt.widgets.client.utils.TimeUtil.DayOfWeek;
import org.pentaho.gwt.widgets.client.utils.TimeUtil.MonthOfYear;
import org.pentaho.gwt.widgets.client.utils.TimeUtil.TimeOfDay;
import org.pentaho.gwt.widgets.client.utils.TimeUtil.WeekOfMonth;
import org.pentaho.mantle.client.messages.Messages;

import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Steven Barkdull
 * 
 */

@SuppressWarnings("deprecation")
public class RecurrenceEditor extends VerticalPanel implements IChangeHandler {
    public static final int VALUE_OF_SUNDAY = 1;

    private static final String SCHEDULE_EDITOR_CAPTION_PANEL = "schedule-editor-caption-panel"; //$NON-NLS-1$
    private static final String DOW_CHECKBOX = "day-of-week-checkbox"; //$NON-NLS-1$
    private static final String EVERY_TXTBOX = "every-txtbox";
    private static final String RECUR_PATTERN_HP = "recur-pattern-hp";

    protected TimePicker startTimePicker = null;

    protected SecondlyRecurrenceEditor secondlyEditor = null;

    protected MinutelyRecurrenceEditor minutelyEditor = null;

    protected HourlyRecurrenceEditor hourlyEditor = null;

    protected DailyRecurrenceEditor dailyEditor = null;

    protected WeeklyRecurrenceEditor weeklyEditor = null;

    protected MonthlyRecurrenceEditor monthlyEditor = null;

    protected YearlyRecurrenceEditor yearlyEditor = null;

    protected DateRangeEditor dateRangeEditor = null;

    protected TemporalValue temporalState = null;
    private DeckPanel deckPanel = null;

    private static final String SPACE = " "; //$NON-NLS-1$

    private ICallback<IChangeHandler> onChangeHandler;

    protected Map<TemporalValue, Panel> temporalPanelMap = new LinkedHashMap<TemporalValue, Panel>();

    public enum TemporalValue {
        SECONDS(0, Messages.getString("schedule.seconds")), MINUTES(1,
                Messages.getString("schedule.minutes")), HOURS(2, Messages.getString("schedule.hours")), DAILY(3,
                        Messages.getString("schedule.daily")), WEEKLY(4,
                                Messages.getString("schedule.weekly")), MONTHLY(5,
                                        Messages.getString("schedule.monthly")), YEARLY(6,
                                                Messages.getString("schedule.yearly"));

        private TemporalValue(int value, String name) {
            this.value = value;
            this.name = name;
        }

        private final int value;

        private final String name;

        private static TemporalValue[] temporalValues = { SECONDS, MINUTES, HOURS, DAILY, WEEKLY, MONTHLY, YEARLY };

        public int value() {
            return value;
        }

        public String toString() {
            return name;
        }

        public static TemporalValue get(int idx) {
            return temporalValues[idx];
        }

        public static int length() {
            return temporalValues.length;
        }

        public static TemporalValue stringToTemporalValue(String temporalValue) throws EnumException {
            for (TemporalValue v : EnumSet.range(TemporalValue.SECONDS, TemporalValue.YEARLY)) {
                if (v.toString().equals(temporalValue)) {
                    return v;
                }
            }
            throw new EnumException(Messages.getString("schedule.invalidTemporalValue", temporalValue));
        }
    } /* end enum */

    private static final String DAILY_RB_GROUP = "daily-group"; //$NON-NLS-1$

    private static final String MONTHLY_RB_GROUP = "monthly-group"; //$NON-NLS-1$

    public RecurrenceEditor(final TimePicker startTimePicker) {
        super();
        this.setWidth("100%"); //$NON-NLS-1$

        Widget p = createRecurrencePanel();
        add(p);

        Date now = new Date();
        dateRangeEditor = new DateRangeEditor(now);
        add(dateRangeEditor);

        this.startTimePicker = startTimePicker;

        configureOnChangeHandler();
    }

    public void reset(Date d) {

        startTimePicker.setHour("12"); //$NON-NLS-1$
        startTimePicker.setMinute("00"); //$NON-NLS-1$
        startTimePicker.setTimeOfDay(TimeUtil.TimeOfDay.AM);

        dateRangeEditor.reset(d);

        secondlyEditor.reset();
        minutelyEditor.reset();
        hourlyEditor.reset();
        dailyEditor.reset();
        weeklyEditor.reset();
        monthlyEditor.reset();
        yearlyEditor.reset();
    }

    /**
     * 
     * @param recurrenceStr
     * @throws EnumException
     *           thrown if recurrenceTokens[0] is not a valid ScheduleType String.
     */
    public void inititalizeWithRecurrenceString(String recurrenceStr) throws EnumException {
        String[] recurrenceTokens = recurrenceStr.split("\\s"); //$NON-NLS-1$

        setStartTime(recurrenceTokens[1], recurrenceTokens[2], recurrenceTokens[3]);

        RecurrenceType rt = RecurrenceType.stringToScheduleType(recurrenceTokens[0]);

        switch (rt) {
        case EveryWeekday:
            setEveryWeekdayRecurrence(recurrenceTokens);
            break;
        case WeeklyOn:
            setWeeklyOnRecurrence(recurrenceTokens);
            break;
        case DayNOfMonth:
            setDayNOfMonthRecurrence(recurrenceTokens);
            break;
        case NthDayNameOfMonth:
            setNthDayNameOfMonthRecurrence(recurrenceTokens);
            break;
        case LastDayNameOfMonth:
            setLastDayNameOfMonthRecurrence(recurrenceTokens);
            break;
        case EveryMonthNameN:
            setEveryMonthNameNRecurrence(recurrenceTokens);
            break;
        case NthDayNameOfMonthName:
            setNthDayNameOfMonthNameRecurrence(recurrenceTokens);
            break;
        case LastDayNameOfMonthName:
            setLastDayNameOfMonthNameRecurrence(recurrenceTokens);
            break;
        default:
        }
    }

    private void setStartTime(String seconds, String minutes, String hours) {
        TimeOfDay td = TimeUtil.getTimeOfDayBy0To23Hour(hours);
        int intHours = Integer.parseInt(hours);
        int intTwelveHour = TimeUtil.to12HourClock(intHours); // returns 0..11
        startTimePicker.setHour(Integer.toString(TimeUtil.map0Through11To12Through11(intTwelveHour)));
        startTimePicker.setMinute(minutes);
        startTimePicker.setTimeOfDay(td);
    }

    private void setEveryWeekdayRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.DAILY);
        dailyEditor.setEveryWeekday();
    }

    private void setWeeklyOnRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.WEEKLY);
        String days = recurrenceTokens[4];
        weeklyEditor.setCheckedDaysAsString(days, VALUE_OF_SUNDAY);
    }

    private void setDayNOfMonthRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.MONTHLY);
        monthlyEditor.setDayNOfMonth();
        String dayNOfMonth = recurrenceTokens[4];
        monthlyEditor.setDayOfMonth(dayNOfMonth);
    }

    private void setNthDayNameOfMonthRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.MONTHLY);
        monthlyEditor.setNthDayNameOfMonth();
        monthlyEditor.setWeekOfMonth(WeekOfMonth.get(Integer.parseInt(recurrenceTokens[5]) - 1));
        monthlyEditor.setDayOfWeek(DayOfWeek.get(Integer.parseInt(recurrenceTokens[4]) - 1));
    }

    private void setLastDayNameOfMonthRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.MONTHLY);
        monthlyEditor.setNthDayNameOfMonth();
        monthlyEditor.setWeekOfMonth(WeekOfMonth.LAST);
        monthlyEditor.setDayOfWeek(DayOfWeek.get(Integer.parseInt(recurrenceTokens[4]) - 1));
    }

    private void setEveryMonthNameNRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.YEARLY);
        yearlyEditor.setEveryMonthOnNthDay();
        yearlyEditor.setDayOfMonth(recurrenceTokens[4]);
        yearlyEditor.setMonthOfYear0(MonthOfYear.get(Integer.parseInt(recurrenceTokens[5]) - 1));
    }

    private void setNthDayNameOfMonthNameRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.YEARLY);
        yearlyEditor.setNthDayNameOfMonthName();
        yearlyEditor.setMonthOfYear1(MonthOfYear.get(Integer.parseInt(recurrenceTokens[6]) - 1));
        yearlyEditor.setWeekOfMonth(WeekOfMonth.get(Integer.parseInt(recurrenceTokens[5]) - 1));
        yearlyEditor.setDayOfWeek(DayOfWeek.get(Integer.parseInt(recurrenceTokens[4]) - 1));
    }

    private void setLastDayNameOfMonthNameRecurrence(String[] recurrenceTokens) {
        setTemporalState(TemporalValue.YEARLY);
        yearlyEditor.setNthDayNameOfMonthName();
        yearlyEditor.setMonthOfYear1(MonthOfYear.get(Integer.parseInt(recurrenceTokens[5]) - 1));
        yearlyEditor.setWeekOfMonth(WeekOfMonth.LAST);
        yearlyEditor.setDayOfWeek(DayOfWeek.get(Integer.parseInt(recurrenceTokens[4]) - 1));
    }

    /**
     * 
     * @param repeatInSecs
     */
    public void inititalizeWithRepeatInSecs(int repeatInSecs) {

        TemporalValue currentVal;
        long repeatTime;
        if (TimeUtil.isSecondsWholeDay(repeatInSecs)) {
            repeatTime = TimeUtil.secsToDays(repeatInSecs);
            currentVal = TemporalValue.DAILY;
            dailyEditor.setRepeatValue(Long.toString(repeatTime));
        } else {
            SimpleRecurrencePanel p = null;
            if (TimeUtil.isSecondsWholeHour(repeatInSecs)) {
                repeatTime = TimeUtil.secsToHours(repeatInSecs);
                currentVal = TemporalValue.HOURS;
            } else if (TimeUtil.isSecondsWholeMinute(repeatInSecs)) {
                repeatTime = TimeUtil.secsToMinutes(repeatInSecs);
                currentVal = TemporalValue.MINUTES;
            } else {
                // the repeat time is seconds
                repeatTime = repeatInSecs;
                currentVal = TemporalValue.SECONDS;
            }
            p = (SimpleRecurrencePanel) temporalPanelMap.get(currentVal);
            p.setValue(Long.toString(repeatTime));
        }
        setTemporalState(currentVal);
    }

    private Widget createRecurrencePanel() {

        CaptionPanel recurrenceGB = new CaptionPanel(Messages.getString("schedule.recurrencePattern"));
        recurrenceGB.setStyleName(SCHEDULE_EDITOR_CAPTION_PANEL);

        deckPanel = new DeckPanel();
        recurrenceGB.add(deckPanel);

        secondlyEditor = new SecondlyRecurrenceEditor();
        minutelyEditor = new MinutelyRecurrenceEditor();
        hourlyEditor = new HourlyRecurrenceEditor();
        dailyEditor = new DailyRecurrenceEditor();
        weeklyEditor = new WeeklyRecurrenceEditor();
        monthlyEditor = new MonthlyRecurrenceEditor();
        yearlyEditor = new YearlyRecurrenceEditor();

        createTemporalMap();

        deckPanel.add(secondlyEditor);
        deckPanel.add(minutelyEditor);
        deckPanel.add(hourlyEditor);

        deckPanel.add(dailyEditor);
        deckPanel.add(weeklyEditor);
        deckPanel.add(monthlyEditor);
        deckPanel.add(yearlyEditor);

        deckPanel.showWidget(0);

        return recurrenceGB;
    }

    private void createTemporalMap() {
        // must come after creation of temporal panels
        assert dailyEditor != null : "Temporal panels must be initialized before calling createTemporalCombo."; //$NON-NLS-1$

        temporalPanelMap.put(TemporalValue.SECONDS, secondlyEditor);
        temporalPanelMap.put(TemporalValue.MINUTES, minutelyEditor);
        temporalPanelMap.put(TemporalValue.HOURS, hourlyEditor);
        temporalPanelMap.put(TemporalValue.DAILY, dailyEditor);
        temporalPanelMap.put(TemporalValue.WEEKLY, weeklyEditor);
        temporalPanelMap.put(TemporalValue.MONTHLY, monthlyEditor);
        temporalPanelMap.put(TemporalValue.YEARLY, yearlyEditor);
    }

    public class SimpleRecurrencePanel extends VerticalPanel implements IChangeHandler {
        private TextBox valueTb = new TextBox();
        private ErrorLabel valueLabel = null;
        private ICallback<IChangeHandler> onChangeHandler;

        public SimpleRecurrencePanel(String strLabel) {

            HorizontalPanel hp = new HorizontalPanel();
            hp.setStyleName(RECUR_PATTERN_HP);
            Label l = new Label(Messages.getString("schedule.every"));
            l.setStyleName("startLabel"); //$NON-NLS-1$
            hp.add(l);

            valueTb.setTitle(Messages.getString("schedule.numberOfXToRepeat", strLabel));
            valueTb.setStyleName(EVERY_TXTBOX);
            hp.add(valueTb);

            l = new Label(strLabel);
            l.setStyleName("endLabel"); //$NON-NLS-1$
            hp.add(l);

            valueLabel = new ErrorLabel(hp);
            add(valueLabel);

            configureOnChangeHandler();
        }

        public String getValue() {
            return valueTb.getText();
        }

        public void setValue(String val) {
            valueTb.setText(val);
        }

        public void reset() {
            setValue(""); //$NON-NLS-1$
        }

        public void setValueError(String errorMsg) {
            valueLabel.setErrorMsg(errorMsg);
        }

        public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
            this.onChangeHandler = handler;
        }

        private void changeHandler() {
            if (null != onChangeHandler) {
                onChangeHandler.onHandle(this);
            }
        }

        private void configureOnChangeHandler() {
            final SimpleRecurrencePanel localThis = this;

            KeyboardListener keyboardListener = new KeyboardListener() {
                public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyPress(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyUp(Widget sender, char keyCode, int modifiers) {
                    localThis.changeHandler();
                }
            };

            valueTb.addKeyboardListener(keyboardListener);
        }
    }

    public class SecondlyRecurrenceEditor extends SimpleRecurrencePanel {
        public SecondlyRecurrenceEditor() {
            super(Messages.getString("seconds"));
        }
    }

    public class MinutelyRecurrenceEditor extends SimpleRecurrencePanel {
        public MinutelyRecurrenceEditor() {
            super(Messages.getString("schedule.minuteOrMinutes"));
        }
    }

    public class HourlyRecurrenceEditor extends SimpleRecurrencePanel {
        public HourlyRecurrenceEditor() {
            super(Messages.getString("schedule.hourOrHours"));
        }
    }

    public class DailyRecurrenceEditor extends VerticalPanel implements IChangeHandler {

        private TextBox repeatValueTb = new TextBox();
        protected RadioButton everyNDaysRb = new RadioButton(DAILY_RB_GROUP, Messages.getString("schedule.every"));
        protected RadioButton everyWeekdayRb = new RadioButton(DAILY_RB_GROUP,
                Messages.getString("schedule.everyWeekDay"));
        private ErrorLabel repeatLabel = null;
        private ICallback<IChangeHandler> onChangeHandler;

        public DailyRecurrenceEditor() {
            HorizontalPanel hp = new HorizontalPanel();
            hp.setStyleName(RECUR_PATTERN_HP);
            hp.getElement().setId("daily-recur-hp");
            everyNDaysRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            everyNDaysRb.setChecked(true);
            hp.add(everyNDaysRb);

            repeatValueTb.setStyleName(EVERY_TXTBOX);
            repeatValueTb.setTitle(Messages.getString("schedule.numDaysToRepeat"));
            hp.add(repeatValueTb);

            Label l = new Label(Messages.getString("schedule.dayOrDays"));
            l.setStyleName("endLabel"); //$NON-NLS-1$
            hp.add(l);
            repeatLabel = new ErrorLabel(hp);
            add(repeatLabel);

            everyWeekdayRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            add(everyWeekdayRb);
            configureOnChangeHandler();
        }

        public void reset() {
            setRepeatValue(""); //$NON-NLS-1$
            setEveryNDays();
        }

        public String getRepeatValue() {
            return repeatValueTb.getText();
        }

        public void setRepeatValue(String repeatValue) {
            repeatValueTb.setText(repeatValue);
        }

        public void setEveryNDays() {
            everyNDaysRb.setChecked(true);
            everyWeekdayRb.setChecked(false);
        }

        public boolean isEveryNDays() {
            return everyNDaysRb.isChecked();
        }

        public void setEveryWeekday() {
            everyWeekdayRb.setChecked(true);
            everyNDaysRb.setChecked(false);
        }

        public boolean isEveryWeekday() {
            return everyWeekdayRb.isChecked();
        }

        public void setRepeatError(String errorMsg) {
            repeatLabel.setErrorMsg(errorMsg);
        }

        public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
            this.onChangeHandler = handler;
        }

        private void changeHandler() {
            if (null != onChangeHandler) {
                onChangeHandler.onHandle(this);
            }
        }

        private void configureOnChangeHandler() {
            final DailyRecurrenceEditor localThis = this;

            KeyboardListener keyboardListener = new KeyboardListener() {
                public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyPress(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyUp(Widget sender, char keyCode, int modifiers) {
                    localThis.changeHandler();
                }
            };

            ClickListener clickListener = new ClickListener() {
                public void onClick(Widget sender) {
                    localThis.changeHandler();
                }
            };

            repeatValueTb.addKeyboardListener(keyboardListener);
            everyNDaysRb.addClickListener(clickListener);
            everyNDaysRb.addKeyboardListener(keyboardListener);
            everyWeekdayRb.addClickListener(clickListener);
            everyWeekdayRb.addKeyboardListener(keyboardListener);
        }
    }

    public class WeeklyRecurrenceEditor extends VerticalPanel implements IChangeHandler {

        protected Map<DayOfWeek, CheckBox> dayToCheckBox = new HashMap<DayOfWeek, CheckBox>();
        private ErrorLabel everyWeekOnLabel = null;
        private ICallback<IChangeHandler> onChangeHandler;
        private static final String WEEKLY_RECUR = "weekly-recur";

        public WeeklyRecurrenceEditor() {
            setStyleName("weeklyRecurrencePanel"); //$NON-NLS-1$

            Label l = new Label(Messages.getString("schedule.recurEveryWeek"));
            everyWeekOnLabel = new ErrorLabel(l);
            l.setStyleName("startLabel"); //$NON-NLS-1$
            add(everyWeekOnLabel);

            FlexTable gp = new FlexTable();
            gp.getElement().setId(WEEKLY_RECUR);
            gp.setCellPadding(0);
            gp.setCellSpacing(0);
            // add Sun - Wed
            final int ITEMS_IN_ROW = 4;
            for (int ii = 0; ii < ITEMS_IN_ROW; ++ii) {
                DayOfWeek day = DayOfWeek.get(ii);
                CheckBox cb = new CheckBox(Messages.getString(day.toString()));
                cb.setStylePrimaryName(DOW_CHECKBOX);
                gp.setWidget(0, ii, cb);
                dayToCheckBox.put(day, cb);
            }
            // Add Thur - Sat
            for (int ii = ITEMS_IN_ROW; ii < DayOfWeek.length(); ++ii) {
                DayOfWeek day = DayOfWeek.get(ii);
                CheckBox cb = new CheckBox(Messages.getString(day.toString()));
                cb.setStylePrimaryName(DOW_CHECKBOX);
                gp.setWidget(1, ii - 4, cb);
                dayToCheckBox.put(day, cb);
            }
            add(gp);
            configureOnChangeHandler();
        }

        public void reset() {
            for (DayOfWeek d : dayToCheckBox.keySet()) {
                CheckBox cb = dayToCheckBox.get(d);
                cb.setChecked(false);
            }
        }

        public List<DayOfWeek> getCheckedDays() {
            ArrayList<DayOfWeek> checkedDays = new ArrayList<DayOfWeek>();
            for (DayOfWeek d : EnumSet.range(DayOfWeek.SUN, DayOfWeek.SAT)) {
                CheckBox cb = dayToCheckBox.get(d);
                if (cb.isChecked()) {
                    checkedDays.add(d);
                }
            }
            return checkedDays;
        }

        /**
         * 
         * @param valueOfSunday
         *          int used to adjust the starting point of the weekday sequence. If this value is 0, Sun-Sat maps to
         *          0-6, if this value is 1, Sun-Sat maps to 1-7, etc.
         * @return String comma separated list of numeric days of the week.
         */
        public String getCheckedDaysAsString(int valueOfSunday) {
            StringBuilder sb = new StringBuilder();
            for (DayOfWeek d : getCheckedDays()) {
                sb.append(Integer.toString(d.value() + valueOfSunday)).append(","); //$NON-NLS-1$
            }
            sb.deleteCharAt(sb.length() - 1);
            return sb.toString();
        }

        /**
         * 
         * @param valueOfSunday
         *          int used to adjust the starting point of the weekday sequence. If this value is 0, Sun-Sat maps to
         *          0-6, if this value is 1, Sun-Sat maps to 1-7, etc.
         * @return String comma separated list of numeric days of the week.
         */
        public void setCheckedDaysAsString(String strDays, int valueOfSunday) {
            String[] days = strDays.split(","); //$NON-NLS-1$
            for (String day : days) {
                int intDay = Integer.parseInt(day) - valueOfSunday;
                DayOfWeek dayOfWeek = DayOfWeek.get(intDay);
                CheckBox cb = dayToCheckBox.get(dayOfWeek);
                cb.setChecked(true);
            }
        }

        public int getNumCheckedDays() {
            int numCheckedDays = 0;
            // for ( DayOfWeek d : EnumSet.range( DayOfWeek.SUN, DayOfWeek.SAT) ) {
            for (Map.Entry<DayOfWeek, CheckBox> cbEntry : dayToCheckBox.entrySet()) {
                if (cbEntry.getValue().isChecked()) {
                    numCheckedDays++;
                }
            }
            return numCheckedDays;
        }

        public void setEveryDayOnError(String errorMsg) {
            everyWeekOnLabel.setErrorMsg(errorMsg);
        }

        public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
            this.onChangeHandler = handler;
        }

        private void changeHandler() {
            if (null != onChangeHandler) {
                onChangeHandler.onHandle(this);
            }
        }

        private void configureOnChangeHandler() {

            final WeeklyRecurrenceEditor localThis = this;

            KeyboardListener keyboardListener = new KeyboardListener() {
                public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyPress(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyUp(Widget sender, char keyCode, int modifiers) {
                    localThis.changeHandler();
                }
            };

            ClickListener clickListener = new ClickListener() {
                public void onClick(Widget sender) {
                    localThis.changeHandler();
                }
            };
            for (DayOfWeek d : dayToCheckBox.keySet()) {
                CheckBox cb = dayToCheckBox.get(d);
                cb.addClickListener(clickListener);
                cb.addKeyboardListener(keyboardListener);
            }
        }
    }

    public class MonthlyRecurrenceEditor extends VerticalPanel implements IChangeHandler {

        protected RadioButton dayNOfMonthRb = new RadioButton(MONTHLY_RB_GROUP, Messages.getString("schedule.day"));
        protected RadioButton nthDayNameOfMonthRb = new RadioButton(MONTHLY_RB_GROUP,
                Messages.getString("schedule.the"));
        private TextBox dayOfMonthTb = new TextBox();
        private ListBox whichWeekLb = createWhichWeekListBox();
        private ListBox dayOfWeekLb = createDayOfWeekListBox();
        private ErrorLabel dayNOfMonthLabel = null;
        private ICallback<IChangeHandler> onChangeHandler;

        public MonthlyRecurrenceEditor() {
            setSpacing(6);
            this.setStyleName(RECUR_PATTERN_HP);
            getElement().removeAttribute("cellpadding");

            HorizontalPanel hp = new HorizontalPanel();
            hp.getElement().setId("day-n-of-month-radio");
            dayNOfMonthRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            dayNOfMonthRb.setChecked(true);
            hp.add(dayNOfMonthRb);
            dayOfMonthTb.setStyleName(EVERY_TXTBOX);
            hp.add(dayOfMonthTb);
            Label l = new Label(Messages.getString("schedule.ofEveryMonth"));
            l.setStyleName("endLabel"); //$NON-NLS-1$
            hp.add(l);

            dayNOfMonthLabel = new ErrorLabel(hp);
            add(dayNOfMonthLabel);

            hp = new HorizontalPanel();
            nthDayNameOfMonthRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            hp.add(nthDayNameOfMonthRb);
            hp.add(whichWeekLb);

            dayOfWeekLb.getElement().setId("day-of-week-lb");
            hp.add(dayOfWeekLb);
            l = new Label(Messages.getString("schedule.ofEveryMonth"));
            l.setStyleName("endLabel"); //$NON-NLS-1$
            hp.add(l);
            add(hp);
            configureOnChangeHandler();
        }

        public void reset() {
            setDayNOfMonth();
            setDayOfMonth(""); //$NON-NLS-1$
            setWeekOfMonth(WeekOfMonth.FIRST);
            setDayOfWeek(DayOfWeek.SUN);
        }

        public void setDayNOfMonth() {
            dayNOfMonthRb.setChecked(true);
            nthDayNameOfMonthRb.setChecked(false);
        }

        public boolean isDayNOfMonth() {
            return dayNOfMonthRb.isChecked();
        }

        public void setNthDayNameOfMonth() {
            nthDayNameOfMonthRb.setChecked(true);
            dayNOfMonthRb.setChecked(false);
        }

        public boolean isNthDayNameOfMonth() {
            return nthDayNameOfMonthRb.isChecked();
        }

        public String getDayOfMonth() {
            return dayOfMonthTb.getText();
        }

        public void setDayOfMonth(String dayOfMonth) {
            dayOfMonthTb.setText(dayOfMonth);
        }

        public WeekOfMonth getWeekOfMonth() {
            return WeekOfMonth.get(whichWeekLb.getSelectedIndex());
        }

        public void setWeekOfMonth(WeekOfMonth week) {
            whichWeekLb.setSelectedIndex(week.value());
        }

        public DayOfWeek getDayOfWeek() {
            return DayOfWeek.get(dayOfWeekLb.getSelectedIndex());
        }

        public void setDayOfWeek(DayOfWeek day) {
            dayOfWeekLb.setSelectedIndex(day.value());
        }

        public void setDayNOfMonthError(String errorMsg) {
            dayNOfMonthLabel.setErrorMsg(errorMsg);
        }

        public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
            this.onChangeHandler = handler;
        }

        private void changeHandler() {
            if (null != onChangeHandler) {
                onChangeHandler.onHandle(this);
            }
        }

        private void configureOnChangeHandler() {
            final MonthlyRecurrenceEditor localThis = this;

            KeyboardListener keyboardListener = new KeyboardListener() {
                public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyPress(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyUp(Widget sender, char keyCode, int modifiers) {
                    localThis.changeHandler();
                }
            };

            ClickListener clickListener = new ClickListener() {
                public void onClick(Widget sender) {
                    localThis.changeHandler();
                }
            };

            ChangeListener changeListener = new ChangeListener() {
                public void onChange(Widget sender) {
                    localThis.changeHandler();
                }
            };
            dayNOfMonthRb.addClickListener(clickListener);
            dayNOfMonthRb.addKeyboardListener(keyboardListener);
            nthDayNameOfMonthRb.addClickListener(clickListener);
            nthDayNameOfMonthRb.addKeyboardListener(keyboardListener);
            dayOfMonthTb.addKeyboardListener(keyboardListener);
            whichWeekLb.addChangeListener(changeListener);
            dayOfWeekLb.addChangeListener(changeListener);
        }
    }

    public class YearlyRecurrenceEditor extends VerticalPanel implements IChangeHandler {

        protected RadioButton everyMonthOnNthDayRb = new RadioButton(YEARLY_RB_GROUP,
                Messages.getString("schedule.every"));
        protected RadioButton nthDayNameOfMonthNameRb = new RadioButton(YEARLY_RB_GROUP,
                Messages.getString("schedule.the"));
        private TextBox dayOfMonthTb = new TextBox();
        private ListBox monthOfYearLb0 = createMonthOfYearListBox();
        private ListBox monthOfYearLb1 = createMonthOfYearListBox();
        private ListBox whichWeekLb = createWhichWeekListBox();
        private ListBox dayOfWeekLb = createDayOfWeekListBox();
        private ErrorLabel dayOfMonthLabel = null;
        private ICallback<IChangeHandler> onChangeHandler;

        private static final String YEARLY_RB_GROUP = "yearly-group"; //$NON-NLS-1$

        public YearlyRecurrenceEditor() {
            setSpacing(6);
            this.setStyleName(RECUR_PATTERN_HP);
            getElement().removeAttribute("cellpadding");

            HorizontalPanel p = new HorizontalPanel();
            p.getElement().setId("every-month-on-nth-day-radio");
            everyMonthOnNthDayRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            everyMonthOnNthDayRb.setChecked(true);
            p.add(everyMonthOnNthDayRb);
            p.add(monthOfYearLb0);
            dayOfMonthTb.addStyleName("DAY_OF_MONTH_TB"); //$NON-NLS-1$
            dayOfMonthTb.addStyleName(EVERY_TXTBOX);
            dayOfMonthTb.getElement().setId("day-of-month-tb");
            p.add(dayOfMonthTb);
            dayOfMonthLabel = new ErrorLabel(p);
            add(dayOfMonthLabel);

            p = new HorizontalPanel();
            nthDayNameOfMonthNameRb.setStyleName("recurrenceRadioButton"); //$NON-NLS-1$
            p.add(nthDayNameOfMonthNameRb);
            p.add(whichWeekLb);
            dayOfWeekLb.getElement().setId("day-of-week-lb");
            p.add(dayOfWeekLb);
            Label l = new Label(Messages.getString("schedule.of"));
            l.setStyleName("middleLabel"); //$NON-NLS-1$
            p.add(l);
            p.add(monthOfYearLb1);
            add(p);
            configureOnChangeHandler();
        }

        public void reset() {
            setEveryMonthOnNthDay();
            setMonthOfYear0(MonthOfYear.JAN);
            setDayOfMonth(""); //$NON-NLS-1$
            setWeekOfMonth(WeekOfMonth.FIRST);
            setDayOfWeek(DayOfWeek.SUN);
            setMonthOfYear1(MonthOfYear.JAN);
        }

        public boolean isEveryMonthOnNthDay() {
            return everyMonthOnNthDayRb.isChecked();
        }

        public void setEveryMonthOnNthDay() {
            everyMonthOnNthDayRb.setChecked(true);
            nthDayNameOfMonthNameRb.setChecked(false);
        }

        public boolean isNthDayNameOfMonthName() {
            return nthDayNameOfMonthNameRb.isChecked();
        }

        public void setNthDayNameOfMonthName() {
            nthDayNameOfMonthNameRb.setChecked(true);
            everyMonthOnNthDayRb.setChecked(false);
        }

        public String getDayOfMonth() {
            return dayOfMonthTb.getText();
        }

        public void setDayOfMonth(String dayOfMonth) {
            dayOfMonthTb.setText(dayOfMonth);
        }

        public WeekOfMonth getWeekOfMonth() {
            return WeekOfMonth.get(whichWeekLb.getSelectedIndex());
        }

        public void setWeekOfMonth(WeekOfMonth week) {
            whichWeekLb.setSelectedIndex(week.value());
        }

        public DayOfWeek getDayOfWeek() {
            return DayOfWeek.get(dayOfWeekLb.getSelectedIndex());
        }

        public void setDayOfWeek(DayOfWeek day) {
            dayOfWeekLb.setSelectedIndex(day.value());
        }

        public MonthOfYear getMonthOfYear0() {
            return MonthOfYear.get(monthOfYearLb0.getSelectedIndex());
        }

        public void setMonthOfYear0(MonthOfYear month) {
            monthOfYearLb0.setSelectedIndex(month.value());
        }

        public MonthOfYear getMonthOfYear1() {
            return MonthOfYear.get(monthOfYearLb1.getSelectedIndex());
        }

        public void setMonthOfYear1(MonthOfYear month) {
            monthOfYearLb1.setSelectedIndex(month.value());
        }

        public void setDayOfMonthError(String errorMsg) {
            dayOfMonthLabel.setErrorMsg(errorMsg);
        }

        public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
            this.onChangeHandler = handler;
        }

        private void changeHandler() {
            if (null != onChangeHandler) {
                onChangeHandler.onHandle(this);
            }
        }

        private void configureOnChangeHandler() {

            final YearlyRecurrenceEditor localThis = this;

            KeyboardListener keyboardListener = new KeyboardListener() {
                public void onKeyDown(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyPress(Widget sender, char keyCode, int modifiers) {
                }

                public void onKeyUp(Widget sender, char keyCode, int modifiers) {
                    localThis.changeHandler();
                }
            };

            ClickListener clickListener = new ClickListener() {
                public void onClick(Widget sender) {
                    localThis.changeHandler();
                }
            };

            ChangeListener changeListener = new ChangeListener() {
                public void onChange(Widget sender) {
                    localThis.changeHandler();
                }
            };

            everyMonthOnNthDayRb.addClickListener(clickListener);
            everyMonthOnNthDayRb.addKeyboardListener(keyboardListener);

            nthDayNameOfMonthNameRb.addClickListener(clickListener);
            nthDayNameOfMonthNameRb.addKeyboardListener(keyboardListener);

            dayOfMonthTb.addKeyboardListener(keyboardListener);

            monthOfYearLb0.addChangeListener(changeListener);
            monthOfYearLb1.addChangeListener(changeListener);
            whichWeekLb.addChangeListener(changeListener);
            dayOfWeekLb.addChangeListener(changeListener);
        }
    }

    private ListBox createDayOfWeekListBox() {
        ListBox l = new ListBox();
        for (int ii = 0; ii < DayOfWeek.length(); ++ii) {
            DayOfWeek day = DayOfWeek.get(ii);
            l.addItem(Messages.getString(day.toString()));
        }
        return l;
    }

    private ListBox createMonthOfYearListBox() {

        ListBox l = new ListBox();
        for (int ii = 0; ii < MonthOfYear.length(); ++ii) {
            MonthOfYear month = MonthOfYear.get(ii);
            l.addItem(Messages.getString(month.toString()));
        }

        return l;
    }

    private ListBox createWhichWeekListBox() {

        ListBox l = new ListBox();
        for (WeekOfMonth week : EnumSet.range(WeekOfMonth.FIRST, WeekOfMonth.LAST)) {
            l.addItem(Messages.getString(week.toString()));
        }

        return l;
    }

    private void selectTemporalPanel(TemporalValue selectedTemporalValue) {
        int i = 0;
        for (Map.Entry<TemporalValue, Panel> me : temporalPanelMap.entrySet()) {
            if (me.getKey().equals(selectedTemporalValue)) {
                deckPanel.showWidget(i);
                break;
            }
            i++;
        }
    }

    /**
     * 
     * @return null if the selected schedule does not support repeat-in-seconds, otherwise return the number of
     *         seconds between schedule execution.
     * @throws RuntimeException
     *           if the temporal value (tv) is invalid. This condition occurs as a result of programmer error.
     */
    public Long getRepeatInSecs() throws RuntimeException {
        switch (temporalState) {
        case WEEKLY:
            // fall through
        case MONTHLY:
            // fall through
        case YEARLY:
            return null;
        case SECONDS:
            return Long.parseLong(secondlyEditor.getValue());
        case MINUTES:
            return TimeUtil.minutesToSecs(Long.parseLong(minutelyEditor.getValue()));
        case HOURS:
            return TimeUtil.hoursToSecs(Long.parseLong(hourlyEditor.getValue()));
        case DAILY:
            return TimeUtil.daysToSecs(Long.parseLong(dailyEditor.getRepeatValue()));
        default:
            throw new RuntimeException(
                    Messages.getString("schedule.invalidTemporalValueInGetRepeatInSecs", temporalState.toString()));
        }
    }

    /**
     * 
     * @return null if the selected schedule does not support CRON, otherwise return the CRON string.
     * @throws RuntimeException
     *           if the temporal value (tv) is invalid. This condition occurs as a result of programmer error.
     */
    public String getCronString() throws RuntimeException {
        switch (temporalState) {
        case SECONDS:
            // fall through
        case MINUTES:
            // fall through
        case HOURS:
            return null;
        case DAILY:
            return getDailyCronString();
        case WEEKLY:
            return getWeeklyCronString();
        case MONTHLY:
            return getMonthlyCronString();
        case YEARLY:
            return getYearlyCronString();
        default:
            throw new RuntimeException(
                    Messages.getString("schedule.invalidTemporalValueInGetCronString", temporalState.toString()));
        }
    }

    public boolean isEveryNDays() {
        return (temporalState == TemporalValue.DAILY) && dailyEditor.isEveryNDays();
    }

    public MonthOfYear getSelectedMonth() {
        MonthOfYear selectedMonth = null;
        if ((temporalState == TemporalValue.YEARLY) && yearlyEditor.isNthDayNameOfMonthName()) {
            selectedMonth = yearlyEditor.getMonthOfYear1();
        } else if ((temporalState == TemporalValue.YEARLY) && yearlyEditor.isEveryMonthOnNthDay()) {
            selectedMonth = yearlyEditor.getMonthOfYear0();
        }
        return selectedMonth;
    }

    public List<DayOfWeek> getSelectedDaysOfWeek() {
        ArrayList<DayOfWeek> selectedDaysOfWeek = new ArrayList<DayOfWeek>();
        if ((temporalState == TemporalValue.DAILY) && !dailyEditor.isEveryNDays()) {
            selectedDaysOfWeek.add(DayOfWeek.MON);
            selectedDaysOfWeek.add(DayOfWeek.TUE);
            selectedDaysOfWeek.add(DayOfWeek.WED);
            selectedDaysOfWeek.add(DayOfWeek.THU);
            selectedDaysOfWeek.add(DayOfWeek.FRI);
        } else if (temporalState == TemporalValue.WEEKLY) {
            selectedDaysOfWeek.addAll(weeklyEditor.getCheckedDays());
        } else if ((temporalState == TemporalValue.MONTHLY) && monthlyEditor.isNthDayNameOfMonth()) {
            selectedDaysOfWeek.add(monthlyEditor.getDayOfWeek());
        } else if ((temporalState == TemporalValue.YEARLY) && yearlyEditor.isNthDayNameOfMonthName()) {
            selectedDaysOfWeek.add(yearlyEditor.getDayOfWeek());
        }
        return selectedDaysOfWeek;
    }

    public WeekOfMonth getSelectedWeekOfMonth() {
        WeekOfMonth selectedWeekOfMonth = null;
        if ((temporalState == TemporalValue.MONTHLY) && monthlyEditor.isNthDayNameOfMonth()) {
            selectedWeekOfMonth = monthlyEditor.getWeekOfMonth();
        } else if ((temporalState == TemporalValue.YEARLY) && yearlyEditor.isNthDayNameOfMonthName()) {
            selectedWeekOfMonth = yearlyEditor.getWeekOfMonth();
        }
        return selectedWeekOfMonth;
    }

    public Integer getSelectedDayOfMonth() {
        Integer selectedDayOfMonth = null;
        if ((temporalState == TemporalValue.MONTHLY) && monthlyEditor.isDayNOfMonth()) {
            try {
                selectedDayOfMonth = Integer.parseInt(monthlyEditor.getDayOfMonth());
            } catch (Exception ex) {
                //ignored
            }
        } else if ((temporalState == TemporalValue.YEARLY) && yearlyEditor.isEveryMonthOnNthDay()) {
            try {
                selectedDayOfMonth = Integer.parseInt(yearlyEditor.getDayOfMonth());
            } catch (Exception ex) {
                //ignored
            }
        }
        return selectedDayOfMonth;
    }

    /**
     * 
     * @return
     * @throws RuntimeException
     */
    protected String getDailyCronString() throws RuntimeException {
        String cronStr;
        StringBuilder recurrenceSb = new StringBuilder();
        if (dailyEditor.isEveryNDays()) {
            return null;
        } else {
            // must be every weekday
            recurrenceSb.append(RecurrenceType.EveryWeekday).append(SPACE).append(getTimeOfRecurrence());
            try {
                cronStr = CronParser.recurrenceStringToCronString(recurrenceSb.toString());
            } catch (CronParseException e) {
                throw new RuntimeException(
                        Messages.getString("schedule.invalidRecurrenceString", recurrenceSb.toString()));
            }
            return cronStr;
        }
    }

    protected String getWeeklyCronString() throws RuntimeException {
        String cronStr;
        StringBuilder recurrenceSb = new StringBuilder();
        // WeeklyOn 0 33 6 1,3,5
        recurrenceSb.append(RecurrenceType.WeeklyOn).append(SPACE).append(getTimeOfRecurrence()).append(SPACE)
                .append(weeklyEditor.getCheckedDaysAsString(VALUE_OF_SUNDAY));
        try {
            cronStr = CronParser.recurrenceStringToCronString(recurrenceSb.toString());
        } catch (CronParseException e) {
            throw new RuntimeException(
                    Messages.getString("schedule.invalidRecurrenceString", recurrenceSb.toString()));
        }
        return cronStr;

    }

    protected String getMonthlyCronString() throws RuntimeException {
        String cronStr;
        StringBuilder recurrenceSb = new StringBuilder();
        if (monthlyEditor.isDayNOfMonth()) {
            recurrenceSb.append(RecurrenceType.DayNOfMonth).append(SPACE).append(getTimeOfRecurrence())
                    .append(SPACE).append(monthlyEditor.getDayOfMonth());
        } else if (monthlyEditor.isNthDayNameOfMonth()) {
            if (monthlyEditor.getWeekOfMonth() != WeekOfMonth.LAST) {
                String weekOfMonth = Integer.toString(monthlyEditor.getWeekOfMonth().value() + 1);
                String dayOfWeek = Integer.toString(monthlyEditor.getDayOfWeek().value() + 1);
                recurrenceSb.append(RecurrenceType.NthDayNameOfMonth).append(SPACE).append(getTimeOfRecurrence())
                        .append(SPACE).append(dayOfWeek).append(SPACE).append(weekOfMonth);
            } else {
                String dayOfWeek = Integer.toString(monthlyEditor.getDayOfWeek().value() + 1);
                recurrenceSb.append(RecurrenceType.LastDayNameOfMonth).append(SPACE).append(getTimeOfRecurrence())
                        .append(SPACE).append(dayOfWeek);
            }
        } else {
            throw new RuntimeException(Messages.getString("schedule.noRadioBtnsSelected"));
        }
        try {
            cronStr = CronParser.recurrenceStringToCronString(recurrenceSb.toString());
        } catch (CronParseException e) {
            throw new RuntimeException(
                    Messages.getString("schedule.invalidRecurrenceString", recurrenceSb.toString()));
        }
        return cronStr;
    }

    protected String getYearlyCronString() throws RuntimeException {
        String cronStr;
        StringBuilder recurrenceSb = new StringBuilder();
        if (yearlyEditor.isEveryMonthOnNthDay()) {
            String monthOfYear = Integer.toString(yearlyEditor.getMonthOfYear0().value() + 1);
            recurrenceSb.append(RecurrenceType.EveryMonthNameN).append(SPACE).append(getTimeOfRecurrence())
                    .append(SPACE).append(yearlyEditor.getDayOfMonth()).append(SPACE).append(monthOfYear);
        } else if (yearlyEditor.isNthDayNameOfMonthName()) {
            if (yearlyEditor.getWeekOfMonth() != WeekOfMonth.LAST) {
                String monthOfYear = Integer.toString(yearlyEditor.getMonthOfYear1().value() + 1);
                String dayOfWeek = Integer.toString(yearlyEditor.getDayOfWeek().value() + 1);
                String weekOfMonth = Integer.toString(yearlyEditor.getWeekOfMonth().value() + 1);
                recurrenceSb.append(RecurrenceType.NthDayNameOfMonthName).append(SPACE)
                        .append(getTimeOfRecurrence()).append(SPACE).append(dayOfWeek).append(SPACE)
                        .append(weekOfMonth).append(SPACE).append(monthOfYear);
            } else {
                String monthOfYear = Integer.toString(yearlyEditor.getMonthOfYear1().value() + 1);
                String dayOfWeek = Integer.toString(yearlyEditor.getDayOfWeek().value() + 1);
                recurrenceSb.append(RecurrenceType.LastDayNameOfMonthName).append(SPACE)
                        .append(getTimeOfRecurrence()).append(SPACE).append(dayOfWeek).append(SPACE)
                        .append(monthOfYear);
            }
        } else {
            throw new RuntimeException(Messages.getString("schedule.noRadioBtnsSelected"));
        }
        try {
            cronStr = CronParser.recurrenceStringToCronString(recurrenceSb.toString());
        } catch (CronParseException e) {
            throw new RuntimeException(
                    Messages.getString("schedule.invalidRecurrenceString", recurrenceSb.toString()));
        }
        return cronStr;
    }

    private StringBuilder getTimeOfRecurrence() {
        int timeOfDayAdjust = (startTimePicker.getTimeOfDay().equals(TimeUtil.TimeOfDay.AM)) ? TimeUtil.MIN_HOUR // 0
                : TimeUtil.MAX_HOUR; // 12
        String strHour = StringUtils.addStringToInt(startTimePicker.getHour(), timeOfDayAdjust);
        return new StringBuilder().append("00").append(SPACE) //$NON-NLS-1$
                .append(startTimePicker.getMinute()).append(SPACE).append(strHour);
    }

    // TODO sbarkdull
    // private static DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());

    public void setStartTime(String startTime) {
        startTimePicker.setTime(startTime);
    }

    public String getStartTime() {
        return startTimePicker.getTime();
    }

    public void setStartDate(Date startDate) {
        dateRangeEditor.setStartDate(startDate);
    }

    public Date getStartDate() {
        return dateRangeEditor.getStartDate();
    }

    public void setEndDate(Date endDate) {
        dateRangeEditor.setEndDate(endDate);
    }

    public Date getEndDate() {
        return dateRangeEditor.getEndDate();
    }

    public void setNoEndDate() {
        dateRangeEditor.setNoEndDate();
    }

    public void setEndBy() {
        dateRangeEditor.setEndBy();
    }

    public TemporalValue getTemporalState() {
        return temporalState;
    }

    public void setTemporalState(TemporalValue temporalState) {
        this.temporalState = temporalState;
        selectTemporalPanel(temporalState);
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return DateRangeEditor
     */
    public DateRangeEditor getDateRangeEditor() {
        return dateRangeEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return SecondlyRecurrencePanel
     */
    public SecondlyRecurrenceEditor getSecondlyEditor() {
        return secondlyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return MinutelyRecurrencePanel
     */
    public MinutelyRecurrenceEditor getMinutelyEditor() {
        return minutelyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return HourlyRecurrencePanel
     */
    public HourlyRecurrenceEditor getHourlyEditor() {
        return hourlyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return DailyRecurrencePanel
     */
    public DailyRecurrenceEditor getDailyEditor() {
        return dailyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return WeeklyRecurrencePanel
     */
    public WeeklyRecurrenceEditor getWeeklyEditor() {
        return weeklyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return MonthlyRecurrencePanel
     */
    public MonthlyRecurrenceEditor getMonthlyEditor() {
        return monthlyEditor;
    }

    /**
     * NOTE: should only ever be used by validators. This is a backdoor into this class that shouldn't be here, do
     * not use this method unless you are validating.
     * 
     * @return YearlyRecurrencePanel
     */
    public YearlyRecurrenceEditor getYearlyEditor() {
        return yearlyEditor;
    }

    public void setOnChangeHandler(ICallback<IChangeHandler> handler) {
        this.onChangeHandler = handler;
    }

    private void changeHandler() {
        if (null != onChangeHandler) {
            onChangeHandler.onHandle(this);
        }
    }

    private void configureOnChangeHandler() {
        final RecurrenceEditor localThis = this;

        ICallback<IChangeHandler> handler = new ICallback<IChangeHandler>() {
            public void onHandle(IChangeHandler o) {
                localThis.changeHandler();
            }
        };

        startTimePicker.setOnChangeHandler(handler);
        dateRangeEditor.setOnChangeHandler(handler);

        secondlyEditor.setOnChangeHandler(handler);
        minutelyEditor.setOnChangeHandler(handler);
        hourlyEditor.setOnChangeHandler(handler);
        dailyEditor.setOnChangeHandler(handler);
        weeklyEditor.setOnChangeHandler(handler);
        monthlyEditor.setOnChangeHandler(handler);
        yearlyEditor.setOnChangeHandler(handler);
    }
}