/* JnumberField.java Created: 12 Jul 1996 Module By: Navin Manohar, Jonathan Abbey, Michael Mulvaney ----------------------------------------------------------------------- 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; import arlut.csd.Util.TranslationService; /*------------------------------------------------------------------------------ class JnumberField ------------------------------------------------------------------------------*/ /** * This class defines an entry field that is capable of handling * integers. The maximum and minimum bounds for the range of * integers that can be entered into this JnumberField can also * be preset. */ public class JnumberField extends JentryField { /** * TranslationService object for handling string localization in the * Ganymede client. */ static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.JDataComponent.JnumberField"); public static int DEFAULT_COLS = 20; public static String allowedChars = "0123456789-"; private Integer oldvalue; private boolean limited = false; private boolean processingCallback = false; private int maxSize; private int minSize; private boolean replacingValue = false; private Integer replacementValue = null; /////////////////// // Constructors // /////////////////// /** * Base constructor for JnumberField * * @param columns number of colums in the JnumberField * @param iseditable true if this JnumberField 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 JnumberField(int columns, boolean iseditable, boolean islimited, int minsize, int maxsize) { super(columns); if (islimited) { limited = true; maxSize = maxsize; minSize = minsize; } setEditable(iseditable); // will this JnumberField be editable or not? } /** * Constructor which uses takes a number of columns, and everything * else default. */ public JnumberField(int width) { this(width, true, false, 0,Integer.MAX_VALUE); } /** * Constructor which uses default everything. */ public JnumberField() { this(JnumberField.DEFAULT_COLS); } /** * Constructor that allows for the creation of a JnumberField * that knows about its parent and can invoke a callback method. * * @param columns number of colums in the JnumberField * @param iseditable true if this JnumberField 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 JnumberField is contained * (This container will implement an interface that will utilize the * data contained within this JnumberField.) */ public JnumberField(int columns, boolean iseditable, boolean islimited, int minsize, int 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 numerical digit */ public boolean isAllowed(char c) { if (allowedChars.indexOf(c) == -1) { if (debug) { System.err.println("JnumberField.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 JnumberField as an Integer object */ public Integer getValue() throws NumberFormatException { String str = getText(); if (str == null || str.equals("")) { return null; } return Integer.valueOf(str); } /** * <p>Sets the value of this JnumberField 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(int num) { setValue(Integer.valueOf(num)); } /** * <p>Sets the value of this JnumberField using an Integer * 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 Integer object to use */ public void setValue(Integer num) { if (limited) { if (num != null) { if (num.intValue() > maxSize || num.intValue() < minSize) { if (debug) { System.err.println("Invalid Parameter: number out of range"); } return; } } } // remember the value that is being set. oldvalue = num; // and set the text field if (num != null) { setText(num.toString()); } else { setText(""); } } /** * <p>Sets the limited/non-limited status of this JnumberField 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(int 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(int n) { limited = true; minSize = n; } /** * @return True if there is a bound on the range of values that can * be entered into this JnumberField */ public boolean isLimited() { return limited; } /** * @return The maximum value in the range of valid values for this * JnumberField */ public int getMaxValue() { return maxSize; } /** * @return The minimum value in the range of valid values for this * JnumberField */ public int getMinValue() { return minSize; } /** * <p>overrides JentryField.sendCallback().</p> * * <p>This is called when the number 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 */ public int sendCallback() { boolean success = false; /* -- */ synchronized (this) { if (processingCallback) { return -1; } processingCallback = true; } try { Integer currentValue; try { currentValue = getValue(); } catch (NumberFormatException ex) { // ""{0}" is not a valid number." reportError(ts.l("sendCallback.not_valid", getText())); // revert the text field setValue(oldvalue); return -1; } if ((currentValue == null && oldvalue == null) || (oldvalue != null && oldvalue.equals(currentValue))) { if (debug) { System.err.println("The field was not changed."); } return 0; } // check to see if it's in bounds, if we have bounds set. if (limited) { int value = currentValue.intValue(); if ((value > maxSize) || (value < minSize)) { // nope, revert. // "{0}" must be between {1,num,#} and {2,num,#}. reportError(ts.l("sendCallback.out_of_range", getText(), Integer.valueOf(minSize), Integer.valueOf(maxSize))); // revert setValue(oldvalue); return -1; } } // now, tell somebody, if we need to. if (allowCallback) { // Do a callback if (debug) { System.err.println("Sending callback"); } success = false; try { success = my_parent.setValuePerformed(new JSetValueObject(this,currentValue)); } catch (java.rmi.RemoteException re) { // success will still be false, that's good enough for us. } if (!success) { // revert setValue(oldvalue); return -1; } else { // 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 { oldvalue = currentValue; } return 1; } } else { // no one to say no. Odd, guess nobody cares.. remember our // value anyway. oldvalue = currentValue; 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) { if (debug) { System.err.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 Integer that the callback wishes to * have us rewrite ourselves with */ public void substituteValueByCallBack(JsetValueCallback callback, Integer replacementValue) { if (callback != this.my_parent) { throw new IllegalStateException(); } this.replacingValue = true; this.replacementValue = replacementValue; } }