001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027
028package org.opends.guitools.controlpanel.ui;
029
030import static org.opends.messages.AdminToolMessages.*;
031
032import java.awt.Component;
033import java.awt.Dimension;
034import java.awt.GridBagConstraints;
035import java.awt.GridBagLayout;
036import java.awt.event.ItemEvent;
037import java.awt.event.ItemListener;
038import java.util.ArrayList;
039import java.util.Calendar;
040import java.util.Collection;
041import java.util.Date;
042import java.util.GregorianCalendar;
043
044import javax.swing.Box;
045import javax.swing.DefaultComboBoxModel;
046import javax.swing.JCheckBox;
047import javax.swing.JComboBox;
048import javax.swing.JComponent;
049import javax.swing.JEditorPane;
050import javax.swing.JLabel;
051import javax.swing.JPanel;
052import javax.swing.JTextField;
053import javax.swing.text.PlainDocument;
054
055import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
056import org.opends.guitools.controlpanel.datamodel.ScheduleType;
057import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
058import org.opends.guitools.controlpanel.ui.components.
059 NumericLimitedSizeDocumentFilter;
060import org.opends.guitools.controlpanel.ui.components.TimeDocumentFilter;
061import org.opends.guitools.controlpanel.ui.renderer.
062 NoLeftInsetCategoryComboBoxRenderer;
063import org.opends.guitools.controlpanel.util.Utilities;
064import org.forgerock.i18n.LocalizableMessage;
065import org.opends.server.backends.task.RecurringTask;
066
067/**
068 * The panel that allows the user to specify when a task will be launched.
069 *
070 */
071public class TaskToSchedulePanel extends StatusGenericPanel
072{
073  private static final long serialVersionUID = 6855081932432566784L;
074
075  private String taskName;
076
077  private JComboBox scheduleType;
078
079  private JTextField time;
080  private JTextField day;
081  private JComboBox month;
082  private JComboBox year;
083
084  private JLabel lTime;
085  private JLabel lDay;
086  private JLabel lMonth;
087  private JLabel lYear;
088
089  private JLabel lDailyTime;
090  private JTextField dailyTime;
091
092  private JLabel lWeeklyTime;
093  private JLabel lWeeklyDays;
094  private JTextField weeklyTime;
095  private JCheckBox sunday, monday, tuesday, wednesday, thursday, friday,
096  saturday;
097  {
098    sunday =
099      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUNDAY.get());
100    monday =
101      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONDAY.get());
102    tuesday =
103      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TUESDAY.get());
104    wednesday =
105      Utilities.createCheckBox(
106          INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEDNESDAY.get());
107    thursday =
108      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_THURSDAY.get());
109    friday =
110      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_FRIDAY.get());
111    saturday =
112      Utilities.createCheckBox(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SATURDAY.get());
113  }
114
115  JCheckBox[] weekDays =
116  {
117      sunday, monday, tuesday, wednesday, thursday, friday, saturday
118  };
119
120  private JLabel lMonthlyTime;
121  private JLabel lMonthlyDays;
122  private JTextField monthlyTime;
123  private JCheckBox[] monthDays = new JCheckBox[31];
124
125  private JLabel lCronMinute;
126  private JLabel lCronHour;
127  private JLabel lCronWeekDay;
128  private JLabel lCronMonthDay;
129  private JLabel lCronMonth;
130
131  private JTextField cronMinute;
132  private JTextField cronHour;
133  private JTextField cronWeekDay;
134  private JTextField cronMonthDay;
135  private JTextField cronMonth;
136
137  private Component launchLaterPanel;
138  private Component dailyPanel;
139  private Component weeklyPanel;
140  private Component monthlyPanel;
141  private Component cronPanel;
142
143  private LocalizableMessage LAUNCH_NOW = INFO_CTRL_PANEL_LAUNCH_NOW.get();
144  private LocalizableMessage LAUNCH_LATER = INFO_CTRL_PANEL_LAUNCH_LATER.get();
145  private LocalizableMessage LAUNCH_DAILY = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAILY.get();
146  private LocalizableMessage LAUNCH_WEEKLY = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_WEEKLY.get();
147  private LocalizableMessage LAUNCH_MONTHLY =
148    INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTHLY.get();
149  private LocalizableMessage CRON = INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON.get();
150
151  private ScheduleType schedule;
152
153  /**
154   * Default constructor.
155   * @param taskName the name of the task to be scheduled.
156   */
157  public TaskToSchedulePanel(String taskName)
158  {
159    super();
160    this.taskName = taskName;
161    createLayout();
162  }
163
164  /**
165   * Creates the layout of the panel (but the contents are not populated here).
166   */
167  private void createLayout()
168  {
169    GridBagConstraints gbc = new GridBagConstraints();
170    JEditorPane explanation = Utilities.makeHtmlPane(
171        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_SUMMARY.get(taskName).toString(),
172        ColorAndFontConstants.defaultFont);
173    gbc.gridx = 0;
174    gbc.gridy = 0;
175    gbc.gridwidth = 1;
176    gbc.fill = GridBagConstraints.HORIZONTAL;
177    add(explanation, gbc);
178    gbc.gridy ++;
179    gbc.insets.top = 10;
180    scheduleType = Utilities.createComboBox();
181    scheduleType.setModel(new DefaultComboBoxModel());
182
183    ArrayList<Object> newElements = new ArrayList<>();
184    newElements.add(new CategorizedComboBoxElement(LAUNCH_NOW,
185        CategorizedComboBoxElement.Type.REGULAR));
186    newElements.add(COMBO_SEPARATOR);
187    newElements.add(new CategorizedComboBoxElement(LAUNCH_LATER,
188        CategorizedComboBoxElement.Type.REGULAR));
189    newElements.add(COMBO_SEPARATOR);
190    newElements.add(new CategorizedComboBoxElement(LAUNCH_DAILY,
191        CategorizedComboBoxElement.Type.REGULAR));
192    newElements.add(new CategorizedComboBoxElement(LAUNCH_WEEKLY,
193        CategorizedComboBoxElement.Type.REGULAR));
194    newElements.add(new CategorizedComboBoxElement(LAUNCH_MONTHLY,
195        CategorizedComboBoxElement.Type.REGULAR));
196    newElements.add(new CategorizedComboBoxElement(CRON,
197        CategorizedComboBoxElement.Type.REGULAR));
198    updateComboBoxModel(newElements,
199        (DefaultComboBoxModel)scheduleType.getModel());
200    scheduleType.setRenderer(
201        new NoLeftInsetCategoryComboBoxRenderer(scheduleType));
202    scheduleType.addItemListener(new IgnoreItemListener(scheduleType));
203
204    gbc.weightx = 0.0;
205    gbc.anchor = GridBagConstraints.NORTHWEST;
206    gbc.fill = GridBagConstraints.NONE;
207    add(scheduleType, gbc);
208
209    launchLaterPanel = createLaunchLaterPanel();
210    dailyPanel = createDailyPanel();
211    weeklyPanel = createWeeklyPanel();
212    monthlyPanel = createMonthlyPanel();
213    cronPanel = createCronPanel();
214
215    scheduleType.addItemListener(new ItemListener()
216    {
217      public void itemStateChanged(ItemEvent ev)
218      {
219        Object element = scheduleType.getSelectedItem();
220        boolean launchLaterVisible = false;
221        boolean launchDailyVisible = false;
222        boolean launchWeeklyVisible = false;
223        boolean launchMonthlyVisible = false;
224        boolean cronVisible = false;
225        if (element != null)
226        {
227          if (element instanceof CategorizedComboBoxElement)
228          {
229            element = ((CategorizedComboBoxElement)element).getValue();
230          }
231          launchLaterVisible = element == LAUNCH_LATER;
232          launchDailyVisible = element == LAUNCH_DAILY;
233          launchWeeklyVisible = element == LAUNCH_WEEKLY;
234          launchMonthlyVisible = element == LAUNCH_MONTHLY;
235          cronVisible = element == CRON;
236        }
237        launchLaterPanel.setVisible(launchLaterVisible);
238        dailyPanel.setVisible(launchDailyVisible);
239        weeklyPanel.setVisible(launchWeeklyVisible);
240        monthlyPanel.setVisible(launchMonthlyVisible);
241        cronPanel.setVisible(cronVisible);
242      }
243    });
244    launchLaterPanel.setVisible(false);
245    dailyPanel.setVisible(false);
246    weeklyPanel.setVisible(false);
247    monthlyPanel.setVisible(false);
248    cronPanel.setVisible(false);
249
250    int width = 0;
251    int height = 0;
252    Component[] comps =
253    {launchLaterPanel, dailyPanel, weeklyPanel, monthlyPanel, cronPanel};
254    for (Component comp : comps)
255    {
256      width = Math.max(width, comp.getPreferredSize().width);
257      height = Math.max(height, comp.getPreferredSize().height);
258    }
259
260    gbc.gridy ++;
261    gbc.gridwidth = 1;
262    gbc.gridx = 0;
263    gbc.weightx = 0.0;
264    gbc.insets.left = 30;
265    add(launchLaterPanel, gbc);
266    add(dailyPanel, gbc);
267    add(weeklyPanel, gbc);
268    add(monthlyPanel, gbc);
269    add(cronPanel, gbc);
270    add(Box.createRigidArea(new Dimension(width, height)), gbc);
271    gbc.gridy ++;
272    gbc.gridx = 0;
273    gbc.fill = GridBagConstraints.VERTICAL;
274    gbc.weighty = 1.0;
275    add(Box.createVerticalGlue(), gbc);
276  }
277
278  /** {@inheritDoc} */
279  public void toBeDisplayed(boolean visible)
280  {
281    // Reset the schedule and the labels
282    if (visible)
283    {
284      schedule = null;
285      setPrimaryValid(lTime);
286      setPrimaryValid(lDay);
287      setPrimaryValid(lMonth);
288      setPrimaryValid(lYear);
289      setPrimaryValid(lWeeklyTime);
290      setPrimaryValid(lWeeklyDays);
291      setPrimaryValid(lMonthlyTime);
292      setPrimaryValid(lMonthlyDays);
293      setPrimaryValid(lCronMinute);
294      setPrimaryValid(lCronHour);
295      setPrimaryValid(lCronMonthDay);
296      setPrimaryValid(lCronMonth);
297      setPrimaryValid(lCronWeekDay);
298    }
299  }
300
301  /** {@inheritDoc} */
302  public LocalizableMessage getTitle()
303  {
304    return INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TITLE.get(taskName);
305  }
306
307  /** {@inheritDoc} */
308  public void okClicked()
309  {
310    schedule = null;
311    ArrayList<LocalizableMessage> errorMessages = new ArrayList<>();
312
313    updateErrorMessages(errorMessages);
314
315    if (!errorMessages.isEmpty())
316    {
317      displayErrorDialog(errorMessages);
318    }
319    else
320    {
321      schedule = createSchedule();
322      Utilities.getParentDialog(this).setVisible(false);
323    }
324  }
325
326  /**
327   * Checks the validity of the provided information and updates the provided
328   * collection of messages with the errors that have been found.
329   * @param errorMessages the collection of messages to be updated.
330   */
331  private void updateErrorMessages(Collection<LocalizableMessage> errorMessages)
332  {
333    Object type =
334      ((CategorizedComboBoxElement)scheduleType.getSelectedItem()).getValue();
335    if (type == LAUNCH_LATER)
336    {
337      updateLaunchLaterErrorMessages(errorMessages);
338    }
339    else if (type == LAUNCH_DAILY)
340    {
341      updateLaunchDailyErrorMessages(errorMessages);
342    }
343    else if (type == LAUNCH_WEEKLY)
344    {
345      updateLaunchWeeklyErrorMessages(errorMessages);
346    }
347    else if (type == LAUNCH_MONTHLY)
348    {
349      updateLaunchMonthlyErrorMessages(errorMessages);
350    }
351    else if (type == CRON)
352    {
353      updateCronErrorMessages(errorMessages);
354    }
355  }
356
357  /**
358   * Checks the validity of the launch later information and updates
359   * the provided collection of messages with the errors that have been found.
360   * The associated labels are also updated.
361   * @param errorMessages the collection of messages to be updated.
362   */
363  private void updateLaunchLaterErrorMessages(Collection<LocalizableMessage> errorMessages)
364  {
365    setPrimaryValid(lTime);
366    setPrimaryValid(lDay);
367    setPrimaryValid(lMonth);
368    setPrimaryValid(lYear);
369
370    int previousErrorNumber = errorMessages.size();
371
372    int y = Integer.parseInt(year.getSelectedItem().toString());
373    int d = -1;
374    int m = month.getSelectedIndex();
375    int[] h = {-1};
376    int[] min = {-1};
377    checkTime(time, lTime, h, min, errorMessages);
378    try
379    {
380      d = Integer.parseInt(day.getText().trim());
381      if (d < 0 || d > 31)
382      {
383        errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY.get());
384        setPrimaryInvalid(lDay);
385      }
386    }
387    catch (Exception ex)
388    {
389      errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY.get());
390      setPrimaryInvalid(lDay);
391    }
392
393    if (errorMessages.size() == previousErrorNumber)
394    {
395      GregorianCalendar calendar = new GregorianCalendar(y, m, d, h[0], min[0]);
396      Date date = calendar.getTime();
397      // Check that the actual date's month date corresponds to a valid day
398      // (for instance if user specifies 30th of February, the resulting date
399      // is 2nd (or 1st depending of the year) of Mars.
400      if (calendar.get(Calendar.MONTH) != m)
401      {
402        errorMessages.add(ERR_CTRL_PANEL_INVALID_DAY_IN_MONTH.get(d, month.getSelectedItem()));
403        setPrimaryInvalid(lDay);
404        setPrimaryInvalid(lMonth);
405      }
406      else if (date.before(new Date()))
407      {
408        errorMessages.add(ERR_CTRL_PANEL_DATE_ALREADY_PASSED.get());
409        setPrimaryInvalid(lTime);
410        setPrimaryInvalid(lDay);
411        setPrimaryInvalid(lMonth);
412        setPrimaryInvalid(lYear);
413      }
414    }
415  }
416
417  /**
418   * Checks the validity of the launch daily information and updates
419   * the provided collection of messages with the errors that have been found.
420   * The associated labels are also updated.
421   * @param errorMessages the collection of messages to be updated.
422   */
423  private void updateLaunchDailyErrorMessages(Collection<LocalizableMessage> errorMessages)
424  {
425    setPrimaryValid(lDailyTime);
426
427    int[] h = {-1};
428    int[] min = {-1};
429    checkTime(dailyTime, lDailyTime, h, min, errorMessages);
430  }
431
432  /**
433   * Checks the validity of the launch weekly information and updates
434   * the provided collection of messages with the errors that have been found.
435   * The associated labels are also updated.
436   * @param errorMessages the collection of messages to be updated.
437   */
438  private void updateLaunchWeeklyErrorMessages(
439      Collection<LocalizableMessage> errorMessages)
440  {
441    setPrimaryValid(lWeeklyTime);
442    setPrimaryValid(lWeeklyDays);
443
444    int[] h = {-1};
445    int[] min = {-1};
446    checkTime(weeklyTime, lWeeklyTime, h, min, errorMessages);
447
448    boolean oneSelected = false;
449    for (JCheckBox cb : weekDays)
450    {
451      if (cb.isSelected())
452      {
453        oneSelected = true;
454        break;
455      }
456    }
457    if (!oneSelected)
458    {
459      errorMessages.add(ERR_CTRL_PANEL_NO_WEEK_DAY_SELECTED.get());
460      setPrimaryInvalid(lWeeklyDays);
461    }
462  }
463
464  /**
465   * Checks the validity of the launch monthly information and updates
466   * the provided collection of messages with the errors that have been found.
467   * The associated labels are also updated.
468   * @param errorMessages the collection of messages to be updated.
469   */
470  private void updateLaunchMonthlyErrorMessages(
471      Collection<LocalizableMessage> errorMessages)
472  {
473    setPrimaryValid(lMonthlyTime);
474    setPrimaryValid(lMonthlyDays);
475
476    int[] h = {-1};
477    int[] min = {-1};
478    checkTime(monthlyTime, lMonthlyTime, h, min, errorMessages);
479
480    boolean oneSelected = false;
481    for (JCheckBox cb : monthDays)
482    {
483      if (cb.isSelected())
484      {
485        oneSelected = true;
486        break;
487      }
488    }
489    if (!oneSelected)
490    {
491      errorMessages.add(ERR_CTRL_PANEL_NO_MONTH_DAY_SELECTED.get());
492      setPrimaryInvalid(lMonthlyDays);
493    }
494  }
495
496  /**
497   * Checks the validity of the cron schedule information and updates
498   * the provided collection of messages with the errors that have been found.
499   * The associated labels are also updated.
500   * @param errorMessages the collection of messages to be updated.
501   */
502  private void updateCronErrorMessages(Collection<LocalizableMessage> errorMessages)
503  {
504    setPrimaryValid(lCronMinute);
505    setPrimaryValid(lCronHour);
506    setPrimaryValid(lCronMonthDay);
507    setPrimaryValid(lCronMonth);
508    setPrimaryValid(lCronWeekDay);
509
510    String minute = cronMinute.getText().trim();
511    String hour = cronHour.getText().trim();
512    String monthDay = cronMonthDay.getText().trim();
513    String month = cronMonth.getText().trim();
514    String weekDay = cronWeekDay.getText().trim();
515
516    updateCronErrorMessages(minute, lCronMinute,
517        ERR_CTRL_PANEL_NO_CRON_MINUTE_PROVIDED.get(),
518        ERR_CTRL_PANEL_NOT_VALID_CRON_MINUTE_PROVIDED.get(),
519        0, 59,
520        errorMessages);
521    updateCronErrorMessages(hour, lCronHour,
522        ERR_CTRL_PANEL_NO_CRON_HOUR_PROVIDED.get(),
523        ERR_CTRL_PANEL_NOT_VALID_CRON_HOUR_PROVIDED.get(),
524        0, 23,
525        errorMessages);
526    updateCronErrorMessages(weekDay, lCronWeekDay,
527        ERR_CTRL_PANEL_NO_CRON_WEEK_DAY_PROVIDED.get(),
528        ERR_CTRL_PANEL_NOT_VALID_CRON_WEEK_DAY_PROVIDED.get(),
529        0, 6,
530        errorMessages);
531    updateCronErrorMessages(monthDay, lCronMonthDay,
532        ERR_CTRL_PANEL_NO_CRON_MONTH_DAY_PROVIDED.get(),
533        ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_DAY_PROVIDED.get(),
534        1, 31,
535        errorMessages);
536    updateCronErrorMessages(month, lCronMonth,
537        ERR_CTRL_PANEL_NO_CRON_MONTH_PROVIDED.get(),
538        ERR_CTRL_PANEL_NOT_VALID_CRON_MONTH_PROVIDED.get(),
539        1, 12,
540        errorMessages);
541  }
542
543  /**
544   * Checks the validity of the cron schedule information tab and updates
545   * the provided collection of messages with the errors that have been found.
546   * The associated labels are also updated.
547   * @param value the value of the cron schedule tab.
548   * @param label the label associated with the cron schedule tab.
549   * @param errorIfEmpty the message to be displayed if the value tab is empty.
550   * @param contentError the message to be displayed if the value tab is not
551   * valid.
552   * @param minValue the minimum value accepted.
553   * @param maxValue the maximum value accepted.
554   * @param errorMessages the collection of messages to be updated.
555   */
556  private void updateCronErrorMessages(String value, JLabel label,
557      LocalizableMessage errorIfEmpty, LocalizableMessage contentError, int minValue, int maxValue,
558      Collection<LocalizableMessage> errorMessages)
559  {
560    if (value.length() == 0)
561    {
562      errorMessages.add(errorIfEmpty);
563      setPrimaryInvalid(label);
564    }
565    else
566    {
567      try
568      {
569        RecurringTask.parseTaskTabField(value, minValue, maxValue);
570      }
571      catch (Exception ex)
572      {
573        errorMessages.add(contentError);
574        setPrimaryInvalid(label);
575      }
576    }
577  }
578
579  /**
580   * Returns the schedule type corresponding to the input provided by user.
581   * This method assumes that all the date provided by the user has been
582   * validated.
583   * @return the schedule type corresponding to the input provided by user.
584   */
585  private ScheduleType createSchedule()
586  {
587    ScheduleType schedule;
588    Object type =
589      ((CategorizedComboBoxElement)scheduleType.getSelectedItem()).getValue();
590    if (type == LAUNCH_NOW)
591    {
592      schedule = ScheduleType.createLaunchNow();
593    }
594    else if (type == LAUNCH_LATER)
595    {
596      int y = Integer.parseInt(year.getSelectedItem().toString());
597      int d = Integer.parseInt(day.getText().trim());
598      int m = month.getSelectedIndex();
599      String sTime = time.getText().trim();
600      int index = sTime.indexOf(':');
601      int h = Integer.parseInt(sTime.substring(0, index).trim());
602      int min = Integer.parseInt(sTime.substring(index+1).trim());
603      GregorianCalendar calendar = new GregorianCalendar(y, m, d, h, min);
604      schedule = ScheduleType.createLaunchLater(calendar.getTime());
605    }
606    else if (type == LAUNCH_DAILY)
607    {
608      String sTime = dailyTime.getText().trim();
609      int index = sTime.indexOf(':');
610      int h = Integer.parseInt(sTime.substring(0, index).trim());
611      int m = Integer.parseInt(sTime.substring(index+1).trim());
612      String cron = m+" "+h+" * * *";
613      schedule = ScheduleType.createCron(cron);
614    }
615    else if (type == LAUNCH_WEEKLY)
616    {
617      String sTime = weeklyTime.getText().trim();
618      int index = sTime.indexOf(':');
619      int h = Integer.parseInt(sTime.substring(0, index).trim());
620      int m = Integer.parseInt(sTime.substring(index+1).trim());
621      StringBuilder sb = new StringBuilder();
622      sb.append(m).append(" ").append(h).append(" * * ");
623
624      boolean oneDayAdded = false;
625      for (int i=0; i<weekDays.length; i++)
626      {
627        if (weekDays[i].isSelected())
628        {
629          if (oneDayAdded)
630          {
631            sb.append(',');
632          }
633          sb.append(i);
634          oneDayAdded = true;
635        }
636      }
637      schedule = ScheduleType.createCron(sb.toString());
638    }
639    else if (type == LAUNCH_MONTHLY)
640    {
641      String sTime = monthlyTime.getText().trim();
642      int index = sTime.indexOf(':');
643      int h = Integer.parseInt(sTime.substring(0, index).trim());
644      int m = Integer.parseInt(sTime.substring(index+1).trim());
645      StringBuilder sb = new StringBuilder();
646      sb.append(m).append(" ").append(h).append(" ");
647      boolean oneDayAdded = false;
648      for (int i=0; i<monthDays.length; i++)
649      {
650        if (monthDays[i].isSelected())
651        {
652          if (oneDayAdded)
653          {
654            sb.append(',');
655          }
656          sb.append(i+1);
657          oneDayAdded = true;
658        }
659      }
660      sb.append(" * *");
661      schedule = ScheduleType.createCron(sb.toString());
662    }
663    else if (type == CRON)
664    {
665      String cron = cronMinute.getText().trim() + " "+
666      cronHour.getText().trim() + " "+
667      cronMonthDay.getText().trim() + " "+
668      cronMonth.getText().trim() + " "+
669      cronWeekDay.getText().trim();
670      schedule = ScheduleType.createCron(cron);
671    }
672    else
673    {
674      throw new RuntimeException("Unknown schedule type: "+type);
675    }
676    return schedule;
677  }
678
679  /**
680   * Convenience method to retrieve the time specified by the user.
681   * @param time the text field where the user specifies time.
682   * @param lTime the label associated with the text field.
683   * @param h an integer array of size 1 where the value of the hour specified
684   * by the user will be set.
685   * @param m an integer array of size 1 where the value of the minute specified
686   * by the user will be set.
687   * @param errorMessages the collection of error messages that will be updated
688   * with the encountered problems.
689   */
690  private void checkTime(JTextField time, JLabel lTime, int[] h, int[] m,
691      Collection<LocalizableMessage> errorMessages)
692  {
693    String sTime = time.getText().trim();
694    int index = sTime.indexOf(':');
695    try
696    {
697      h[0] = Integer.parseInt(sTime.substring(0, index).trim());
698      m[0] = Integer.parseInt(sTime.substring(index+1).trim());
699      if (h[0] < 0 || h[0] > 23)
700      {
701        errorMessages.add(ERR_CTRL_PANEL_INVALID_HOUR.get());
702        setPrimaryInvalid(lTime);
703      }
704      if (m[0] < 0 || m[0] > 59)
705      {
706        errorMessages.add(ERR_CTRL_PANEL_INVALID_MINUTE.get());
707        setPrimaryInvalid(lTime);
708      }
709    }
710    catch (Exception ex)
711    {
712      errorMessages.add(ERR_CTRL_PANEL_INVALID_TIME.get());
713      setPrimaryInvalid(lTime);
714    }
715  }
716
717  /**
718   * Tells whether the user chose to close the dialog discarding the provided
719   * input.
720   * @return <CODE>true</CODE> if the user chose to close the dialog discarding
721   * the provided input and <CODE>false</CODE> otherwise.
722   */
723  public boolean isCanceled()
724  {
725    return schedule == null;
726  }
727
728  /** {@inheritDoc} */
729  public void configurationChanged(ConfigurationChangeEvent ev)
730  {
731  }
732
733  /** {@inheritDoc} */
734  public Component getPreferredFocusComponent()
735  {
736    return scheduleType;
737  }
738
739  /**
740   * Returns the schedule provided by the user.
741   * @return the schedule provided by the user.
742   */
743  public ScheduleType getSchedule()
744  {
745    return schedule;
746  }
747
748  private Component createLaunchLaterPanel()
749  {
750    JPanel panel = new JPanel(new GridBagLayout());
751    panel.setOpaque(false);
752    GridBagConstraints gbc = new GridBagConstraints();
753    Calendar calendar = Calendar.getInstance();
754
755    int currentYear = calendar.get(Calendar.YEAR);
756    int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
757    int currentMinute = calendar.get(Calendar.MINUTE);
758    int currentDay = calendar.get(Calendar.DAY_OF_MONTH);
759    int currentMonth = calendar.get(Calendar.MONTH);
760
761    time = Utilities.createShortTextField();
762    PlainDocument plainTextDocument = new PlainDocument();
763    time.setDocument(plainTextDocument);
764    String sHour = currentHour >= 10 ?
765        String.valueOf(currentHour) : "0"+currentHour;
766    String sMinute = currentMinute >= 10 ?
767        String.valueOf(currentMinute) : "0"+currentMinute;
768    time.setText(sHour+":"+sMinute);
769    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(time));
770
771
772    day = Utilities.createShortTextField();
773    day.setColumns(4);
774    plainTextDocument = new PlainDocument();
775    day.setDocument(plainTextDocument);
776    day.setText(String.valueOf(currentDay));
777    plainTextDocument.setDocumentFilter(
778        new NumericLimitedSizeDocumentFilter(day, 2));
779    month = Utilities.createComboBox();
780    year = Utilities.createComboBox();
781
782    int[][] maxMin =
783    {
784        {currentYear, currentYear + 5}
785    };
786
787    JComboBox[] numericBoxes =
788    {
789        year
790    };
791
792    int[] currentValues =
793    {
794        currentYear
795    };
796
797    for (int i=0; i<maxMin.length; i++)
798    {
799      int min = maxMin[i][0];
800      int max = maxMin[i][1];
801
802      DefaultComboBoxModel model = new DefaultComboBoxModel();
803
804      int selectedIndex = 0;
805
806      int index = 0;
807      for (int j=min; j<=max; j++)
808      {
809        String s;
810        if (j < 10)
811        {
812          s = "0"+j;
813        }
814        else
815        {
816          s = String.valueOf(j);
817        }
818        model.addElement(s);
819
820        if (j == currentValues[i])
821        {
822          selectedIndex= index;
823        }
824        index++;
825      }
826
827      numericBoxes[i].setModel(model);
828
829      if (selectedIndex != 0)
830      {
831        numericBoxes[i].setSelectedIndex(selectedIndex);
832      }
833    }
834
835    DefaultComboBoxModel model = new DefaultComboBoxModel();
836    month.setModel(model);
837
838    LocalizableMessage[] monthMessages =
839    {
840        INFO_CTRL_PANEL_JANUARY.get(),
841        INFO_CTRL_PANEL_FEBRUARY.get(),
842        INFO_CTRL_PANEL_MARCH.get(),
843        INFO_CTRL_PANEL_APRIL.get(),
844        INFO_CTRL_PANEL_MAY.get(),
845        INFO_CTRL_PANEL_JUNE.get(),
846        INFO_CTRL_PANEL_JULY.get(),
847        INFO_CTRL_PANEL_AUGUST.get(),
848        INFO_CTRL_PANEL_SEPTEMBER.get(),
849        INFO_CTRL_PANEL_OCTOBER.get(),
850        INFO_CTRL_PANEL_NOVEMBER.get(),
851        INFO_CTRL_PANEL_DECEMBER.get(),
852    };
853    for (LocalizableMessage msg : monthMessages)
854    {
855      model.addElement(msg.toString());
856    }
857
858    month.setSelectedIndex(currentMonth);
859
860    lTime = Utilities.createPrimaryLabel(
861        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
862    lDay = Utilities.createPrimaryLabel(
863        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_DAY.get());
864    lMonth = Utilities.createPrimaryLabel(
865        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_MONTH.get());
866    lYear = Utilities.createPrimaryLabel(
867        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_YEAR.get());
868
869    gbc.gridy = 0;
870
871    JLabel[] labels = {lTime, lDay, lMonth, lYear};
872    JComponent[] comps = {time, day, month, year};
873    LocalizableMessage[] inlineHelp =
874    {
875        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME_TOOLTIP.get(),
876        null,
877        null,
878        null
879    };
880
881    gbc.gridwidth = 1;
882    gbc.fill = GridBagConstraints.HORIZONTAL;
883
884    for (int i=0; i<labels.length; i++)
885    {
886      gbc.gridx = 0;
887      gbc.weightx = 0.0;
888      gbc.gridwidth = 1;
889
890      panel.add(labels[i], gbc);
891      gbc.gridx = 1;
892      gbc.insets.left = 10;
893      panel.add(comps[i], gbc);
894      gbc.gridx = 2;
895      gbc.weightx = 1.0;
896      gbc.insets.left = 0;
897      panel.add(Box.createHorizontalGlue(), gbc);
898
899      if (inlineHelp[i] != null)
900      {
901        gbc.gridwidth = 2;
902        gbc.insets.top = 3;
903        gbc.insets.left = 10;
904        gbc.gridx = 1;
905        gbc.gridy ++;
906        panel.add(Utilities.createInlineHelpLabel(inlineHelp[i]), gbc);
907      }
908
909      gbc.insets.top = 10;
910      gbc.gridy ++;
911    }
912
913    gbc.insets.top = 0;
914    gbc.weighty = 1.0;
915    gbc.fill = GridBagConstraints.VERTICAL;
916    panel.add(Box.createVerticalGlue(), gbc);
917
918    return panel;
919  }
920
921  private Component createDailyPanel()
922  {
923    JPanel panel = new JPanel(new GridBagLayout());
924    panel.setOpaque(false);
925    GridBagConstraints gbc = new GridBagConstraints();
926    gbc.gridx = 0;
927    gbc.gridy = 0;
928    gbc.weightx = 0.0;
929
930    lDailyTime =
931      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
932
933    dailyTime = Utilities.createShortTextField();
934    PlainDocument plainTextDocument = new PlainDocument();
935    dailyTime.setDocument(plainTextDocument);
936    dailyTime.setColumns(4);
937    dailyTime.setText("00:00");
938    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(dailyTime));
939
940    panel.add(lDailyTime, gbc);
941    gbc.gridx = 1;
942    gbc.insets.left = 10;
943    gbc.fill = GridBagConstraints.NONE;
944    panel.add(dailyTime, gbc);
945    gbc.gridx = 2;
946    gbc.weightx = 1.0;
947    gbc.insets.left = 0;
948    gbc.fill = GridBagConstraints.HORIZONTAL;
949    panel.add(Box.createHorizontalGlue(), gbc);
950
951    gbc.gridy ++;
952    gbc.gridwidth = 2;
953    gbc.insets.top = 3;
954    gbc.insets.left = 10;
955    gbc.gridx = 1;
956    panel.add(Utilities.createInlineHelpLabel(
957        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME_TOOLTIP.get()), gbc);
958
959    return panel;
960  }
961
962  private Component createWeeklyPanel()
963  {
964    JPanel panel = new JPanel(new GridBagLayout());
965    panel.setOpaque(false);
966    GridBagConstraints gbc = new GridBagConstraints();
967    gbc.gridx = 0;
968    gbc.gridy = 0;
969    gbc.weightx = 0.0;
970
971    lWeeklyTime =
972      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
973
974    weeklyTime = Utilities.createShortTextField();
975    PlainDocument plainTextDocument = new PlainDocument();
976    weeklyTime.setDocument(plainTextDocument);
977    weeklyTime.setColumns(4);
978    weeklyTime.setText("00:00");
979    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(weeklyTime));
980
981    lWeeklyDays = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DAYS.get());
982    for (JCheckBox cb : weekDays)
983    {
984      cb.setFont(ColorAndFontConstants.inlineHelpFont);
985    }
986    sunday.setSelected(true);
987    wednesday.setSelected(true);
988
989    gbc.anchor = GridBagConstraints.WEST;
990    panel.add(lWeeklyTime, gbc);
991    gbc.gridx = 1;
992    gbc.insets.left = 10;
993    gbc.gridwidth = weekDays.length;
994    gbc.fill = GridBagConstraints.NONE;
995    panel.add(weeklyTime, gbc);
996    gbc.gridx = 2;
997    gbc.weightx = 1.0;
998    gbc.insets.left = 0;
999    gbc.gridwidth = 1;
1000    gbc.fill = GridBagConstraints.HORIZONTAL;
1001    panel.add(Box.createHorizontalGlue(), gbc);
1002    gbc.gridy ++;
1003    gbc.gridwidth = weekDays.length + 1;
1004    gbc.insets.top = 3;
1005    gbc.insets.left = 10;
1006    gbc.gridx = 1;
1007    panel.add(Utilities.createInlineHelpLabel(
1008        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME_TOOLTIP.get()), gbc);
1009
1010    gbc.gridx = 0;
1011    gbc.gridy ++;
1012    gbc.insets.top = 10;
1013    gbc.weightx = 1.0;
1014    panel.add(lWeeklyDays, gbc);
1015    gbc.insets.left = 10;
1016    gbc.gridwidth = 1;
1017    for (JCheckBox cb : weekDays)
1018    {
1019      gbc.gridx ++;
1020      panel.add(cb, gbc);
1021    }
1022    gbc.weightx = 1.0;
1023    gbc.insets.left = 0;
1024    gbc.gridwidth = 1;
1025    gbc.gridx ++;
1026    panel.add(Box.createHorizontalGlue(), gbc);
1027
1028    return panel;
1029  }
1030
1031  private Component createMonthlyPanel()
1032  {
1033    JPanel panel = new JPanel(new GridBagLayout());
1034    panel.setOpaque(false);
1035    GridBagConstraints gbc = new GridBagConstraints();
1036    gbc.gridx = 0;
1037    gbc.gridy = 0;
1038    gbc.weightx = 0.0;
1039
1040    lMonthlyTime =
1041      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME.get());
1042
1043    monthlyTime = Utilities.createShortTextField();
1044    PlainDocument plainTextDocument = new PlainDocument();
1045    monthlyTime.setDocument(plainTextDocument);
1046    monthlyTime.setColumns(4);
1047    monthlyTime.setText("00:00");
1048    plainTextDocument.setDocumentFilter(new TimeDocumentFilter(monthlyTime));
1049
1050    lMonthlyDays = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_DAYS.get());
1051
1052    gbc.anchor = GridBagConstraints.WEST;
1053    panel.add(lMonthlyTime, gbc);
1054    gbc.gridx = 1;
1055    gbc.insets.left = 10;
1056    gbc.fill = GridBagConstraints.NONE;
1057    gbc.gridwidth = 7;
1058    panel.add(monthlyTime, gbc);
1059    gbc.gridx = 2;
1060    gbc.weightx = 1.0;
1061    gbc.insets.left = 0;
1062    gbc.gridwidth = 1;
1063    gbc.fill = GridBagConstraints.HORIZONTAL;
1064    panel.add(Box.createHorizontalGlue(), gbc);
1065    gbc.gridy ++;
1066    gbc.gridwidth = 8;
1067    gbc.insets.top = 3;
1068    gbc.insets.left = 10;
1069    gbc.gridx = 1;
1070    panel.add(Utilities.createInlineHelpLabel(
1071        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME_TOOLTIP.get()), gbc);
1072
1073    gbc.gridx = 0;
1074    gbc.gridy ++;
1075    gbc.insets.top = 10;
1076    gbc.weightx = 1.0;
1077    gbc.gridwidth = 1;
1078    panel.add(lMonthlyDays, gbc);
1079    gbc.insets.left = 10;
1080    gbc.gridwidth = 1;
1081    for (int i=0 ; i<monthDays.length; i++)
1082    {
1083      monthDays[i] = Utilities.createCheckBox(LocalizableMessage.raw(String.valueOf(i+1)));
1084      monthDays[i].setFont(ColorAndFontConstants.inlineHelpFont);
1085      int x = i % 7;
1086      if (x == 0 && i != 0)
1087      {
1088        gbc.gridy ++;
1089        gbc.insets.top = 5;
1090      }
1091      if (x != 0)
1092      {
1093        gbc.insets.left = 5;
1094      }
1095      else
1096      {
1097        gbc.insets.left = 10;
1098      }
1099      gbc.gridx = x + 1;
1100      panel.add(monthDays[i], gbc);
1101    }
1102    monthDays[0].setSelected(true);
1103    gbc.weightx = 1.0;
1104    gbc.insets.left = 0;
1105    gbc.gridwidth = 1;
1106    gbc.gridx ++;
1107    panel.add(Box.createHorizontalGlue(), gbc);
1108
1109    return panel;
1110  }
1111
1112  private Component createCronPanel()
1113  {
1114    JPanel panel = new JPanel(new GridBagLayout());
1115    panel.setOpaque(false);
1116    GridBagConstraints gbc = new GridBagConstraints();
1117
1118    JEditorPane explanation = Utilities.makeHtmlPane(
1119        INFO_CTRL_PANEL_CRON_HELP.get(),
1120        ColorAndFontConstants.inlineHelpFont);
1121    gbc.gridx = 0;
1122    gbc.gridy = 0;
1123    gbc.gridwidth = 2;
1124    gbc.fill = GridBagConstraints.HORIZONTAL;
1125    panel.add(explanation, gbc);
1126    gbc.gridy ++;
1127    gbc.insets.top = 10;
1128
1129    gbc.gridwidth = 1;
1130    lCronMinute = Utilities.createPrimaryLabel(
1131        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MINUTE.get());
1132    lCronHour = Utilities.createPrimaryLabel(
1133        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_HOUR.get());
1134    lCronWeekDay = Utilities.createPrimaryLabel(
1135        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_WEEK_DAY.get());
1136    lCronMonthDay = Utilities.createPrimaryLabel(
1137        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH_DAY.get());
1138    lCronMonth = Utilities.createPrimaryLabel(
1139        INFO_CTRL_PANEL_TASK_TO_SCHEDULE_CRON_MONTH.get());
1140
1141    cronMinute = Utilities.createShortTextField();
1142    cronMinute.setText("*");
1143
1144    cronHour = Utilities.createShortTextField();
1145    cronHour.setText("*");
1146
1147    cronWeekDay = Utilities.createShortTextField();
1148    cronWeekDay.setText("*");
1149
1150    cronMonthDay = Utilities.createShortTextField();
1151    cronMonthDay.setText("*");
1152
1153    cronMonth = Utilities.createShortTextField();
1154    cronMonth.setText("*");
1155
1156    JLabel[] labels = {lCronMinute, lCronHour, lCronWeekDay, lCronMonthDay,
1157        lCronMonth};
1158    Component[] comps = {cronMinute, cronHour, cronWeekDay, cronMonthDay,
1159        cronMonth};
1160    LocalizableMessage[] help =
1161    {
1162      INFO_CTRL_PANEL_CRON_MINUTE_HELP.get(),
1163      INFO_CTRL_PANEL_CRON_HOUR_HELP.get(),
1164      INFO_CTRL_PANEL_CRON_WEEK_DAY_HELP.get(),
1165      INFO_CTRL_PANEL_CRON_MONTH_DAY_HELP.get(),
1166      INFO_CTRL_PANEL_CRON_MONTH_HELP.get(),
1167    };
1168
1169    gbc.gridwidth = 1;
1170    gbc.fill = GridBagConstraints.HORIZONTAL;
1171
1172    for (int i=0; i<labels.length; i++)
1173    {
1174      gbc.gridx = 0;
1175      gbc.weightx = 0.0;
1176
1177      gbc.insets.left = 0;
1178      panel.add(labels[i], gbc);
1179      gbc.gridx = 1;
1180      gbc.insets.left = 10;
1181      panel.add(comps[i], gbc);
1182      gbc.gridx = 2;
1183      gbc.weightx = 1.0;
1184      gbc.insets.left = 0;
1185      panel.add(Box.createHorizontalGlue(), gbc);
1186      if (help[i] != null)
1187      {
1188        gbc.insets.top = 3;
1189        gbc.insets.left = 10;
1190        gbc.gridy ++;
1191        gbc.gridx = 1;
1192        panel.add(Utilities.createInlineHelpLabel(help[i]), gbc);
1193      }
1194
1195      gbc.insets.top = 10;
1196      gbc.gridy ++;
1197    }
1198
1199    gbc.insets.top = 0;
1200    gbc.weighty = 1.0;
1201    gbc.fill = GridBagConstraints.VERTICAL;
1202    panel.add(Box.createVerticalGlue(), gbc);
1203
1204    return panel;
1205  }
1206
1207  /**
1208   * The main method to test this panel.
1209   * @param args the arguments.
1210   */
1211  public static void main(String[] args)
1212  {
1213    while (true)
1214    {
1215      TaskToSchedulePanel p = new TaskToSchedulePanel("TEST TASK");
1216      GenericDialog dlg = new GenericDialog(Utilities.createFrame(), p);
1217      dlg.setModal(true);
1218      dlg.setVisible(true);
1219    }
1220  }
1221}