001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2002 Elmar Grom
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021:
022: package com.izforge.izpack.panels;
023:
024: import java.awt.Toolkit;
025: import java.awt.event.FocusEvent;
026: import java.awt.event.FocusListener;
027: import java.awt.event.KeyEvent;
028: import java.awt.event.KeyListener;
029: import java.util.Map;
030: import java.util.StringTokenizer;
031: import java.util.Vector;
032: import java.io.Serializable;
033:
034: import javax.swing.JComponent;
035: import javax.swing.JLabel;
036: import javax.swing.JTextField;
037: import javax.swing.event.CaretEvent;
038: import javax.swing.event.CaretListener;
039:
040: import org.apache.regexp.RE;
041:
042: import com.izforge.izpack.installer.InstallData;
043: import com.izforge.izpack.util.Debug;
044: import com.izforge.izpack.util.VariableSubstitutor;
045:
046: /*---------------------------------------------------------------------------*/
047: /**
048: * This class assists the user in entering serial numbers. <BR>
049: * <BR>
050: * Serial numbers, license number, CD keys and the like are often lenghty alpha-numerical numbers.
051: * In many cases they are devided into multiple parts by dash or point separators. Entering these in
052: * a single text field can be a frustrating experience for the user. This class provides a way of
053: * presenting the user with an assembly of input fields that are arranged in the same way as the
054: * key, with the separators already in place. Immideate testing for format compliance if performed
055: * ans soon as each field is completed. In addition, the cursor is automatically advanced to make
056: * entering numbers as painless as possible. <br>
057: * <br>
058: * <b>Formatting:</b>
059: *
060: * <ul>
061: * <li><code>N:X:Y </code>- numeric field, accepts digits only
062: * <li><code>H:X:Y </code>- hex field, accepts only hexadecimal digits
063: * <li><code>A:X:Y </code>- alpha field, accepts only letters, no digits
064: * <li><code>AN:X:Y</code>- alpha-numeric field, accepts digits and letters
065: * </ul>
066: * <b>Example:</b> <br>
067: * <br>
068: * <code>"N:4:4 - H:6:6 - AN:3:3 x A:5:5"</code><br>
069: * <br>
070: * This formatting string will produce a serial number field consisting of four separate input
071: * fields. The fisrt input field will accept four numeric digits, the second six hexa-decimal
072: * digits, the third three alpha-numeric digits and the fourth five letters. The first three input
073: * fields will be separated by '-' and the third and fourth by 'x'. The following snapshot was
074: * obtained with this setting: <br>
075: * <br>
076: * <img src="doc-files/RuleInputField-1.gif"/>
077: *
078: * @version 0.0.1 / 10/19/02
079: * @author Elmar Grom
080: */
081: /*---------------------------------------------------------------------------*/
082: public class RuleInputField extends JComponent implements KeyListener,
083: FocusListener, CaretListener, ProcessingClient {
084:
085: /**
086: *
087: */
088: private static final long serialVersionUID = 3832616275124958257L;
089:
090: /**
091: * Used to specify the retsult format. This constant specifies to return the contents of all
092: * fields concatenated into one long string, with separation between each component.
093: */
094: public static final int PLAIN_STRING = 1;
095:
096: /**
097: * Used to specify the retsult format. This constant specifies to return the contents of all
098: * fields together with all separators as specified in the field format concatenated into one
099: * long string. In this case the resulting string looks just like the user saw it during data
100: * entry
101: */
102: public static final int DISPLAY_FORMAT = 2;
103:
104: /**
105: * Used to specify the retsult format. This constant specifies to return the contents of all
106: * fields concatenated into one long string, with a special separator string inserted in between
107: * the individual components.
108: */
109: public static final int SPECIAL_SEPARATOR = 3;
110:
111: /**
112: * Used to specify the retsult format. This constant specifies to return the contents of all
113: * fields in a somehow modified way. How the content is modified depends on the operation
114: * performed by a encryption service class. The class must be provided at object instatiation.
115: */
116: public static final int ENCRYPTED = 4;
117:
118: /** Used internally to identify the default setting for the return format. */
119: private static int DEFAULT = DISPLAY_FORMAT;
120:
121: private Vector<Serializable> items = new Vector<Serializable>();
122:
123: /**
124: * This <code>Vector</code> holds a reference to each input field, in the order in which they
125: * appear on the screen.
126: */
127: private Vector inputFields = new Vector();
128:
129: private boolean hasParams = false;
130:
131: private Map<String, String> validatorParams;
132:
133: private RuleTextField activeField;
134:
135: private boolean backstep = false;
136:
137: private Toolkit toolkit;
138:
139: private String separator;
140:
141: private int resultFormat = DEFAULT;
142:
143: private InstallData idata = null;
144:
145: /**
146: * Holds an instance of the <code>Validator</code> if one was specified and available
147: */
148: private Validator validationService;
149:
150: /**
151: * Holds an instance of the <code>Processor</code> if one was specified and available
152: */
153: private Processor encryptionService;
154:
155: /*--------------------------------------------------------------------------*/
156: // javadoc inherited
157: public boolean hasParams() {
158: return hasParams;
159: }
160:
161: /*--------------------------------------------------------------------------*/
162: /**
163: * Constructs a rule input field.
164: *
165: * @param format a string that specifies the formatting and to a limited degree the behavior of
166: * this field.
167: * @param preset a string that specifies preset values for specific sub-fields.
168: * @param separator a string to be used for separating the contents of individual fields in the
169: * string returned by <code>getText()</code>
170: * @param validator A string that specifies a class to perform validation services. The string
171: * must completely identify the class, so that it can be instantiated. The class must implement
172: * the <code>RuleValidator</code> interface. If an attempt to instantiate this class fails, no
173: * validation will be performed.
174: * @param validatorParams A <code>java.util.Map</code> containing name/ value pairs, which
175: * will be forwarded to the validator.
176: * @param processor A string that specifies a class to perform processing services. The string
177: * must completely identify the class, so that it can be instantiated. The class must implement
178: * the <code>Processor</code> interface. If an attempt to instantiate this class fails, no
179: * processing will be performed. Instead, the text is returned in the default formatting.
180: * @param resultFormat specifies in which format the resulting text should be returned, wehn
181: * <code>getText()</code> is called. The following values are legal:<br>
182: * <ul>
183: * <li>PLAIN_STRING
184: * <li>DISPLAY_FORMAT
185: * <li>SPECIAL_SEPARATOR
186: * <li>ENCRYPTED
187: * </ul>
188: * @param toolkit needed to gain access to <code>beep()</code>
189: */
190: /*--------------------------------------------------------------------------*/
191: public RuleInputField(String format, String preset,
192: String separator, String validator,
193: Map<String, String> validatorParams, String processor,
194: int resultFormat, Toolkit toolkit, InstallData idata) {
195: this (format, preset, separator, validator, processor,
196: resultFormat, toolkit, idata);
197: this .validatorParams = validatorParams;
198: this .hasParams = true;
199: }
200:
201: /*--------------------------------------------------------------------------*/
202: /**
203: * Constructs a rule input field.
204: *
205: * @param format a string that specifies the formatting and to a limited degree the behavior of
206: * this field.
207: * @param preset a string that specifies preset values for specific sub-fields.
208: * @param separator a string to be used for separating the contents of individual fields in the
209: * string returned by <code>getText()</code>
210: * @param validator A string that specifies a class to perform validation services. The string
211: * must completely identify the class, so that it can be instantiated. The class must implement
212: * the <code>RuleValidator</code> interface. If an attempt to instantiate this class fails, no
213: * validation will be performed.
214: * @param processor A string that specifies a class to perform processing services. The string
215: * must completely identify the class, so that it can be instantiated. The class must implement
216: * the <code>Processor</code> interface. If an attempt to instantiate this class fails, no
217: * processing will be performed. Instead, the text is returned in the default formatting.
218: * @param resultFormat specifies in which format the resulting text should be returned, wehn
219: * <code>getText()</code> is called. The following values are legal:<br>
220: * <ul>
221: * <li>PLAIN_STRING
222: * <li>DISPLAY_FORMAT
223: * <li>SPECIAL_SEPARATOR
224: * <li>ENCRYPTED
225: * </ul>
226: * @param toolkit needed to gain access to <code>beep()</code>
227: */
228: /*--------------------------------------------------------------------------*/
229: public RuleInputField(String format, String preset,
230: String separator, String validator, String processor,
231: int resultFormat, Toolkit toolkit, InstallData idata) {
232: this .toolkit = toolkit;
233: this .separator = separator;
234: this .resultFormat = resultFormat;
235: this .idata = idata;
236:
237: com.izforge.izpack.gui.FlowLayout layout = new com.izforge.izpack.gui.FlowLayout();
238: layout.setAlignment(com.izforge.izpack.gui.FlowLayout.LEFT);
239: setLayout(layout);
240:
241: // ----------------------------------------------------
242: // attempt to create an instance of the Validator
243: // ----------------------------------------------------
244: try {
245: if (validator != null) {
246: validationService = (Validator) Class
247: .forName(validator).newInstance();
248: }
249: } catch (Throwable exception) {
250: validationService = null;
251: Debug.trace(exception);
252: }
253:
254: // ----------------------------------------------------
255: // attempt to create an instance of the Processor
256: // ----------------------------------------------------
257: try {
258: if (processor != null) {
259: encryptionService = (Processor) Class
260: .forName(processor).newInstance();
261: }
262: } catch (Throwable exception) {
263: encryptionService = null;
264: Debug.trace(exception);
265: }
266:
267: // ----------------------------------------------------
268: // create the fields and field separators
269: // ----------------------------------------------------
270: createItems(format);
271:
272: if ((preset != null) && (preset.length() > 0)) {
273: setFields(preset);
274: }
275:
276: // ----------------------------------------------------
277: // set the focus to the first field
278: // ----------------------------------------------------
279: activeField = (RuleTextField) inputFields.elementAt(0);
280: activeField.grabFocus();
281: }
282:
283: /*--------------------------------------------------------------------------*/
284: /**
285: * Returns the number of sub-fields composing this <code>RuleInputField</code>.
286: *
287: * @return the number of sub-fields
288: */
289: /*--------------------------------------------------------------------------*/
290: public int getNumFields() {
291: return (inputFields.size());
292: }
293:
294: /*--------------------------------------------------------------------------*/
295: /**
296: * Returns the contents of the field indicated by <code>index</code>.
297: *
298: * @param index the index of the sub-field from which the contents is requested.
299: *
300: * @return the contents of the indicated sub-field.
301: *
302: * @exception IndexOutOfBoundsException if the index is out of bounds.
303: */
304: /*--------------------------------------------------------------------------*/
305: public String getFieldContents(int index)
306: throws IndexOutOfBoundsException {
307: if ((index < 0) || (index > (inputFields.size() - 1))) {
308: throw (new IndexOutOfBoundsException());
309: }
310:
311: return (((JTextField) inputFields.elementAt(index)).getText());
312: }
313:
314: /*--------------------------------------------------------------------------*/
315: // javadoc inherited
316: public Map<String, String> getValidatorParams() {
317: return validatorParams;
318: }
319:
320: /*---------------------------------------------------------------------------*/
321: /**
322: * Returns the field contents, assembled acording to the encryption and separator rules.
323: *
324: * @return the field contents
325: */
326: /*--------------------------------------------------------------------------*/
327: public String getText() {
328: Object item;
329: StringBuffer buffer = new StringBuffer();
330: int size = inputFields.size();
331:
332: // ----------------------------------------------------
333: // have the encryption service class perfrom the task
334: // of assembling an output string. If we have no instance
335: // of this class available set the formatting
336: // instruction to the default setting.
337: // ----------------------------------------------------
338: if (resultFormat == ENCRYPTED) {
339: if (encryptionService != null) {
340: buffer.append(encryptionService.process(this ));
341: } else {
342: resultFormat = DEFAULT;
343: }
344: }
345:
346: // ----------------------------------------------------
347: // concatentate the field contents, with no separators
348: // in between.
349: // ----------------------------------------------------
350: else if (resultFormat == PLAIN_STRING) {
351: for (int i = 0; i < inputFields.size(); i++) {
352: buffer.append(((JTextField) inputFields.elementAt(i))
353: .getText());
354: }
355: }
356:
357: // ----------------------------------------------------
358: // concatenate the field contents and setarators, as
359: // specified for the display of the field.
360: // ----------------------------------------------------
361: else if (resultFormat == DISPLAY_FORMAT) {
362: for (int i = 0; i < items.size(); i++) {
363: item = items.elementAt(i);
364: if (item instanceof JTextField) {
365: buffer.append(((JTextField) item).getText());
366: } else {
367: buffer.append((String) item);
368: }
369: }
370: }
371:
372: // ----------------------------------------------------
373: // concatenate the field contents and insert the
374: // separator string in between.
375: // ----------------------------------------------------
376: else if (resultFormat == SPECIAL_SEPARATOR) {
377: for (int i = 0; i < size; i++) {
378: buffer.append(((JTextField) inputFields.elementAt(i))
379: .getText());
380:
381: if (i < (size - 1)) {
382: buffer.append(separator);
383: }
384: }
385: }
386:
387: return (buffer.toString());
388: }
389:
390: /*--------------------------------------------------------------------------*/
391: /**
392: * Creates the items that make up this field. Both separators and input fields are considered
393: * items. The items created are stored in <code>items</code>. In addition, all fields are
394: * stored in <code>inputFields</code>.
395: *
396: * @param format a string that specifies the layout of the input fields and separators.
397: */
398: /*--------------------------------------------------------------------------*/
399: /*
400: * $ @design
401: *
402: * I used a simple StringTokenizer to break the format string into individual tokens. The
403: * approach in building up the field is to consider each token a potential definition for an
404: * input field. Therefore I attempt to create an instance of FieldSpec from each token.
405: * FieldSpec analyzes the token and if it does not represent a valid specification for an input
406: * field throws an exception. If I catch an exception, I know the token does not represent a
407: * valid field specification. In this case I treat the token as a separator, even though this
408: * might not be what the user had intended. However, this approach allows me to implement robust
409: * behavior (no exception thrown) even though the user might have made a mistake in the
410: * definition. The mistake should become immediately obvious when testing the code, since a
411: * input field definition would show up as separator between two fields.
412: * --------------------------------------------------------------------------
413: */
414: private void createItems(String format) {
415: Object item;
416: JTextField field;
417: String token;
418: FieldSpec spec;
419: StringTokenizer tokenizer = new StringTokenizer(format);
420:
421: while (tokenizer.hasMoreTokens()) {
422: token = tokenizer.nextToken();
423: try {
424: spec = new FieldSpec(token);
425: field = new RuleTextField(spec.getColumns(), spec
426: .getEditLength(), spec.getType(), spec
427: .getUnlimitedEdit(), toolkit);
428:
429: // ------------------------------------------------
430: // if the previous item is also a field, insert a
431: // space as separator
432: // ------------------------------------------------
433: if (items.size() > 0) {
434: item = items.lastElement();
435:
436: if (item instanceof JTextField) {
437: items.add(" ");
438: }
439: }
440:
441: items.add(field);
442: inputFields.add(field);
443: field.addFocusListener(this );
444: field.addKeyListener(this );
445: field.addCaretListener(this );
446: }
447: // --------------------------------------------------
448: // if we were not successful creating an input field,
449: // the token must be a separator or the definition
450: // has an error. Simply insert it as separator,
451: // when testing the installer the error should become
452: // obvious to the developer.
453: // --------------------------------------------------
454: catch (Throwable exception) {
455: if (items.size() == 0) {
456: items.add(token);
457: } else {
458: item = items.lastElement();
459:
460: // ----------------------------------------------
461: // if the previous item is also a separator,
462: // simply concatenate the token with a space
463: // inserted in between, don't add it as new
464: // separator.
465: // ----------------------------------------------
466: if (item instanceof String) {
467: items.setElementAt(item + " " + token, (items
468: .size() - 1));
469: } else {
470: items.add(token);
471: }
472: }
473: }
474: }
475:
476: // ----------------------------------------------------
477: // add the fields and separators to the component
478: // ----------------------------------------------------
479: for (int i = 0; i < items.size(); i++) {
480: item = items.elementAt(i);
481:
482: if (item instanceof String) {
483: add(new JLabel((String) item));
484: } else {
485: add((JTextField) item);
486: }
487: }
488: }
489:
490: /*--------------------------------------------------------------------------*/
491: /**
492: * Sets each field to a pre-defined value.
493: *
494: * @param data a <code>String</code> containing the preset values for each field. The format
495: * of the string is as follows: The content for the individuals fields must be separated by
496: * whitespace. Each data block is preceeded by the index of the field to set (counting starts at
497: * 0) followed by a colon ':'and after that the actual data for the field.
498: */
499: /*--------------------------------------------------------------------------*/
500: private void setFields(String data) {
501: StringTokenizer tokenizer = new StringTokenizer(data);
502: String token;
503: String indexString;
504: int index;
505: boolean process = false;
506: String[] vals = null;
507: int i = 0;
508:
509: vals = new String[tokenizer.countTokens()];
510: while (tokenizer.hasMoreTokens()) {
511: token = tokenizer.nextToken();
512: indexString = token.substring(0, token.indexOf(':'));
513:
514: try {
515: index = Integer.parseInt(indexString);
516: if (index < inputFields.size()) {
517: String val = token.substring(
518: (token.indexOf(':') + 1), token.length());
519: String className = "";
520: if (val.indexOf(":") > -1) {
521: className = val.substring(val.indexOf(":") + 1);
522: val = val.substring(0, val.indexOf(":"));
523: }
524:
525: if (!"".equals(className) && !process) {
526: process = true;
527: }
528: VariableSubstitutor vs = new VariableSubstitutor(
529: idata.getVariables());
530: val = vs.substitute(val, null);
531: vals[i] = val;
532: i++;
533: ((JTextField) inputFields.elementAt(index))
534: .setText(val);
535: }
536: } catch (Throwable exception) {
537: exception.printStackTrace();
538: }
539: }
540:
541: if (process) {
542: tokenizer = new StringTokenizer(data);
543: while (tokenizer.hasMoreTokens()) {
544: token = tokenizer.nextToken();
545: indexString = token.substring(0, token.indexOf(':'));
546:
547: try {
548: index = Integer.parseInt(indexString);
549: if (index < inputFields.size()) {
550: String val = token.substring((token
551: .indexOf(':') + 1), token.length());
552: String className = "";
553: String presult = "";
554: if (val.indexOf(":") > -1) {
555: className = val
556: .substring(val.indexOf(":") + 1);
557: val = val.substring(0, val.indexOf(":"));
558: }
559:
560: if (!"".equals(className)) {
561: Processor p = (Processor) Class.forName(
562: className).newInstance();
563: presult = p.process(this );
564: }
565: String[] td = new RE("\\*").split(presult);
566: ((JTextField) inputFields.elementAt(index))
567: .setText(td[index]);
568: }
569: } catch (Throwable exception) {
570: }
571: }
572: }
573: }
574:
575: /*--------------------------------------------------------------------------*/
576: /**
577: * This method validates the field content. Validating is performed through a user supplied
578: * service class that provides the validation rules.
579: *
580: * @return <code>true</code> if the validation passes or no implementation of a validation
581: * rule exists. Otherwise <code>false</code> is returned.
582: */
583: /*--------------------------------------------------------------------------*/
584: public boolean validateContents() {
585: if (validationService != null) {
586: return (validationService.validate(this ));
587: } else {
588: return (true);
589: }
590: }
591:
592: /*---------------------------------------------------------------------------*
593: Implementation for KeyListener
594: *---------------------------------------------------------------------------*/
595:
596: /*--------------------------------------------------------------------------*/
597: /**
598: * This method is invoked when a key has been typed. The event occurs when a key press is
599: * followed by a key release.
600: *
601: * @param event the key event forwarded by the system.
602: */
603: /*--------------------------------------------------------------------------*/
604: public void keyTyped(KeyEvent event) {
605: }
606:
607: /*--------------------------------------------------------------------------*/
608: /**
609: * This method is invoked when a key has been pressed. This method verifies the condition of the
610: * input field in focus. Once the column count in the field has reached the specified maximum,
611: * the rule specified for the field in question is invoked. In case the test result is positive,
612: * focus is set to the next field. If hte test result is negative, the field content is marked
613: * and the caret set to the start of the field.
614: *
615: * @param event the key event forwarded by the system.
616: */
617: /*--------------------------------------------------------------------------*/
618: public void keyPressed(KeyEvent event) {
619: if (event.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
620: int caretPosition = activeField.getCaretPosition();
621:
622: if (caretPosition == 0) {
623: int activeIndex = inputFields.indexOf(activeField);
624:
625: if (activeIndex > 0) {
626: activeIndex--;
627: backstep = true;
628: activeField = (RuleTextField) inputFields
629: .elementAt(activeIndex);
630: activeField.grabFocus();
631: }
632: }
633: }
634: }
635:
636: /*--------------------------------------------------------------------------*/
637: /**
638: * This method is invoked when a key has been released.
639: *
640: * @param event the key event forwarded by the system.
641: */
642: /*--------------------------------------------------------------------------*/
643: public void keyReleased(KeyEvent event) {
644: }
645:
646: /*---------------------------------------------------------------------------*
647: Implementation for FocusListener
648: *---------------------------------------------------------------------------*/
649:
650: /*--------------------------------------------------------------------------*/
651: /**
652: * Invoked when a component gains the keyboard focus.
653: *
654: * @param event the focus event forwardes by the sytem.
655: */
656: /*--------------------------------------------------------------------------*/
657: /*
658: * $ @design <- keep this tag in place and don't write on this line!
659: *
660: * Enter design related documentation here.
661: * --------------------------------------------------------------------------
662: */
663: public void focusGained(FocusEvent event) {
664: activeField = (RuleTextField) event.getSource();
665:
666: if (backstep) {
667: activeField
668: .setCaretPosition(activeField.getText().length());
669: backstep = false;
670: } else {
671: activeField.selectAll();
672: }
673: }
674:
675: /*--------------------------------------------------------------------------*/
676: /**
677: * Invoked when a component loses the keyboard focus. This method does nothing, we are only
678: * interested in 'focus gained' events.
679: *
680: * @param event the focus event forwardes by the sytem.
681: */
682: /*--------------------------------------------------------------------------*/
683: public void focusLost(FocusEvent event) {
684: }
685:
686: /*---------------------------------------------------------------------------*
687: Implementation for CaretListener
688: *---------------------------------------------------------------------------*/
689:
690: /*--------------------------------------------------------------------------*/
691: /**
692: * Called when the caret position is updated.
693: *
694: * @param event the caret event received from the text field
695: */
696: /*--------------------------------------------------------------------------*/
697: public void caretUpdate(CaretEvent event) {
698: if (activeField != null) {
699: String text = activeField.getText();
700: int fieldSize = activeField.getEditLength();
701: int caretPosition = activeField.getCaretPosition();
702: int selection = activeField.getSelectionEnd()
703: - activeField.getSelectionStart();
704:
705: if ((!inputFields.lastElement().equals(activeField))
706: && (!activeField.unlimitedEdit())) {
707: if ((text.length() == fieldSize) && (selection == 0)
708: && (caretPosition == fieldSize) && !backstep) {
709: activeField.transferFocus();
710: }
711: }
712: }
713: }
714:
715: // ----------------------------------------------------------------------------
716: //
717: // ----------------------------------------------------------------------------
718: private static class FieldSpec {
719:
720: private int MIN_TOKENS = 2;
721:
722: private int MAX_TOKENS = 3;
723:
724: private int type;
725:
726: private int columns;
727:
728: private int editLength;
729:
730: private boolean unlimitedEdit = false;
731:
732: public FieldSpec(String spec) throws Exception {
733: StringTokenizer tokenizer = new StringTokenizer(spec, ":");
734:
735: if ((tokenizer.countTokens() >= MIN_TOKENS)
736: && (tokenizer.countTokens() <= MAX_TOKENS)) {
737: String token = tokenizer.nextToken().toUpperCase();
738: // ------------------------------------------------
739: // test the first token for a valid type identifier
740: // if it's valid assign the token to the type.
741: // ------------------------------------------------
742: if ("N".equals(token)) {
743: type = RuleTextField.N;
744: } else if ("H".equals(token)) {
745: type = RuleTextField.H;
746: } else if ("A".equals(token)) {
747: type = RuleTextField.A;
748: } else if ("O".equals(token)) {
749: type = RuleTextField.O;
750: } else if ("AN".equals(token)) {
751: type = RuleTextField.AN;
752: } else {
753: throw (new Exception());
754: }
755:
756: // ------------------------------------------------
757: // test for a valid integer to define the size
758: // of the field and assing to columns.
759: // ------------------------------------------------
760: try {
761: token = tokenizer.nextToken();
762: columns = Integer.parseInt(token);
763: } catch (Throwable exception) {
764: throw (new Exception());
765: }
766:
767: // ------------------------------------------------
768: // test for a valid integer to define the edit
769: // length and assign to editLength. If this fails
770: // test for identifier for unlimited edit length.
771: // If this works, set unlimitedEdit to true.
772: // ------------------------------------------------
773: try {
774: token = tokenizer.nextToken().toUpperCase();
775: editLength = Integer.parseInt(token);
776: } catch (Throwable exception) {
777: if ("U".equals(token)) {
778: unlimitedEdit = true;
779: } else {
780: throw (new Exception());
781: }
782: }
783:
784: } else {
785: throw (new Exception());
786: }
787: }
788:
789: public int getColumns() {
790: return (columns);
791: }
792:
793: public int getEditLength() {
794: return (editLength);
795: }
796:
797: public int getType() {
798: return (type);
799: }
800:
801: public boolean getUnlimitedEdit() {
802: return (unlimitedEdit);
803: }
804:
805: }
806: // ----------------------------------------------------------------------------
807:
808: }
809: /*---------------------------------------------------------------------------*/
|