From bd7162eca5451009651c79b287138c95a7817232 Mon Sep 17 00:00:00 2001 From: Ron Anderson Date: Tue, 11 Dec 2012 08:13:24 -0600 Subject: [PATCH] Issue #1395 Modifed AwipsCalender and added additional date/time related widgets Change-Id: I123a63ff4a42d36b2a35229dff719eda49097f7b Former-commit-id: bc5f445ecf25fa8aa39d13ee9fc269e75c7796e9 [formerly bc5f445ecf25fa8aa39d13ee9fc269e75c7796e9 [formerly 475861fe615a070f1a3cad18dd798ba6db6b66e8]] Former-commit-id: 43881be47a7efc71307a5610eb87d2b091bd11c4 Former-commit-id: 641d268bd80a3f06c15b9e1e1ac209a0eae91570 --- cave/build/p2-build.xml | 20 +- .../uf/viz/stats/ui/StatsControlDlg.java | 42 +- .../feature.xml | 4 + cave/com.raytheon.viz.ui/icons/calendar.gif | Bin 0 -> 424 bytes .../viz/ui/dialogs/AwipsCalendar.java | 199 +++--- .../viz/ui/widgets/DateTimeEntry.java | 244 +++++++ .../raytheon/viz/ui/widgets/TimeEntry.java | 625 ++++++++++++++++++ .../viz/ui/widgets/TimeRangeEntry.java | 156 +++++ 8 files changed, 1186 insertions(+), 104 deletions(-) create mode 100644 cave/com.raytheon.viz.ui/icons/calendar.gif create mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/DateTimeEntry.java create mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeEntry.java create mode 100644 cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeRangeEntry.java diff --git a/cave/build/p2-build.xml b/cave/build/p2-build.xml index c9d3bd9fb5..02a7b7d4ad 100644 --- a/cave/build/p2-build.xml +++ b/cave/build/p2-build.xml @@ -266,18 +266,18 @@ - - - + + + - - - + + + @@ -286,6 +286,10 @@ + + + diff --git a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java index 21a58bfe03..013b15fec7 100644 --- a/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java +++ b/cave/com.raytheon.uf.viz.stats/src/com/raytheon/uf/viz/stats/ui/StatsControlDlg.java @@ -62,17 +62,17 @@ import com.raytheon.viz.ui.widgets.duallist.IUpdate; /** * Stats graphing control dialog. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Sep 25, 2012            mpduff     Initial creation
- *
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ @@ -160,8 +160,9 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, /** * Constructor. - * - * @param parent parent Shell + * + * @param parent + * parent Shell */ public StatsControlDlg(Shell parent) { super(parent, SWT.DIALOG_TRIM, CAVE.INDEPENDENT_SHELL @@ -401,10 +402,13 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, /** * Display an informational popup message to the user. - * - * @param title The title - * @param message The message - * @param type Type of message + * + * @param title + * The title + * @param message + * The message + * @param type + * Type of message */ public void displayPopup(String title, String message, int type) { MessageBox messageDialog = new MessageBox(getShell(), type); @@ -415,8 +419,9 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, /** * Set the data types. - * - * @param dataTypes String[] of data types + * + * @param dataTypes + * String[] of data types */ public void setDataTypes(String[] dataTypes) { if (dataTypes != null) { @@ -429,11 +434,11 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, * Date/Time selection handler */ protected void handleDateTimeSelection() { - AwipsCalendar ac = new AwipsCalendar(getShell(), selectedDate, true); + AwipsCalendar ac = new AwipsCalendar(getShell(), selectedDate, 1); Object obj = ac.open(); - if ((obj != null) && (obj instanceof Calendar)) { - selectedDate = ((Calendar) obj).getTime(); + if ((obj != null) && (obj instanceof Date)) { + selectedDate = (Date) obj; dateTimeSelectedLabel.setText(getFormattedDate(selectedDate)); } } @@ -647,8 +652,9 @@ public class StatsControlDlg extends CaveSWTDialog implements IStatsControl, /** * Format the date. - * - * @param date The date to format + * + * @param date + * The date to format * @return the formated string */ private String getFormattedDate(Date date) { diff --git a/cave/com.raytheon.viz.feature.awips.developer/feature.xml b/cave/com.raytheon.viz.feature.awips.developer/feature.xml index d4ef19206a..e33173b5b0 100644 --- a/cave/com.raytheon.viz.feature.awips.developer/feature.xml +++ b/cave/com.raytheon.viz.feature.awips.developer/feature.xml @@ -164,6 +164,10 @@ + + diff --git a/cave/com.raytheon.viz.ui/icons/calendar.gif b/cave/com.raytheon.viz.ui/icons/calendar.gif new file mode 100644 index 0000000000000000000000000000000000000000..7977e01968bd9ccb37d26d3f83481bbfbfca2789 GIT binary patch literal 424 zcmex=rv2k^IE_ z>YsD=e1GPA`R&dJf!PaRA2*CyJgJ~6hu{7FmkNKqZ*POPtc;#N&AsVNrp%mT2D`;= a%t{93jdNdLpZdLXs>0M&w)&I*-vj{I>TALP literal 0 HcmV?d00001 diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/AwipsCalendar.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/AwipsCalendar.java index df9da24787..3f2d4bf68f 100644 --- a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/AwipsCalendar.java +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/dialogs/AwipsCalendar.java @@ -19,6 +19,7 @@ **/ package com.raytheon.viz.ui.dialogs; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; @@ -33,80 +34,108 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DateTime; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Spinner; + +import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.viz.ui.widgets.TimeEntry; /** * Awips Calendar Date Selection Dialog. - * + * *
- *
+ * 
  * SOFTWARE HISTORY
- *
+ * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Jan 9, 2012            mpduff     Initial creation
- *
+ * 
  * 
- * + * * @author mpduff * @version 1.0 */ public class AwipsCalendar extends CaveSWTDialogBase { - /** The date selection calendar class */ + /** The date selection calendar widget */ private DateTime calendar; - /** The hour selection spinner class */ - private Spinner hourSpinner; + /** the time selection widget */ + private TimeEntry timeEntry; - /** The showHour flag */ - private boolean showHour = true; + private int timeFieldCount; - /** The showHour flag */ private Date date = null; - /** - * Constructor. - * - * @param parentShell - * @param showHour - */ - public AwipsCalendar(Shell parentShell, boolean showHour) { - super(parentShell, SWT.DIALOG_TRIM); - setText("Calendar"); - this.showHour = showHour; - } + private TimeZone timeZone; /** * Constructor. - * + * * @param parentShell */ public AwipsCalendar(Shell parentShell) { - super(parentShell, SWT.DIALOG_TRIM); - setText("Calendar"); - - + this(parentShell, null, 0); } /** * Constructor. - * + * * @param parentShell - * @param d Date to preset the calendar widget - * @param showHour true to display the hour spinner + * @param timeFieldCount + * number of time fields to display + * + *
+     *   0 - do not display time field 
+     *   1 - display hours 
+     *   2 - display hours and minutes 
+     *   3 - display hours, minutes, and seconds
+     * 
*/ - public AwipsCalendar(Shell parentShell, Date d, boolean showHour) { + public AwipsCalendar(Shell parentShell, int timeFieldCount) { + this(parentShell, null, timeFieldCount); + } + + /** + * Constructor. + * + * @param parentShell + * @param d + * Date to preset the calendar widget + * @param timeFieldCount + * number of time fields to display + * + *
+     *   0 - do not display time field 
+     *   1 - display hours 
+     *   2 - display hours and minutes
+     *   3 - display hours, minutes, and seconds
+     * 
+ */ + public AwipsCalendar(Shell parentShell, Date d, int timeFieldCount) { super(parentShell, SWT.DIALOG_TRIM); setText("Calendar"); this.date = d; - this.showHour = showHour; + if (timeFieldCount < 0 || timeFieldCount > 3) { + throw new IllegalArgumentException( + "timeFieldCount must be 0, 1, 2, or 3"); + } + this.timeFieldCount = timeFieldCount; + this.timeZone = TimeZone.getTimeZone("GMT"); + } + + /** + * The time zone used for displaying the time field + * + * @param timeZone + */ + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; } /* * (non-Javadoc) - * + * * @see * com.raytheon.viz.ui.dialogs.CaveSWTDialogBase#initializeComponents(org * .eclipse.swt.widgets.Shell) @@ -114,49 +143,53 @@ public class AwipsCalendar extends CaveSWTDialogBase { @Override protected void initializeComponents(Shell shell) { - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + Calendar cal = TimeUtil.newCalendar(this.timeZone); if (date != null) { cal.setTime(date); } + GridLayout layout = new GridLayout(2, false); + shell.setLayout(layout); - if (showHour) { - createTopWidgets(cal.get(Calendar.HOUR_OF_DAY)); + if (timeFieldCount > 0) { + Label lbl = new Label(shell, SWT.NONE); + GridData layoutData = new GridData(SWT.LEFT, SWT.CENTER, true, + false); + lbl.setLayoutData(layoutData); + TimeZone tz = cal.getTimeZone(); + String tzId = "Z"; + if (tz.getRawOffset() != 0) { + SimpleDateFormat sdf = new SimpleDateFormat("z"); + sdf.setTimeZone(tz); + // date below is not used + // we just want to get the tz abbreviation + tzId = sdf.format(new Date()); + } + + if (timeFieldCount == 1) { + lbl.setText("Select Hour (" + tzId + ") and Date: "); + } else { + lbl.setText("Select Time (" + tzId + ") and Date: "); + } + + timeEntry = new TimeEntry(shell, timeFieldCount); + layoutData = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false); + timeEntry.setLayoutData(layoutData); + timeEntry.setTime(cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)); } - calendar = new DateTime(shell, SWT.CALENDAR | SWT.BORDER_SOLID); - calendar.setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); + calendar = new DateTime(shell, SWT.CALENDAR | SWT.BORDER); + GridData layoutData = new GridData(SWT.DEFAULT, SWT.DEFAULT, false, + false); + layoutData.horizontalSpan = 2; + calendar.setLayoutData(layoutData); + calendar.setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), + cal.get(Calendar.DAY_OF_MONTH)); createButtons(); } - /** - * Create the top widgets - */ - private void createTopWidgets(int hour) { - GridLayout gl = new GridLayout(2, false); - GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false); - - Composite top = new Composite(shell, SWT.NONE); - top.setLayout(gl); - top.setLayoutData(gd); - - gd = new GridData(SWT.LEFT, SWT.DEFAULT, true, false); - Label lbl = new Label(top, SWT.NONE); - lbl.setLayoutData(gd); - lbl.setText("Select Hour (Z) and Date: "); - - gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false); - - hourSpinner = new Spinner(top, SWT.BORDER | SWT.RIGHT); - hourSpinner.setLayoutData(gd); - hourSpinner.setMinimum(0); - hourSpinner.setMaximum(23); - hourSpinner.setSelection(hour); - hourSpinner.setIncrement(1); - hourSpinner.setPageIncrement(1); - } - /** * Create the buttons */ @@ -165,6 +198,7 @@ public class AwipsCalendar extends CaveSWTDialogBase { GridData btnData = new GridData(buttonWidth, SWT.DEFAULT); GridData gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false); + gd.horizontalSpan = 2; GridLayout gl = new GridLayout(3, false); Composite btnComp = new Composite(shell, SWT.NONE); btnComp.setLayout(gl); @@ -196,31 +230,40 @@ public class AwipsCalendar extends CaveSWTDialogBase { * Event handler action for OK button */ private void handleOk() { - Calendar selectedDate = Calendar.getInstance(TimeZone - .getTimeZone("GMT")); + Calendar selectedDate = Calendar.getInstance(this.timeZone); selectedDate.set(Calendar.YEAR, calendar.getYear()); selectedDate.set(Calendar.MONTH, calendar.getMonth()); selectedDate.set(Calendar.DAY_OF_MONTH, calendar.getDay()); - if (showHour) { - selectedDate.set(Calendar.HOUR_OF_DAY, - Integer.parseInt(hourSpinner.getText())); + if (timeFieldCount > 0) { + selectedDate.set(Calendar.HOUR_OF_DAY, timeEntry.getHours()); + selectedDate.set(Calendar.MINUTE, timeEntry.getMinutes()); + selectedDate.set(Calendar.SECOND, timeEntry.getSeconds()); } else { selectedDate.set(Calendar.HOUR_OF_DAY, 0); + selectedDate.set(Calendar.MINUTE, 0); + selectedDate.set(Calendar.SECOND, 0); } - selectedDate.set(Calendar.MINUTE, 0); - selectedDate.set(Calendar.SECOND, 0); selectedDate.set(Calendar.MILLISECOND, 0); - this.setReturnValue(selectedDate); + + this.setReturnValue(selectedDate.getTime()); } /** * Main - * + * * @param args */ public static void main(String[] args) { - AwipsCalendar ac = new AwipsCalendar(new Shell()); - ac.open(); + AwipsCalendar ac = new AwipsCalendar(new Shell(), 1); + ac.setTimeZone(TimeZone.getDefault()); + Date date = (Date) ac.open(); + if (date == null) { + System.out.println("null"); + } else { + SimpleDateFormat sdf = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + System.out.println(sdf.format(date)); + } } - } diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/DateTimeEntry.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/DateTimeEntry.java new file mode 100644 index 0000000000..e0cd1ddc0b --- /dev/null +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/DateTimeEntry.java @@ -0,0 +1,244 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.ui.widgets; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Text; + +import com.raytheon.viz.ui.UiPlugin; +import com.raytheon.viz.ui.dialogs.AwipsCalendar; + +/** + * Date/Time entry widget with read-only text and button to pop up and editable + * dialog to enter the date and time. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 6, 2012            randerso     Initial creation
+ * 
+ * 
+ * + * @author randerso + * @version 1.0 + */ + +public class DateTimeEntry extends Composite { + /** + * Interface for a listener to receive notification when a DateTimeEntry + * widget is updated + */ + public static interface IUpdateListener { + /** + * Called when the associated DateTimeEntry widget is updated. + * + * @param date + * the newly updated date + */ + public void dateTimeUpdated(Date date); + } + + private static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + private SimpleDateFormat sdf; + + private String dateFormat; + + private Date date; + + private Text text; + + private ListenerList listeners; + + /** + * Construct a DateTimeEnty widget + * + * @param parent + */ + public DateTimeEntry(Composite parent) { + super(parent, SWT.NONE); + dateFormat = DEFAULT_DATE_FORMAT; + sdf = new SimpleDateFormat(dateFormat); + date = new Date(); + listeners = new ListenerList(); + + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + layout.horizontalSpacing = 0; + setLayout(layout); + + text = new Text(this, SWT.BORDER | SWT.READ_ONLY); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + text.setLayoutData(layoutData); + + Button button = new Button(this, SWT.PUSH); + ImageDescriptor imageDesc = UiPlugin + .getImageDescriptor("icons/calendar.gif"); + Image image = imageDesc.createImage(); + button.setImage(image); + image.dispose(); + + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int fieldCount = getFieldCount(); + AwipsCalendar dlg = new AwipsCalendar(getShell(), date, + fieldCount); + dlg.setTimeZone(sdf.getTimeZone()); + Date selectedDate = (Date) dlg.open(); + if (selectedDate != null) { + updateDate(selectedDate); + } + } + }); + + updateDate(this.date); + } + + private int getFieldCount() { + int fieldCount = 0; + if (dateFormat.contains("s")) { + fieldCount = 3; + } else if (dateFormat.contains("m")) { + fieldCount = 2; + } else if (dateFormat.contains("h") || dateFormat.contains("H")) { + fieldCount = 1; + } + return fieldCount; + } + + private void updateDate(Date date) { + text.setText(sdf.format(date)); + try { + this.date = sdf.parse(text.getText()); + } catch (ParseException e) { + // should never happen since we just formatted the string + // using the same SimpleDateFormat + } + + fireUpdateListeners(this.date); + } + + /** + * Sets the date format string used to format the date/time string for + * display + * + * @param dateFormat + * the date format string see {@link SimpleDateFormat} for more + * information. + */ + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + this.sdf.applyPattern(dateFormat); + updateDate(date); + } + + /** + * Sets the time zone used to format the date/time string for display + * + * @param tz + * the time zone + */ + public void setTimeZone(TimeZone tz) { + sdf.setTimeZone(tz); + updateDate(date); + } + + /** + * Sets the contents of the receiver to the given date + * + * @param date + * the date + */ + public void setDate(Date date) { + updateDate(date); + } + + /** + * Retrieve the date from the widget + * + * @return the date + */ + public Date getDate() { + return this.date; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.widgets.Control#setEnabled(boolean) + */ + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + for (Control c : getChildren()) { + c.setEnabled(enabled); + } + } + + /** + * Add a listener to be called when this widget is updated. + * + * @param listener + */ + public void addUpdateListener(IUpdateListener listener) { + listeners.add(listener); + } + + /** + * Remove a listener + * + * @param listener + */ + public void removeUpdateListener(IUpdateListener listener) { + listeners.remove(listener); + } + + /** + * Notify listeners of the updated date + * + * @param date + * the updated date + */ + private void fireUpdateListeners(Date date) { + for (Object listener : listeners.getListeners()) { + ((IUpdateListener) listener).dateTimeUpdated(date); + } + } +} diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeEntry.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeEntry.java new file mode 100644 index 0000000000..12638d4a8d --- /dev/null +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeEntry.java @@ -0,0 +1,625 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.ui.widgets; + +import java.util.Calendar; +import java.util.TimeZone; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DateTime; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * Time of day entry field. Heavily borrowed from {@link DateTime} + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 10, 2012            randerso     Initial creation
+ * 
+ * 
+ * + * @author randerso + * @version 1.0 + */ + +public class TimeEntry extends Composite { + + private static Point[] fieldIndices = new Point[] { new Point(0, 2), + new Point(3, 5), new Point(6, 8) }; + + private static int[] fieldNames = new int[] { Calendar.HOUR_OF_DAY, + Calendar.MINUTE, Calendar.SECOND }; + + private static String[] formatStrings = new String[] { "%02d", "%02d:%02d", + "%02d:%02d:%02d" }; + + private static String[] computeSizeStrings = new String[] { "99", "99:99", + "99:99:99" }; + + private Text text; + + private Button up; + + private Button down; + + private int fieldCount; + + private int characterCount = 0; + + private int currentField = 0; + + private Calendar calendar; + + private boolean ignoreVerify; + + /** + * Constructor + * + * @param parent + * @param fieldCount + * 1 = HH, 2 = HH:MM 3 = HH:MM:SS + * + */ + public TimeEntry(Composite parent, int fieldCount) { + super(parent, SWT.NONE); + if (fieldCount < 1 || fieldCount > 3) { + throw new IllegalArgumentException("fieldCount must be 1, 2, or 3"); + } + this.fieldCount = fieldCount; + calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + + text = new Text(this, SWT.SINGLE | SWT.READ_ONLY | SWT.BORDER); + Listener listener = new Listener() { + @Override + public void handleEvent(Event event) { + switch (event.type) { + case SWT.KeyDown: + onKeyDown(event); + break; + case SWT.FocusIn: + onFocusIn(event); + break; + case SWT.FocusOut: + onFocusOut(event); + break; + case SWT.MouseDown: + onMouseClick(event); + break; + case SWT.MouseUp: + onMouseClick(event); + break; + case SWT.Verify: + onVerify(event); + break; + } + } + }; + + text.addListener(SWT.KeyDown, listener); + text.addListener(SWT.FocusIn, listener); + text.addListener(SWT.FocusOut, listener); + text.addListener(SWT.MouseDown, listener); + text.addListener(SWT.MouseUp, listener); + text.addListener(SWT.Verify, listener); + up = new Button(this, SWT.ARROW | SWT.UP); + down = new Button(this, SWT.ARROW | SWT.DOWN); + up.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + incrementField(+1); + text.setFocus(); + } + }); + down.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + incrementField(-1); + text.setFocus(); + } + }); + addListener(SWT.Resize, new Listener() { + @Override + public void handleEvent(Event event) { + onResize(event); + } + }); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + checkWidget(); + int width = 0, height = 0; + if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) { + /* SWT.DATE and SWT.TIME */ + GC gc = new GC(text); + Point textSize = gc + .stringExtent(computeSizeStrings[fieldCount - 1]); + gc.dispose(); + Rectangle trim = text.computeTrim(0, 0, textSize.x, textSize.y); + Point buttonSize = up + .computeSize(SWT.DEFAULT, SWT.DEFAULT, changed); + width = trim.width + buttonSize.x; + height = Math.max(trim.height, buttonSize.y); + } + if (width == 0) { + width = SWT.DEFAULT; + } + if (height == 0) { + height = SWT.DEFAULT; + } + if (wHint != SWT.DEFAULT) { + width = wHint; + } + if (hHint != SWT.DEFAULT) { + height = hHint; + } + int border = getBorderWidth(); + width += border * 2; + height += border * 2; + return new Point(width, height); + } + + protected void incrementField(int amount) { + int fieldName = fieldNames[currentField]; + int value = calendar.get(fieldName); + setTextField(fieldName, value + amount, true); + } + + void setTextField(int fieldName, int value, boolean commit) { + if (commit) { + int max = calendar.getActualMaximum(fieldName); + int min = calendar.getActualMinimum(fieldName); + if (value > max) { + value = min; // wrap + } + if (value < min) { + value = max; // wrap + } + } + int start = fieldIndices[currentField].x; + int end = fieldIndices[currentField].y; + text.setSelection(start, end); + String newValue = String.format("%02d", value); + ignoreVerify = true; + text.insert(newValue); + ignoreVerify = false; + selectField(currentField); + if (commit) { + setField(fieldName, value); + } + } + + void selectField(int index) { + if (index != currentField) { + commitCurrentField(); + } + final int start = fieldIndices[index].x; + final int end = fieldIndices[index].y; + Point pt = text.getSelection(); + if (index == currentField && start == pt.x && end == pt.y) { + return; + } + currentField = index; + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!text.isDisposed()) { + String value = text.getText(start, end - 1); + int s = value.lastIndexOf(' '); + if (s == -1) { + s = start; + } else { + s = start + s + 1; + } + text.setSelection(s, end); + } + } + }); + } + + void setField(int fieldName, int value) { + if (calendar.get(fieldName) == value) { + return; + } + calendar.set(fieldName, value); + // TODO + // sendSelectionEvent(SWT.Selection); + } + + void commitCurrentField() { + if (characterCount > 0) { + characterCount = 0; + int fieldName = fieldNames[currentField]; + int start = fieldIndices[currentField].x; + int end = fieldIndices[currentField].y; + String value = text.getText(start, end - 1); + int s = value.lastIndexOf(' '); + if (s != -1) { + value = value.substring(s + 1); + } + int newValue = unformattedIntValue(fieldName, value, + calendar.getActualMaximum(fieldName)); + if (newValue != -1) { + setTextField(fieldName, newValue, true); + } + } + } + + int unformattedIntValue(int fieldName, String newText, int max) { + int newValue; + try { + newValue = Integer.parseInt(newText); + } catch (NumberFormatException ex) { + return -1; + } + return newValue; + } + + protected void onResize(Event event) { + Rectangle rect = getClientArea(); + int width = rect.width; + int height = rect.height; + Point buttonSize = up.computeSize(SWT.DEFAULT, height); + int buttonHeight = buttonSize.y / 2; + text.setBounds(0, 0, width - buttonSize.x, height); + up.setBounds(width - buttonSize.x, 0, buttonSize.x, buttonHeight); + down.setBounds(width - buttonSize.x, buttonHeight, buttonSize.x, + buttonHeight); + } + + protected void onKeyDown(Event event) { + int fieldName; + switch (event.keyCode) { + case SWT.ARROW_RIGHT: + // a right arrow or a valid separator navigates to the field on the + // right, with wraping + selectField((currentField + 1) % fieldCount); + break; + case SWT.ARROW_LEFT: + // navigate to the field on the left, with wrapping + int index = currentField - 1; + selectField(index < 0 ? fieldCount - 1 : index); + break; + case SWT.ARROW_UP: + case SWT.KEYPAD_ADD: + // set the value of the current field to value + 1, with wrapping + commitCurrentField(); + incrementField(+1); + break; + case SWT.ARROW_DOWN: + case SWT.KEYPAD_SUBTRACT: + // set the value of the current field to value - 1, with wrapping + commitCurrentField(); + incrementField(-1); + break; + case SWT.HOME: + // set the value of the current field to its minimum + fieldName = fieldNames[currentField]; + setTextField(fieldName, calendar.getActualMinimum(fieldName), true); + break; + case SWT.END: + // set the value of the current field to its maximum + fieldName = fieldNames[currentField]; + setTextField(fieldName, calendar.getActualMaximum(fieldName), true); + break; + case SWT.CR: + // TODO + // sendSelectionEvent(SWT.DefaultSelection); + break; + default: + switch (event.character) { + case '/': + case ':': + case '-': + case '.': + // a valid separator navigates to the field on the right, with + // wrapping + selectField((currentField + 1) % fieldCount); + break; + } + } + } + + protected void onFocusIn(Event event) { + selectField(currentField); + } + + protected void onFocusOut(Event event) { + commitCurrentField(); + } + + protected void onMouseClick(Event event) { + if (event.button != 1) { + return; + } + Point sel = text.getSelection(); + for (int i = 0; i < fieldCount; i++) { + if (fieldIndices[i].x <= sel.x && sel.x <= fieldIndices[i].y) { + selectField(i); + break; + } + } + } + + protected void onVerify(Event event) { + if (ignoreVerify) { + return; + } + event.doit = false; + int fieldName = fieldNames[currentField]; + int start = fieldIndices[currentField].x; + int end = fieldIndices[currentField].y; + int length = end - start; + String newText = event.text; + if (characterCount > 0) { + try { + Integer.parseInt(newText); + } catch (NumberFormatException ex) { + return; + } + String value = text.getText(start, end - 1); + int s = value.lastIndexOf(' '); + if (s != -1) { + value = value.substring(s + 1); + } + newText = "" + value + newText; + } + int newTextLength = newText.length(); + boolean first = characterCount == 0; + characterCount = (newTextLength < length) ? newTextLength : 0; + int max = calendar.getActualMaximum(fieldName); + int min = calendar.getActualMinimum(fieldName); + int newValue = unformattedIntValue(fieldName, newText, max); + if (newValue == -1) { + characterCount = 0; + return; + } + if (first && newValue == 0 && length > 1) { + setTextField(fieldName, newValue, false); + } else if (min <= newValue && newValue <= max) { + setTextField(fieldName, newValue, characterCount == 0); + } else { + if (newTextLength >= length) { + newText = newText.substring(newTextLength - length + 1); + newValue = unformattedIntValue(fieldName, newText, max); + if (newValue != -1) { + characterCount = length - 1; + if (min <= newValue && newValue <= max) { + setTextField(fieldName, newValue, characterCount == 0); + } + } + } + } + } + + private boolean isValidTime(int fieldName, int value) { + int min = calendar.getActualMinimum(fieldName); + int max = calendar.getActualMaximum(fieldName); + return value >= min && value <= max; + } + + String getFormattedString() { + int h = calendar.get(Calendar.HOUR_OF_DAY); + int m = calendar.get(Calendar.MINUTE); + int s = calendar.get(Calendar.SECOND); + + return String.format(formatStrings[fieldCount - 1], h, m, s); + } + + private void updateControl() { + if (text != null) { + String string = getFormattedString(); + ignoreVerify = true; + text.setText(string); + ignoreVerify = false; + } + redraw(); + } + + /** + * Sets the receiver's hours. + *

+ * Hours is an integer between 0 and 23. + *

+ * + * @param hours + * an integer between 0 and 23 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public void setHours(int hours) { + checkWidget(); + if (!isValidTime(Calendar.HOUR_OF_DAY, hours)) { + return; + } + calendar.set(Calendar.HOUR_OF_DAY, hours); + updateControl(); + } + + /** + * Sets the receiver's minutes. + *

+ * Minutes is an integer between 0 and 59. + *

+ * + * @param minutes + * an integer between 0 and 59 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public void setMinutes(int minutes) { + checkWidget(); + if (!isValidTime(Calendar.MINUTE, minutes)) { + return; + } + calendar.set(Calendar.MINUTE, minutes); + updateControl(); + } + + /** + * Sets the receiver's seconds. + *

+ * Seconds is an integer between 0 and 59. + *

+ * + * @param seconds + * an integer between 0 and 59 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public void setSeconds(int seconds) { + checkWidget(); + if (!isValidTime(Calendar.SECOND, seconds)) { + return; + } + calendar.set(Calendar.SECOND, seconds); + updateControl(); + } + + /** + * Sets the receiver's hours, minutes, and seconds in a single operation. + * + * @param hours + * an integer between 0 and 23 + * @param minutes + * an integer between 0 and 59 + * @param seconds + * an integer between 0 and 59 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ * + * @since 3.4 + */ + public void setTime(int hours, int minutes, int seconds) { + checkWidget(); + if (!isValidTime(Calendar.HOUR_OF_DAY, hours)) { + return; + } + if (!isValidTime(Calendar.MINUTE, minutes)) { + return; + } + if (!isValidTime(Calendar.SECOND, seconds)) { + return; + } + calendar.set(Calendar.HOUR_OF_DAY, hours); + calendar.set(Calendar.MINUTE, minutes); + calendar.set(Calendar.SECOND, seconds); + updateControl(); + } + + /** + * Returns the receiver's hours. + *

+ * Hours is an integer between 0 and 23. + *

+ * + * @return an integer between 0 and 23 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public int getHours() { + checkWidget(); + return calendar.get(Calendar.HOUR_OF_DAY); + } + + /** + * Returns the receiver's minutes. + *

+ * Minutes is an integer between 0 and 59. + *

+ * + * @return an integer between 0 and 59 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public int getMinutes() { + checkWidget(); + return calendar.get(Calendar.MINUTE); + } + + /** + * Returns the receiver's seconds. + *

+ * Seconds is an integer between 0 and 59. + *

+ * + * @return an integer between 0 and 59 + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + public int getSeconds() { + checkWidget(); + return calendar.get(Calendar.SECOND); + } +} diff --git a/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeRangeEntry.java b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeRangeEntry.java new file mode 100644 index 0000000000..82fe1938e3 --- /dev/null +++ b/cave/com.raytheon.viz.ui/src/com/raytheon/viz/ui/widgets/TimeRangeEntry.java @@ -0,0 +1,156 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.ui.widgets; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.viz.ui.widgets.DateTimeEntry.IUpdateListener; + +/** + * TimeRange entry widget with read-only text and button to pop up an editable + * dialog to enter the start and end date and time. End time must always be + * greater than or equal the start time. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 10, 2012            randerso     Initial creation
+ * 
+ * 
+ * + * @author randerso + * @version 1.0 + */ + +public class TimeRangeEntry extends Composite { + + private DateTimeEntry start; + + private DateTimeEntry end; + + public TimeRangeEntry(Composite parent, int style) { + super(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 0; + layout.marginWidth = 0; + layout.horizontalSpacing = 0; + if ((style & SWT.HORIZONTAL) != 0) { + layout.numColumns = 2; + } + setLayout(layout); + + start = new DateTimeEntry(this); + GridData layoutData = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + start.setLayoutData(layoutData); + + end = new DateTimeEntry(this); + layoutData = new GridData(SWT.FILL, SWT.DEFAULT, true, false); + end.setLayoutData(layoutData); + + start.addUpdateListener(new IUpdateListener() { + @Override + public void dateTimeUpdated(Date date) { + if (end.getDate().before(date)) { + end.setDate(date); + } + } + }); + + end.addUpdateListener(new IUpdateListener() { + @Override + public void dateTimeUpdated(Date date) { + if (date.before(start.getDate())) { + start.setDate(date); + } + } + }); + } + + /** + * Sets the date format string used to format the date/time strings for + * display + * + * @param dateFormat + * the date format string see {@link SimpleDateFormat} for more + * information. + */ + public void setDateFormat(String dateFormat) { + start.setDateFormat(dateFormat); + end.setDateFormat(dateFormat); + } + + /** + * Sets the time zone used to format the date/time strings for display + * + * @param tz + * the time zone + */ + public void setTimeZone(TimeZone tz) { + start.setTimeZone(tz); + end.setTimeZone(tz); + } + + /** + * Sets the contents of the receiver to the given time range + * + * @param timeRange + * the time range + */ + public void setTimeRange(TimeRange timeRange) { + this.start.setDate(timeRange.getStart()); + if (timeRange.getEnd().before(timeRange.getStart())) { + end.setDate(timeRange.getStart()); + } else { + end.setDate(timeRange.getEnd()); + } + } + + /** + * Get the time range + * + * @return the time range + */ + public TimeRange getTimeRange() { + Date startDate = start.getDate(); + Date endDate = end.getDate(); + + return new TimeRange(startDate, endDate); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + for (Control c : getChildren()) { + c.setEnabled(enabled); + } + } +}