/*! * 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 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.CronExpression; import org.pentaho.gwt.widgets.client.utils.CronParseException; import org.pentaho.gwt.widgets.client.utils.CronParser; import org.pentaho.gwt.widgets.client.utils.EnumException; import org.pentaho.gwt.widgets.client.utils.TimeUtil.TimeOfDay; import org.pentaho.gwt.widgets.client.wizards.AbstractWizardDialog.ScheduleDialogType; import org.pentaho.mantle.client.dialogs.scheduling.RecurrenceEditor.TemporalValue; import org.pentaho.mantle.client.messages.Messages; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CaptionPanel; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; 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.SimplePanel; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.datepicker.client.CalendarUtil; /** * @author Steven Barkdull */ public class ScheduleEditor extends VerticalPanel implements IChangeHandler { private static final int DEFAULT_START_HOUR = 12; //$NON-NLS-1$ private static final int DEFAULT_START_MINUTE = 0; //$NON-NLS-1$ public static enum ENDS_TYPE { TIME, DURATION } public static class DurationValues { public int days = 0; public int hours = 0; public int minutes = 0; } public static enum TIME { MILLISECOND( 1 ), SECOND( MILLISECOND.time * 1000 ), MINUTE( SECOND.time * 60 ), HOUR( MINUTE.time * 60 ), DAY( HOUR.time * 24 ); private long time; TIME( long time ) { this.time = time; } public long getTime() { return time; } } protected static final String SCHEDULE_DROPDOWN_ARROW = "schedule-dropdown-arrow"; protected static final String RECURRENCE_LABEL = "reccurence-label"; protected static final String SCHEDULE_LABEL = "schedule-label"; //$NON-NLS-1$ protected static final String SCHEDULE_EDITOR_CAPTION_PANEL = "schedule-editor-caption-panel"; //$NON-NLS-1$ protected static final String BLOCKOUT_SELECT = "blockout-select"; protected static final String BLOCKOUT_LABEL = "blockout-label"; public enum ScheduleType { //@formatter:off RUN_ONCE( 0, Messages.getString( "schedule.runOnce" ) ), SECONDS( 1, Messages.getString( "schedule.seconds" ) ), MINUTES( 2, Messages.getString( "schedule.minutes" ) ), HOURS( 3, Messages.getString( "schedule.hours" ) ), DAILY( 4, Messages.getString( "schedule.daily" ) ), WEEKLY( 5, Messages.getString( "schedule.weekly" ) ), MONTHLY( 6, Messages.getString( "schedule.monthly" ) ), YEARLY( 7, Messages.getString( "schedule.yearly" ) ), CRON( 8, Messages.getString( "schedule.cron" ) ); //@formatter:on private ScheduleType( int value, String name ) { this.value = value; this.name = name; } private final int value; private final String name; private static ScheduleType[] scheduleValue = { RUN_ONCE, SECONDS, MINUTES, HOURS, DAILY, WEEKLY, MONTHLY, YEARLY, CRON }; public int value() { return value; } @Override public String toString() { return name; } public static ScheduleType get( int idx ) { return scheduleValue[idx]; } public static int length() { return scheduleValue.length; } public static ScheduleType stringToScheduleType( String strSchedule ) throws EnumException { for ( ScheduleType v : EnumSet.range( ScheduleType.RUN_ONCE, ScheduleType.CRON ) ) { if ( v.toString().equals( strSchedule ) ) { return v; } } throw new EnumException( Messages.getString( "schedule.invalidTemporalValue", scheduleValue.toString() ) ); } } /* end enum */ protected RunOnceEditor runOnceEditor = null; protected RecurrenceEditor recurrenceEditor = null; protected CronEditor cronEditor = null; // TODO sbarkdull, can this be static? private final Map<ScheduleType, Panel> scheduleTypeMap = new HashMap<ScheduleType, Panel>(); private final Map<TemporalValue, ScheduleType> temporalValueToScheduleTypeMap = createTemporalValueToScheduleTypeMap(); private final Map<ScheduleType, TemporalValue> scheduleTypeToTemporalValueMap = createScheduleTypeMapToTemporalValue(); protected ListBox scheduleCombo = null; private ICallback<IChangeHandler> onChangeHandler = null; private boolean isBlockoutDialog = false; private TimePicker startTimePicker = null; protected TimePicker blockoutEndTimePicker = null; private Widget startTimePanel = null; private RadioButton endTimeRadioButton = null; private RadioButton durationRadioButton = null; protected ListBox daysListBox = null; protected ListBox hoursListBox = null; protected ListBox minutesListBox = null; protected Button blockoutCheckButton = new Button( Messages.getString( "schedule.viewBlockoutTimes" ) ); protected ListBox timeZonePicker = null; private final Date defaultDate = initDefaultDate(); @SuppressWarnings( "deprecation" ) private Date initDefaultDate() { Date date = new Date(); date.setHours( DEFAULT_START_HOUR ); date.setMinutes( DEFAULT_START_MINUTE ); CalendarUtil.addDaysToDate( date, 1 ); return date; } public ScheduleEditor( ScheduleDialogType type ) { super(); isBlockoutDialog = ( type == ScheduleDialogType.BLOCKOUT ); startTimePicker = new TimePicker(); setStylePrimaryName( "scheduleEditor" ); //$NON-NLS-1$ scheduleCombo = createScheduleCombo(); Label l = new Label( Messages.getString( "schedule.recurrenceColon" ) ); l.getElement().setId( RECURRENCE_LABEL ); l.setStyleName( SCHEDULE_LABEL ); add( l ); add( scheduleCombo ); SimplePanel hspacer = new SimplePanel(); hspacer.setWidth( "100px" ); //$NON-NLS-1$ if ( !isBlockoutDialog ) { startTimePanel = createStartTimePanel(); add( startTimePanel ); } else { // Blockout End TimePicker Date blockoutEndDate = new Date( defaultDate.getTime() ); addMinutes( defaultDate, 1 ); blockoutEndTimePicker = new TimePicker(); blockoutEndTimePicker = new TimePicker(); blockoutEndTimePicker.setTime( blockoutEndDate ); // Blockout End Caption Panel blockoutEndTimePicker.getElement().getStyle().setDisplay( Display.NONE ); final String[] daysList = new String[365]; final String[] hoursList = new String[24]; final String[] minutesList = new String[60]; // Populate list for ( Integer i = 0; i < 365; i++ ) { String iStr = i.toString(); daysList[i] = iStr; if ( i < 60 ) { minutesList[i] = iStr; if ( i < 24 ) { hoursList[i] = iStr; } } } // Units of time Drop Down daysListBox = new ListBox(); daysListBox.getElement().setId( "daysListBox" ); //$NON-NLS-1$ daysListBox.addStyleName( BLOCKOUT_SELECT ); populateListItems( daysListBox, daysList, 0, 365 ); final Label daysLabel = new Label( Messages.getString( "schedule.dayOrDays" ) ); daysLabel.addStyleName( BLOCKOUT_LABEL ); daysLabel.getElement().setAttribute( "for", daysListBox.getElement().getId() ); //$NON-NLS-1$ hoursListBox = new ListBox(); hoursListBox.getElement().setId( "hoursListBox" ); //$NON-NLS-1$ hoursListBox.addStyleName( BLOCKOUT_SELECT ); populateListItems( hoursListBox, hoursList, 0, 24 ); final Label hoursLabel = new Label( Messages.getString( "schedule.hourOrHours" ) ); hoursLabel.addStyleName( BLOCKOUT_LABEL ); hoursLabel.getElement().setAttribute( "for", hoursListBox.getElement().getId() ); //$NON-NLS-1$ minutesListBox = new ListBox(); minutesListBox.getElement().setId( "minutesListBox" ); //$NON-NLS-1$ minutesListBox.addStyleName( BLOCKOUT_SELECT ); populateListItems( minutesListBox, minutesList, 0, 60 ); minutesListBox.setSelectedIndex( 1 ); // default value for Validator final Label minutesLabel = new Label( Messages.getString( "schedule.minuteOrMinutes" ) ); minutesLabel.addStyleName( BLOCKOUT_LABEL ); minutesLabel.getElement().setAttribute( "for", minutesListBox.getElement().getId() ); //$NON-NLS-1$ final HorizontalPanel durationPanel = new HorizontalPanel(); durationPanel.setVerticalAlignment( HasVerticalAlignment.ALIGN_MIDDLE ); durationPanel.setSpacing( blockoutEndTimePicker.getSpacing() ); durationPanel.add( daysListBox ); durationPanel.add( daysLabel ); durationPanel.add( hoursListBox ); durationPanel.add( hoursLabel ); durationPanel.add( minutesListBox ); durationPanel.add( minutesLabel ); // Bind change handler scheduleCombo.addChangeHandler( new ChangeHandler() { @Override public void onChange( ChangeEvent event ) { String scheduleType = scheduleCombo.getItemText( scheduleCombo.getSelectedIndex() ); if ( ScheduleType.RUN_ONCE.toString().equals( scheduleType ) ) { show( true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel ); populateListItems( daysListBox, daysList, 0, 365 ); populateListItems( hoursListBox, hoursList, 0, 24 ); populateListItems( minutesListBox, minutesList, 0, 60 ); } else if ( ScheduleType.HOURS.toString().equals( scheduleType ) ) { hide( true, daysListBox, daysLabel, hoursListBox, hoursLabel ); show( true, minutesListBox, minutesLabel ); populateListItems( minutesListBox, minutesList, 0, 60 ); } else if ( ScheduleType.DAILY.toString().equals( scheduleType ) ) { hide( true, daysListBox, daysLabel ); show( true, hoursListBox, hoursLabel, minutesListBox, minutesLabel ); populateListItems( hoursListBox, hoursList, 0, 24 ); populateListItems( minutesListBox, minutesList, 0, 60 ); } else if ( ScheduleType.WEEKLY.toString().equals( scheduleType ) ) { show( true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel ); populateListItems( daysListBox, daysList, 0, 7 ); populateListItems( hoursListBox, hoursList, 0, 24 ); populateListItems( minutesListBox, minutesList, 0, 60 ); } else if ( ScheduleType.MONTHLY.toString().equals( scheduleType ) ) { show( true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel ); populateListItems( daysListBox, daysList, 0, 28 ); populateListItems( hoursListBox, hoursList, 0, 24 ); populateListItems( minutesListBox, minutesList, 0, 60 ); } else if ( ScheduleType.YEARLY.toString().equals( scheduleType ) ) { show( true, daysListBox, daysLabel, hoursListBox, hoursLabel, minutesListBox, minutesLabel ); populateListItems( daysListBox, daysList, 0, 365 ); populateListItems( hoursListBox, hoursList, 0, 24 ); populateListItems( minutesListBox, minutesList, 0, 60 ); } } } ); /* * Radio Buttons for duration */ durationRadioButton = new RadioButton( "durationRadioGroup", "durationRadioButton" ); //$NON-NLS-1$ //$NON-NLS-2$ durationRadioButton.setText( Messages.getString( "schedule.duration" ) ); durationRadioButton.setValue( Boolean.TRUE ); durationRadioButton.addClickHandler( new ClickHandler() { @Override public void onClick( ClickEvent event ) { blockoutEndTimePicker.getElement().getStyle().setDisplay( Display.NONE ); durationPanel.getElement().getStyle().clearDisplay(); } } ); endTimeRadioButton = new RadioButton( "durationRadioGroup", "endTimeRadioButton" ); //$NON-NLS-1$ //$NON-NLS-2$ endTimeRadioButton.setText( Messages.getString( "schedule.endTime" ) ); endTimeRadioButton.addClickHandler( new ClickHandler() { @Override public void onClick( ClickEvent event ) { blockoutEndTimePicker.getElement().getStyle().clearDisplay(); durationPanel.getElement().getStyle().setDisplay( Display.NONE ); } } ); // Radio Buttons Panel HorizontalPanel radioButtonsPanel = new HorizontalPanel(); radioButtonsPanel.setVerticalAlignment( HasVerticalAlignment.ALIGN_MIDDLE ); radioButtonsPanel.getElement().setId( "radio-buttons-panel" ); radioButtonsPanel.add( durationRadioButton ); radioButtonsPanel.add( endTimeRadioButton ); // Ends Panel VerticalPanel endsPanel = new VerticalPanel(); endsPanel.add( radioButtonsPanel ); endsPanel.add( blockoutEndTimePicker ); endsPanel.add( durationPanel ); // Blockout period CaptionPanel blockoutStartCaptionPanel = new CaptionPanel( Messages.getString( "schedule.startTime" ) ); blockoutStartCaptionPanel.setStyleName( SCHEDULE_EDITOR_CAPTION_PANEL ); HorizontalPanel blockoutStartPanel = new HorizontalPanel(); blockoutStartPanel.getElement().setId( "blockout-start-panel" ); blockoutStartPanel.add( getStartTimePicker() ); timeZonePicker = new ListBox(); timeZonePicker.setStyleName( "timeZonePicker" ); timeZonePicker.setVisibleItemCount( 1 ); blockoutStartPanel.add( timeZonePicker ); timeZonePicker.getElement().getParentElement().getStyle().setPaddingTop( 5, Unit.PX ); blockoutStartCaptionPanel.add( blockoutStartPanel ); populateTimeZonePicker(); // Ends Caption Panel CaptionPanel endCaptionPanel = new CaptionPanel( Messages.getString( "schedule.endsCaptionTitle" ) ); endCaptionPanel.setStyleName( SCHEDULE_EDITOR_CAPTION_PANEL ); endCaptionPanel.add( endsPanel ); VerticalPanel blockoutPanel = new VerticalPanel(); blockoutPanel.setWidth( "100%" ); //$NON-NLS-1$ blockoutPanel.add( blockoutStartCaptionPanel ); blockoutPanel.add( endCaptionPanel ); add( blockoutPanel ); } VerticalPanel vp = new VerticalPanel(); vp.setWidth( "100%" ); //$NON-NLS-1$ add( vp ); setCellHeight( vp, "100%" ); //$NON-NLS-1$ runOnceEditor = new RunOnceEditor( startTimePicker ); vp.add( runOnceEditor ); scheduleTypeMap.put( ScheduleType.RUN_ONCE, runOnceEditor ); runOnceEditor.setVisible( true ); recurrenceEditor = new RecurrenceEditor( startTimePicker ); vp.add( recurrenceEditor ); scheduleTypeMap.put( ScheduleType.SECONDS, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.MINUTES, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.HOURS, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.DAILY, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.WEEKLY, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.MONTHLY, recurrenceEditor ); scheduleTypeMap.put( ScheduleType.YEARLY, recurrenceEditor ); recurrenceEditor.setVisible( false ); cronEditor = new CronEditor(); scheduleTypeMap.put( ScheduleType.CRON, cronEditor ); cronEditor.setVisible( false ); if ( !isBlockoutDialog ) { vp.add( cronEditor ); VerticalPanel blockoutButtonPanel = new VerticalPanel(); blockoutButtonPanel.setWidth( "100%" ); //$NON-NLS-1$ // blockoutButtonPanel.setHeight("30%"); blockoutButtonPanel.setHorizontalAlignment( HasHorizontalAlignment.ALIGN_CENTER ); blockoutButtonPanel.setVerticalAlignment( HasVerticalAlignment.ALIGN_MIDDLE ); // We want to add a button to check for blockout conflicts blockoutCheckButton.setStyleName( "pentaho-button" ); //$NON-NLS-1$ blockoutCheckButton.getElement().setId( "blockout-check-button" ); //$NON-NLS-1$ blockoutCheckButton.setVisible( false ); hspacer.setHeight( "50px" ); //$NON-NLS-1$ blockoutButtonPanel.add( hspacer ); blockoutButtonPanel.add( blockoutCheckButton ); vp.add( hspacer ); add( blockoutButtonPanel ); } reset( defaultDate ); configureOnChangeHandler(); } @SuppressWarnings( "deprecation" ) private void addMinutes( Date date, int count ) { date.setMinutes( date.getMinutes() + count ); } private void show( boolean applyToParent, UIObject... objs ) { for ( UIObject obj : objs ) { Element ele = obj.getElement(); if ( applyToParent ) { ele = ele.getParentElement(); } ele.getStyle().clearDisplay(); } } private void hide( boolean applyToParent, UIObject... objs ) { for ( UIObject obj : objs ) { Element ele = obj.getElement(); if ( applyToParent ) { ele = ele.getParentElement(); } ele.getStyle().setDisplay( Display.NONE ); } } private void populateListItems( ListBox listBox, String[] arr, int startIndex, int howMany ) { // Clear items listBox.clear(); // Add itesm int endIndex = startIndex + howMany; for ( int i = startIndex; i < endIndex; i++ ) { listBox.addItem( arr[i] ); } } private void populateTimeZonePicker() { String url = ScheduleHelper.getFullyQualifiedURL() + "api/system/timezones"; //$NON-NLS-1$ RequestBuilder timeZonesRequest = new RequestBuilder( RequestBuilder.GET, url ); timeZonesRequest.setHeader( "accept", "application/json" ); //$NON-NLS-1$ //$NON-NLS-2$ timeZonesRequest.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); try { timeZonesRequest.sendRequest( null, new RequestCallback() { @Override public void onResponseReceived( Request request, Response response ) { timeZonePicker.clear(); String responseText = response.getText(); JSONValue value = JSONParser.parseLenient( responseText ); JSONObject object = value.isObject(); value = object.get( "timeZones" ); JSONValue serverTZvalue = object.get( "serverTzId" ); JSONString serverTZIdString = serverTZvalue.isString(); String serverTZId = serverTZIdString.stringValue(); object = value.isObject(); value = object.get( "entry" ); JSONArray timeZonesJSONArray = value.isArray(); for ( int i = 0; i < timeZonesJSONArray.size(); i++ ) { JSONValue entryValue = timeZonesJSONArray.get( i ); JSONObject entryObject = entryValue.isObject(); JSONValue keyValue = entryObject.get( "key" ); JSONValue theValue = entryObject.get( "value" ); String key = keyValue.isString().stringValue(); String valueForKey = theValue.isString().stringValue(); timeZonePicker.addItem( valueForKey, key ); } for ( int i = 0; i < timeZonePicker.getItemCount(); i++ ) { if ( timeZonePicker.getValue( i ).equalsIgnoreCase( serverTZId ) ) { timeZonePicker.setSelectedIndex( i ); break; } } } @Override public void onError( Request request, Throwable exception ) { // TODO Auto-generated method stub } } ); } catch ( RequestException e ) { // TODO Auto-generated catch block e.printStackTrace(); } } public ListBox getTimeZonePicker() { return timeZonePicker; } public void setBlockoutButtonHandler( final ClickHandler handler ) { blockoutCheckButton.addClickHandler( handler ); } public Button getBlockoutCheckButton() { return blockoutCheckButton; } public TimePicker getStartTimePicker() { return startTimePicker; } public TimePicker getBlockoutEndTimePicker() { return blockoutEndTimePicker; } public ENDS_TYPE getBlockoutEndsType() { return durationRadioButton.getValue() ? ENDS_TYPE.DURATION : ENDS_TYPE.TIME; } public DurationValues getDurationValues() { DurationValues vals = new DurationValues(); String displayNone = Display.NONE.getCssName(); // Days if ( !displayNone.equals( daysListBox.getElement().getStyle().getDisplay() ) ) { vals.days = Integer.parseInt( daysListBox.getItemText( daysListBox.getSelectedIndex() ) ); } // Hours if ( !displayNone.equals( hoursListBox.getElement().getStyle().getDisplay() ) ) { vals.hours = Integer.parseInt( hoursListBox.getItemText( hoursListBox.getSelectedIndex() ) ); } // Minutes if ( !displayNone.equals( minutesListBox.getElement().getStyle().getDisplay() ) ) { vals.minutes = Integer.parseInt( minutesListBox.getItemText( minutesListBox.getSelectedIndex() ) ); } return vals; } public void setDurationFields( long duration ) { long remainder = duration; long days = remainder / TIME.DAY.getTime(); remainder -= days * TIME.DAY.getTime(); long hours = remainder / TIME.HOUR.getTime(); remainder -= hours * TIME.HOUR.getTime(); long minutes = remainder / TIME.MINUTE.getTime(); daysListBox.setSelectedIndex( new Long( days ).intValue() ); hoursListBox.setSelectedIndex( new Long( hours ).intValue() ); minutesListBox.setSelectedIndex( new Long( minutes ).intValue() ); // Set valid end time if range is within 24hrs if ( duration < TIME.DAY.getTime() ) { boolean isPM = hours >= 12; blockoutEndTimePicker.setHour( new Long( hours + ( isPM ? -12 : 0 ) ).toString() ); blockoutEndTimePicker.setMinute( new Long( minutes ).toString() ); blockoutEndTimePicker.setTimeOfDay( isPM ? TimeOfDay.PM : TimeOfDay.AM ); } } protected Widget createStartTimePanel() { CaptionPanel startTimeGB = new CaptionPanel( Messages.getString( "schedule.startTime" ) ); startTimeGB.setStyleName( SCHEDULE_EDITOR_CAPTION_PANEL ); startTimeGB.add( getStartTimePicker() ); return startTimeGB; } public void reset( Date now ) { runOnceEditor.reset( now ); recurrenceEditor.reset( now ); cronEditor.reset( now ); setScheduleType( ScheduleType.RUN_ONCE ); } public String getCronString() { switch ( getScheduleType() ) { case RUN_ONCE: return null; case SECONDS: // fall through case MINUTES: // fall through case HOURS: // fall through case DAILY: // fall through case WEEKLY: // fall through case MONTHLY: // fall through case YEARLY: return recurrenceEditor.getCronString(); case CRON: return cronEditor.getCronString(); default: throw new RuntimeException( Messages.getString( "schedule.invalidRunType", getScheduleType().toString() ) ); } } /** * * @param cronStr * @throws CronParseException * if cronStr is not a valid CRON string. */ public void setCronString( String cronStr ) throws CronParseException { // Try original simplistic parser... CronParser cp = new CronParser( cronStr ); String recurrenceStr = null; try { recurrenceStr = cp.parseToRecurrenceString(); // throws CronParseException } catch ( CronParseException e ) { if ( !CronExpression.isValidExpression( cronStr ) ) { // Parse with proper expression parser throw e; } recurrenceStr = null; // valid cronstring, not parse-able to recurrence string } if ( null != recurrenceStr ) { recurrenceEditor.inititalizeWithRecurrenceString( recurrenceStr ); TemporalValue tv = recurrenceEditor.getTemporalState(); ScheduleType rt = temporalValueToScheduleType( tv ); setScheduleType( rt ); } else { // its a cron string that cannot be parsed into a recurrence string, switch to cron string editor. setScheduleType( ScheduleType.CRON ); } cronEditor.setCronString( cronStr ); } /** * * @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 is invalid. This condition occurs as a result of programmer error. */ public Long getRepeatInSecs() throws RuntimeException { return recurrenceEditor.getRepeatInSecs(); } public void setRepeatInSecs( Integer repeatInSecs ) { recurrenceEditor.inititalizeWithRepeatInSecs( repeatInSecs ); TemporalValue tv = recurrenceEditor.getTemporalState(); ScheduleType rt = temporalValueToScheduleType( tv ); setScheduleType( rt ); } private ListBox createScheduleCombo() { final ScheduleEditor localThis = this; ListBox lb = new ListBox(); lb.setVisibleItemCount( 1 ); //lb.setStyleName("scheduleCombo"); //$NON-NLS-1$ lb.addChangeHandler( new ChangeHandler() { @Override public void onChange( ChangeEvent event ) { localThis.handleScheduleChange(); } } ); // add all schedule types to the combobox for ( ScheduleType schedType : EnumSet.range( ScheduleType.RUN_ONCE, ScheduleType.CRON ) ) { if ( !isBlockoutDialog || ( schedType != ScheduleType.CRON && schedType != ScheduleType.SECONDS && schedType != ScheduleType.MINUTES && schedType != ScheduleType.HOURS ) ) { lb.addItem( schedType.toString() ); } } lb.setItemSelected( 0, true ); lb.getElement().setId( "schedule-main-gwt-listbox" ); lb.setStyleName( SCHEDULE_DROPDOWN_ARROW ); return lb; } public ScheduleType getScheduleType() { String selectedValue = scheduleCombo.getValue( scheduleCombo.getSelectedIndex() ); return ScheduleType.stringToScheduleType( selectedValue ); } public void setScheduleType( ScheduleType scheduleType ) { int itemCount = scheduleCombo.getItemCount(); for ( int i = 0; i < itemCount; i++ ) { String itemText = scheduleCombo.getItemText( i ); if ( itemText.equals( scheduleType.toString() ) ) { scheduleCombo.setSelectedIndex( i ); } } selectScheduleTypeEditor( scheduleType ); } /** * 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 RecurrenceEditor getRecurrenceEditor() { return recurrenceEditor; } /** * 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 CronEditor getCronEditor() { return cronEditor; } /** * 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 RunOnceEditor getRunOnceEditor() { return runOnceEditor; } public void setStartTime( String startTime ) { runOnceEditor.setStartTime( startTime ); recurrenceEditor.setStartTime( startTime ); } public void setBlockoutEndTime( String endTime ) { blockoutEndTimePicker.setTime( endTime ); } public String getStartTime() { switch ( getScheduleType() ) { case RUN_ONCE: return runOnceEditor.getStartTime(); case SECONDS: // fall through case MINUTES: // fall through case HOURS: // fall through case DAILY: // fall through case WEEKLY: // fall through case MONTHLY: // fall through case YEARLY: return recurrenceEditor.getStartTime(); case CRON: return cronEditor.getStartTime(); default: throw new RuntimeException( Messages.getString( "schedule.invalidRunType", getScheduleType().toString() ) ); } } public void setStartDate( Date startDate ) { runOnceEditor.setStartDate( startDate ); recurrenceEditor.setStartDate( startDate ); cronEditor.setStartDate( startDate ); } @SuppressWarnings( "deprecation" ) public Date getStartDate() { switch ( getScheduleType() ) { case RUN_ONCE: Date startDate = runOnceEditor.getStartDate(); String startTime = runOnceEditor.getStartTime(); String[] times = startTime.split( ":" ); //$NON-NLS-1$ int hour = Integer.parseInt( times[0] ); int minute = Integer.parseInt( times[1] ); if ( startTime.indexOf( TimeOfDay.PM.toString() ) >= 0 ) { //$NON-NLS-1$ hour += 12; } startDate.setHours( hour ); startDate.setMinutes( minute ); startDate.setSeconds( 0 ); return startDate; case SECONDS: // fall through case MINUTES: // fall through case HOURS: // fall through case DAILY: // fall through case WEEKLY: // fall through case MONTHLY: // fall through case YEARLY: return recurrenceEditor.getStartDate(); case CRON: return cronEditor.getStartDate(); default: throw new RuntimeException( Messages.getString( "schedule.invalidRunType", getScheduleType().toString() ) ); } } public void setEndDate( Date endDate ) { recurrenceEditor.setEndDate( endDate ); cronEditor.setEndDate( endDate ); } public Date getEndDate() { switch ( getScheduleType() ) { case RUN_ONCE: return null; case SECONDS: // fall through case MINUTES: // fall through case HOURS: // fall through case DAILY: // fall through case WEEKLY: // fall through case MONTHLY: // fall through case YEARLY: return recurrenceEditor.getEndDate(); case CRON: return cronEditor.getEndDate(); default: throw new RuntimeException( Messages.getString( "schedule.invalidRunType", getScheduleType().toString() ) ); } } public void setNoEndDate() { recurrenceEditor.setNoEndDate(); cronEditor.setNoEndDate(); } public void setEndBy() { cronEditor.setEndBy(); recurrenceEditor.setEndBy(); } private void handleScheduleChange() throws EnumException { ScheduleType schedType = getScheduleType(); selectScheduleTypeEditor( schedType ); } protected void selectScheduleTypeEditor( ScheduleType scheduleType ) { // if we are switching to cron type, then hide the start time panel if ( ( isBlockoutDialog == false ) && ( startTimePanel != null ) ) { if ( scheduleType == ScheduleType.CRON ) { startTimePanel.setVisible( false ); } else { startTimePanel.setVisible( true ); } } // hide all panels for ( Map.Entry<ScheduleType, Panel> me : scheduleTypeMap.entrySet() ) { me.getValue().setVisible( false ); } // show the selected panel Panel p = scheduleTypeMap.get( scheduleType ); p.setVisible( true ); TemporalValue tv = scheduleTypeToTemporalValue( scheduleType ); if ( null != tv ) { // force the recurrence editor to display the appropriate ui recurrenceEditor.setTemporalState( tv ); } } private static Map<TemporalValue, ScheduleType> createTemporalValueToScheduleTypeMap() { Map<TemporalValue, ScheduleType> m = new HashMap<TemporalValue, ScheduleType>(); m.put( TemporalValue.SECONDS, ScheduleType.SECONDS ); m.put( TemporalValue.MINUTES, ScheduleType.MINUTES ); m.put( TemporalValue.HOURS, ScheduleType.HOURS ); m.put( TemporalValue.DAILY, ScheduleType.DAILY ); m.put( TemporalValue.WEEKLY, ScheduleType.WEEKLY ); m.put( TemporalValue.MONTHLY, ScheduleType.MONTHLY ); m.put( TemporalValue.YEARLY, ScheduleType.YEARLY ); return m; } private static Map<ScheduleType, TemporalValue> createScheduleTypeMapToTemporalValue() { Map<ScheduleType, TemporalValue> m = new HashMap<ScheduleType, TemporalValue>(); m.put( ScheduleType.SECONDS, TemporalValue.SECONDS ); m.put( ScheduleType.MINUTES, TemporalValue.MINUTES ); m.put( ScheduleType.HOURS, TemporalValue.HOURS ); m.put( ScheduleType.DAILY, TemporalValue.DAILY ); m.put( ScheduleType.WEEKLY, TemporalValue.WEEKLY ); m.put( ScheduleType.MONTHLY, TemporalValue.MONTHLY ); m.put( ScheduleType.YEARLY, TemporalValue.YEARLY ); return m; } protected ScheduleType temporalValueToScheduleType( TemporalValue tv ) { return temporalValueToScheduleTypeMap.get( tv ); } private TemporalValue scheduleTypeToTemporalValue( ScheduleType st ) { return scheduleTypeToTemporalValueMap.get( st ); } @Override public void setOnChangeHandler( ICallback<IChangeHandler> handler ) { onChangeHandler = handler; } protected void changeHandler() { if ( null != onChangeHandler ) { onChangeHandler.onHandle( this ); } } private void configureOnChangeHandler() { final ScheduleEditor localThis = this; ICallback<IChangeHandler> handler = new ICallback<IChangeHandler>() { @Override public void onHandle( IChangeHandler o ) { localThis.changeHandler(); } }; ChangeHandler changeHandler = new ChangeHandler() { @Override public void onChange( ChangeEvent event ) { localThis.changeHandler(); } }; ClickHandler clickHandler = new ClickHandler() { @Override public void onClick( ClickEvent event ) { localThis.changeHandler(); } }; scheduleCombo.addChangeHandler( changeHandler ); runOnceEditor.setOnChangeHandler( handler ); recurrenceEditor.setOnChangeHandler( handler ); cronEditor.setOnChangeHandler( handler ); if ( daysListBox != null ) { daysListBox.addChangeHandler( changeHandler ); } if ( hoursListBox != null ) { hoursListBox.addChangeHandler( changeHandler ); } if ( minutesListBox != null ) { minutesListBox.addChangeHandler( changeHandler ); } if ( startTimePicker != null ) { startTimePicker.setOnChangeHandler( handler ); } if ( blockoutEndTimePicker != null ) { blockoutEndTimePicker.setOnChangeHandler( handler ); } if ( durationRadioButton != null ) { durationRadioButton.addClickHandler( clickHandler ); } if ( endTimeRadioButton != null ) { endTimeRadioButton.addClickHandler( clickHandler ); } } public boolean isBlockoutDialog() { return isBlockoutDialog; } }