/* JfloatField.java Created: 29 October 1999 Module By: Navin Manohar, Jonathan Abbey, Michael Mulvaney, John Knutson ----------------------------------------------------------------------- Ganymede Directory Management System Copyright (C) 1996-2013 The University of Texas at Austin Ganymede is a registered trademark of The University of Texas at Austin Contact information Author Email: ganymede_author@arlut.utexas.edu Email mailing list: ganymede@arlut.utexas.edu US Mail: Computer Science Division Applied Research Laboratories The University of Texas at Austin PO Box 8029, Austin TX 78713-8029 Telephone: (512) 835-3200 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package arlut.csd.JDataComponent; /*----------------------------------------------------------------------------- class JfloatField -----------------------------------------------------------------------------*/ /** * This class defines a GUI field component that is capable of * handling Java doubles. The maximum and minimum bounds for the * range of doubles that can be entered into this JfloatField can also * be preset. */ public class JfloatField extends JentryField { public static int DEFAULT_COLS = 20; public static String allowedChars = "0123456789-."; private Double storedValue; private boolean limited = false; private boolean processingCallback = false; private double maxSize; private double minSize; private boolean replacingValue = false; private Double replacementValue = null; /////////////////// // Constructors // /////////////////// /** * Base constructor for JfloatField * * @param columns number of columns in the JfloatField * @param iseditable true if this JfloatField is editable * @param islimited true if there is a restriction on the range of values * @param minsize the minimum limit on the range of values * @param maxsize the maximum limit on the range of values */ public JfloatField(int columns, boolean iseditable, boolean islimited, double minsize, double maxsize) { super(columns); if (islimited) { limited = true; maxSize = maxsize; minSize = minsize; } setEditable(iseditable); // will this JfloatField be editable or not? } /** * Constructor which uses takes a number of columns, and everything * else default. */ public JfloatField(int width) { this(width, true, false, Double.MIN_VALUE,Double.MAX_VALUE); } /** * Constructor which uses default everything. */ public JfloatField() { this(JfloatField.DEFAULT_COLS); } /** * Constructor that allows for the creation of a JfloatField * that knows about its parent and can invoke a callback method. * * @param columns number of columns in the JfloatField * @param iseditable true if this JfloatField is editable * @param islimited true if there is a restriction on the range of values * @param minsize the minimum limit on the range of values * @param maxsize the maximum limit on the range of values * @param parent the container within which this JfloatField is contained * (This container will implement an interface that will utilize the * data contained within this JfloatField.) */ public JfloatField(int columns, boolean iseditable, boolean islimited, double minsize, double maxsize, JsetValueCallback parent) { this(columns,iseditable,islimited,minsize,maxsize); setCallback(parent); } /////////////////// // Class Methods // /////////////////// /** * @param c the character to check * @return true if c is a valid character in a float field */ public boolean isAllowed(char c) { if (allowedChars.indexOf(c) == -1) { if (debug) { System.err.println("JfloatField.isAllowed(): ruling NO WAY on char '" + c + "'"); } return false; } return true; } /** * <p>If this field is empty, will return null. If this field is not * empty and has a non-numeric string, will throw a * NumberFormatException.</p> * * @return The value of this JfloatField as a Double object */ public Double getValue() throws NumberFormatException { String str = getText(); if (str == null || str.equals("")) { return null; } return new Double(str); } /** * <p>Sets the value of this JfloatField to num</p> * * <p>This method does not trigger a callback to our container.. we * only callback as a result of loss-of-focus brought on by the * user.</p> * * @param num the number to use */ public void setValue(double num) { setValue(new Double(num)); } /** * <p>Sets the value of this JfloatField using an Double object.</p> * * <p>This method does not trigger a callback to our container.. we * only callback as a result of loss-of-focus brought on by the * user.</p> * * @param num the Double object to use */ public void setValue(Double num) { if (limited) { if (num != null) { if (num.doubleValue() > maxSize || num.doubleValue() < minSize) { System.out.println("Invalid Parameter: float out of range"); return; } } } // remember the value that is being set. storedValue = num; // and set the text field if (num != null) { setText(num.toString()); } else { setText(""); } } /** * <p>Sets the limited/non-limited status of this JfloatField If * setLimited is given a true value as a parameter, then certain * bounds will be imposed on the range of possible values.</p> * * @param bool true if a limit is to be set on the range of values */ public void setLimited(boolean bool) { limited = bool; } /** * <p>Sets the maximum value in the range of possible values.</p> * * @param n the number to use when setting the maximum value */ public void setMaxValue(double n) { limited = true; maxSize = n; } /** * <p>Sets the minimum value in the range of possible values.</p> * * @param n the number to use when setting the minimum value */ public void setMinValue(double n) { limited = true; minSize = n; } /** * @return True if there is a bound on the range of values that can * be entered into this JfloatField */ public boolean isLimited() { return limited; } /** * @return The maximum value in the range of valid values for this * JfloatField */ public double getMaxValue() { return maxSize; } /** * @return The minimum value in the range of valid values for this * JfloatField */ public double getMinValue() { return minSize; } /** * <p>overrides JentryField.sendCallback().</p> * * <p>This is called when the float field loses focus.</p> * * <p>sendCallback is called when focus is lost, or when we are * otherwise triggered.</p> * * @return -1 on change rejected, 0 on no change required, 1 on change approved */ @Override public int sendCallback() { synchronized (this) { if (processingCallback) { return -1; } processingCallback = true; } try { Double currentValue; try { currentValue = getValue(); } catch (NumberFormatException ex) { reportError(getText() + " is not a properly formatted floating point number."); // revert the text field setValue(storedValue); return -1; } if ((currentValue == null && storedValue == null) || (storedValue != null && storedValue.equals(currentValue))) { if (debug) { System.out.println("The field was not changed."); } return 0; } // check to see if it's in bounds, if we have bounds set. if (limited) { double value = currentValue.doubleValue(); if ((value > maxSize) || (value < minSize)) { // nope, revert. reportError(getText() + " must be between " + minSize + " and " + maxSize + "."); setValue(storedValue); return -1; } } // now, tell somebody, if we need to. try { if (!allowCallback || my_parent.setValuePerformed(new JSetValueObject(this,currentValue))) { // good to go. We've already got the text set in the text // field, the user did that for us. Remember the value of // it, so we can revert if we need to later. if (replacingValue) { setValue(replacementValue); } else { storedValue = currentValue; } return 1; } else { setValue(storedValue); return -1; } } catch (java.rmi.RemoteException re) { return -1; } } finally { processingCallback = false; replacingValue = false; replacementValue = null; } } /** * <p>This private helper method relays a descriptive error message * to our callback interface.</p> * * @param errorString A descriptive error message that will be * passed to our callback in a {@link * arlut.csd.JDataComponent.JErrorValueObject JErrorValueObject}. */ private void reportError(String errorString) { if (allowCallback) { try { my_parent.setValuePerformed(new JErrorValueObject(this, errorString)); } catch (java.rmi.RemoteException rx) { System.out.println("Could not send an error callback."); } } } /** * <p>This method is intended to be called if the * setValuePerformed() callback that we call out to decides that it * wants to substitute a replacement value for the value that we * asked to have validated.</p> * * <p>This is used to allow the server to reformat/canonicalize data * that we passed to it.</p> * * @param callback The JsetValueCallback that is ordering us to * translate the value we sent to the callback * @param replacementValue The Double that the callback wishes to * have us rewrite ourselves with */ public void substituteValueByCallBack(JsetValueCallback callback, Double replacementValue) { if (callback != this.my_parent) { throw new IllegalStateException(); } this.replacingValue = true; this.replacementValue = replacementValue; } }