/******************************************************************************* * Copyright 2013 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.common.ui.widgets; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.DragDetectListener; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.GestureListener; import org.eclipse.swt.events.HelpListener; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SegmentListener; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.events.TouchListener; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; /** * A text field that accepts only numeric input. * <p/> * The field can be configured to accept decimal or integer values, and * optionally restrict values to non-negatives. * <p/> * <em>Important</em>: This class extends {@link Composite} in order to be * consistent with the SWT class hierarchy. However, it is not intended to have * child elements. Adding children to this widget is considered programmer error * and may result in undesired behaviour. * * @author James Navin (james.navin@ga.gov.au) * */ public class NumericTextField extends Composite { private final boolean decimal; private final boolean negative; private Number maxValue; private Number minValue; private final Text textField; /** * Create a new numeric text field with the given parent and style. * <p/> * The created field will support decimals and allow negative values. * * @param parent * The parent to create the field in * @param style * The style to apply to the field */ public NumericTextField(Composite parent, int style) { this(parent, style, true, true); } /** * Create a new numeric text field that optionally allows decimal and/or * negative values * * @param parent * The parent to create the field in * @param style * The style to apply to the field * @param allowDecimals * Whether decimal values should be allowed * @param allowNegative * Whether negative values should be allowed */ public NumericTextField(Composite parent, int style, boolean allowDecimals, boolean allowNegative) { super(parent, SWT.NONE); setLayout(new FillLayout()); this.decimal = allowDecimals; this.negative = allowNegative; textField = new Text(this, style); textField.addVerifyListener(new VerifyListener() { @SuppressWarnings("nls") @Override public void verifyText(VerifyEvent e) { final String oldText = textField.getText(); String newText = oldText.substring(0, e.start) + e.text + oldText.substring(e.end); // Allow empty fields if (newText == null || newText.isEmpty()) { e.doit = true; return; } // Don't want negatives if not allowed if (newText.startsWith("-") && !negative) { e.doit = false; return; } // Don't want leading/trailing spaces if (!newText.equals(newText.trim())) { e.doit = false; return; } Number n = toNumber(newText); if (n == null) { e.doit = false; return; } // Value cannot be negative if negative not allowed if (n.doubleValue() < 0 && !negative) { e.doit = false; return; } // Value must be inside optional [min, max] range if ((minValue != null && n.doubleValue() < minValue.doubleValue()) || (maxValue != null && n.doubleValue() > maxValue.doubleValue())) { e.doit = false; return; } } }); } /** * Set the maximum value this field can accept */ public void setMaxValue(Number value) { maxValue = value; } /** * Set the minimum value this field can accept */ public void setMinValue(Number value) { minValue = value; } /** * Return the current value of this numeric field, or <code>null</code> if * the field is empty or non-numeric. * * @return The current value of this field, or <code>null</code> if the * field is empty or non-numeric. */ public Number getNumber() { return toNumber(getText()); } @SuppressWarnings("nls") private Number toNumber(String text) { Number result = null; if (decimal) { // Handle the edge cases first if (text.equals(".")) { result = Double.valueOf(0.0); } else if (text.equals("-")) { result = Double.valueOf(-0); } else if (text.equals("-.")) { result = Double.valueOf(-0.0); } else { try { result = Double.parseDouble(text); } catch (NumberFormatException e) { // Do nothing } } } else { if (text.equals("-")) { result = Long.valueOf(-0); } else { try { result = Long.parseLong(text); } catch (NumberFormatException e) { // Do nothing } } } return result; } @SuppressWarnings("nls") public void setNumber(Number n) { if (n == null) { textField.setText(""); } else if (decimal) { textField.setText("" + n.doubleValue()); } else { textField.setText("" + n.longValue()); } } /** * Return the current text value of this field, exactly as it appears in the * field. * * @return Return the current text value of this field, exactly as it * appears in the field. */ public String getText() { return textField.getText(); } /** * Add a modify listener to this field to listen for changes in its value * * @param listener * The listener to add */ public void addModifyListener(ModifyListener listener) { textField.addModifyListener(listener); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); textField.setEnabled(enabled); } /** * Set the editable state * * @param editable */ public void setEditable(boolean editable) { textField.setEditable(editable); } /** * @return The editable state */ public boolean getEditable() { return textField.getEditable(); } @Override public void setVisible(boolean visible) { super.setVisible(visible); textField.setVisible(visible); } @Override public void addControlListener(ControlListener listener) { textField.addControlListener(listener); } @Override public void addDragDetectListener(DragDetectListener listener) { textField.addDragDetectListener(listener); } @Override public void addListener(int eventType, Listener listener) { textField.addListener(eventType, listener); } @Override public void addFocusListener(FocusListener listener) { textField.addFocusListener(listener); } @Override public void addDisposeListener(DisposeListener listener) { textField.addDisposeListener(listener); } @Override public void addGestureListener(GestureListener listener) { textField.addGestureListener(listener); } @Override public void addHelpListener(HelpListener listener) { textField.addHelpListener(listener); } @Override public void addKeyListener(KeyListener listener) { textField.addKeyListener(listener); } @Override public void addMenuDetectListener(MenuDetectListener listener) { textField.addMenuDetectListener(listener); } public void addSegmentListener(SegmentListener listener) { textField.addSegmentListener(listener); } @Override public void addMouseListener(MouseListener listener) { textField.addMouseListener(listener); } public void addSelectionListener(SelectionListener listener) { textField.addSelectionListener(listener); } @Override public void addMouseTrackListener(MouseTrackListener listener) { textField.addMouseTrackListener(listener); } @Override public void addMouseMoveListener(MouseMoveListener listener) { textField.addMouseMoveListener(listener); } @Override public void addMouseWheelListener(MouseWheelListener listener) { textField.addMouseWheelListener(listener); } @Override public void addPaintListener(PaintListener listener) { textField.addPaintListener(listener); } @Override public void addTouchListener(TouchListener listener) { textField.addTouchListener(listener); } @Override public void addTraverseListener(TraverseListener listener) { textField.addTraverseListener(listener); } @Override public void removeListener(int eventType, Listener listener) { textField.removeListener(eventType, listener); } @Override public void removeDisposeListener(DisposeListener listener) { textField.removeDisposeListener(listener); } public void removeModifyListener(ModifyListener listener) { textField.removeModifyListener(listener); } public void removeSegmentListener(SegmentListener listener) { textField.removeSegmentListener(listener); } public void removeSelectionListener(SelectionListener listener) { textField.removeSelectionListener(listener); } @Override public void removeControlListener(ControlListener listener) { textField.removeControlListener(listener); } @Override public void removeDragDetectListener(DragDetectListener listener) { textField.removeDragDetectListener(listener); } @Override public void removeFocusListener(FocusListener listener) { textField.removeFocusListener(listener); } @Override public void removeGestureListener(GestureListener listener) { textField.removeGestureListener(listener); } @Override public void removeHelpListener(HelpListener listener) { textField.removeHelpListener(listener); } @Override public void removeKeyListener(KeyListener listener) { textField.removeKeyListener(listener); } @Override public void removeMenuDetectListener(MenuDetectListener listener) { textField.removeMenuDetectListener(listener); } @Override public void removeMouseTrackListener(MouseTrackListener listener) { textField.removeMouseTrackListener(listener); } @Override public void removeMouseListener(MouseListener listener) { textField.removeMouseListener(listener); } @Override public void removeMouseMoveListener(MouseMoveListener listener) { textField.removeMouseMoveListener(listener); } @Override public void removeMouseWheelListener(MouseWheelListener listener) { textField.removeMouseWheelListener(listener); } @Override public void removePaintListener(PaintListener listener) { textField.removePaintListener(listener); } @Override public void removeTouchListener(TouchListener listener) { textField.removeTouchListener(listener); } @Override public void removeTraverseListener(TraverseListener listener) { textField.removeTraverseListener(listener); } }