/* JstringField.java This class defines an entry field that is capable of handling strings. It is also possible to restrict the characters which are accepted by this gui component. Furthermore, the maximum size of the string that can be entered into this JstringField can be preset. Created: 12 Jul 1996 Module By: Navin Manohar ----------------------------------------------------------------------- Ganymede Directory Management System Copyright (C) 1996-2012 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 java.rmi.RemoteException; /*------------------------------------------------------------------------------ class JstringField ------------------------------------------------------------------------------*/ /** * <p>This class defines an entry field that is capable of handling * strings. It is also possible to restrict the characters which are * accepted by this gui component. Furthermore, the maximum size of * the string that can be entered into this JstringField can be * preset.</p> */ public class JstringField extends JentryField { public static final boolean debug = false; public static int DEFAULT_COLS = 15; public static int DEFAULT_SIZE = 4096; // --- private int size = DEFAULT_SIZE; private String value = null; private String allowedChars = null; private String disallowedChars = null; private boolean processingCallback = false; private boolean replacingValue = false; private String replacementValue = null; /* -- */ /** Constructors ***/ /** * Base constructor for JstringField * * @param columns number of columns in the JstringField * @param is_editable true if this JstringField is editable */ public JstringField(int columns, int maxstrlen, boolean is_editable, boolean invisible, String allowed, String disallowed) { super(columns); if (maxstrlen <= 0) { throw new IllegalArgumentException("Invalid Parameter: maximum string size is negative or zero"); } size = maxstrlen; setEditable(is_editable); // will this JstringField be editable or not? if (allowed != null) { setAllowedChars(allowed); } if (disallowed != null) { setDisallowedChars(disallowed); } } /** * Constructor which uses default fonts,no parent, * default column size, and default foregound/background * colors. */ public JstringField() { this(JstringField.DEFAULT_COLS,JstringField.DEFAULT_SIZE, true, false, null, null); } /** * Simple constructor. */ public JstringField(int cols, boolean is_editable) { this(cols,JstringField.DEFAULT_SIZE, is_editable, false, null, null); } /** * Constructor that allows for the creation of a JstringField * that knows about its parent. * * @param cols number of colums in the JstringField * @param callback An interface for the container within which this * JstringField is typically contained. The JstringField will * call this interface to pass change notifications. */ public JstringField(int cols, int maxstrlen, boolean is_editable, boolean invisible, String allowed, String disallowed, JsetValueCallback callback) { this(cols,maxstrlen,is_editable,invisible,allowed,disallowed); setCallback(callback); } /************************************************************/ // JstringField methods /** * sets the JstringField to a specific value, without performing any * of the checks that are enforced on interactive text entry. * * @param str value to which the JstringField is set */ public void setText(String str) { if (debug) { System.out.println("JstringField: setText() in JstringField"); } boolean editable = isEditable(); setEditable(true); if (str == null) { if (debug) { System.out.println("JstringField: String is null."); } value = ""; super.setText(""); } else { // XXX verifyValue(str); if (debug) { System.out.println("JstringField: Calling super.setText(" + str + ")"); } try { super.loadingText = true; super.setText(str); } finally { super.loadingText = false; } value = str; } if (!editable) { setCaretPosition(0); // scroll the view to show the start of the string, not the end of the string } setEditable(editable); } /** * <p>Checks the entire string str for compliance with this field's * constraints.</p> * * <p>Throws an IllegalArgumentException if the provided string is * not acceptable.</p> */ private void verifyValue(String str) { if (str.length() > size) { throw new IllegalArgumentException("string too long"); } for (int i = 0; i < str.length(); i++) { if (!isAllowed(str.charAt(i))) { throw new IllegalArgumentException("invalid char in string (\"" + str + "\") : '" + str.charAt(i) + "'"); } } } /** * <p>Return the string contained in this field, whether it has been * validated in a callback or not.</p> */ public String getValue() { return getText(); } /** * <p>Returns the character located at position n in the * JstringField value</p> * * @param n position in the JstringField value from which to * retrieve character */ public char getCharAt(int n) { return this.getText().charAt(n); } /** * <p>Assigns a set of characters which are valid within the * JstringField</p> * * @param s each character in this string will be considered an * allowed character */ public void setAllowedChars(String s) { if (s != null) { this.allowedChars = s; } else { this.allowedChars = null; } } /** * <p>Assigns a set of characters which are invalid within the * JstringField</p> * * @param s each character in this string will be considered a * disallowed character */ public void setDisallowedChars(String s) { if (s!= null) { this.disallowedChars = s; } else { this.disallowedChars = null; } } /** * Returns the set of allowed characters as a String object */ public String getAllowedChars() { return this.allowedChars; } /** * Returns the set of disallowed characters as a String object */ public String getDisallowedChars() { return this.disallowedChars; } /** * Returns the maximum size of the string that can be placed in this * JstringField */ public int getMaxStringSize() { return this.size; } /** * Returns the current size of the contents of this gui field */ public int getLength() { String text = super.getText(); if (text == null) { return 0; } else { return text.length(); } } /** * <p>Determines whether a given character is valid or invalid for a * JstringField</p> * * <p>The JentryDocument object for this field will use this method * to allow or disallow the character ch from being added.</p> * * @param ch the character which is being tested for its validity */ public boolean isAllowed(char ch) { if (debug) { System.out.println("JstringField.isAllowed()"); } if (disallowedChars != null) { if (disallowedChars.indexOf(ch) != -1) { if (debug) { System.out.println("Disallowing char: " + ch + " because it is in string: " + disallowedChars); } return false; } } if (allowedChars != null) { if (allowedChars.indexOf(ch) == -1) { return false; } } return true; } /** * <p>sendCallback is called when focus is lost, or when we are otherwise * triggered. A true value will be returned if the value change was * approved and performed, or false if not. If the value did not change, * this method will also return false.</p> * * @return -1 on change rejected, 0 on no change required, 1 on * change approved */ public int sendCallback() { synchronized (this) { if (processingCallback) { return -1; } processingCallback = true; } try { String str; /* -- */ // if nothing in the JstringField has changed, // we don't need to worry about this event. str = getText(); if ((value != null && value.equals(str)) || (value == null && (str == null || str.equals("")))) { return 0; } /* we don't need to check the string for validity, since it was checked on a character by character basis on entry by our superclass. */ try { if (!allowCallback || my_parent.setValuePerformed(new JSetValueObject(this, str))) { // check to see whether the setValuePerformed() // callback asked us to do a canonicalization of the // str we submitted during its processing. // // If so, we need to be sure that we don't overwrite // the persistent value with the string that we // originally started with, but that we instead accept // and refresh with the replacement value that was set // by a call to substituteValueByCallBack() during the // execution of setValuePerformed(). if (replacingValue) { value = replacementValue; try { super.loadingText = true; super.setText(value == null ? "":value); } finally { super.loadingText = false; } } else { value = str; } return 1; } else { // revert try { // inhibit character filtering super.loadingText = true; super.setText(value == null ? "":value); } finally { super.loadingText = false; } return -1; } } catch (RemoteException re) { return -1; } } finally { processingCallback = false; replacementValue = null; replacingValue = false; } } /** * <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> */ public void substituteValueByCallBack(JsetValueCallback callback, String replacementValue) { if (callback != this.my_parent) { throw new IllegalStateException(); } this.replacingValue = true; this.replacementValue = replacementValue; } }