Statistics
| Revision:

root / import / ext3D / trunk / install-extension3d / IzPack / src / lib / com / izforge / izpack / panels / RuleInputField.java @ 15280

History | View | Annotate | Download (33 KB)

1
/*
2
 * $Id: RuleInputField.java,v 1.1 2006/06/14 07:29:07 cesar Exp $
3
 * Copyright (C) 2002 Elmar Grom
4
 *
5
 * File :               RuleInputField.java
6
 * Description :        A Java component that serves as a serial number
7
 *                      input field with limited format verification.
8
 * Author's email :     elmar@grom.net
9
 * Author's Website :   http://www.izforge.com
10
 *
11
 * This program is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU General Public License
13
 * as published by the Free Software Foundation; either version 2
14
 * of the License, or any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, write to the Free Software
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24
 */
25

    
26
package   com.izforge.izpack.panels;
27

    
28
import java.awt.Toolkit;
29
import java.awt.event.FocusEvent;
30
import java.awt.event.FocusListener;
31
import java.awt.event.KeyEvent;
32
import java.awt.event.KeyListener;
33
import java.util.StringTokenizer;
34
import java.util.Vector;
35
import java.util.Map;
36

    
37
import javax.swing.JComponent;
38
import javax.swing.JLabel;
39
import javax.swing.JTextField;
40
import javax.swing.event.CaretEvent;
41
import javax.swing.event.CaretListener;
42

    
43
import org.apache.regexp.RE;
44
  
45
/*---------------------------------------------------------------------------*/
46
/**
47
 * This class assists the user in entering serial numbers.
48
 * <BR><BR>
49
 * Serial numbers, license number, CD keys and the like are often lenghty
50
 * alpha-numerical numbers. In many cases they are devided into multiple
51
 * parts by dash or point separators. Entering these in a single text field
52
 * can be a frustrating experience for the user. This class provides a way
53
 * of presenting the user with an assembly of input fields that are arranged
54
 * in the same way as the key, with the separators already in place.
55
 * Immideate testing for format compliance if performed ans soon as each
56
 * field is completed. In addition, the cursor is automatically advanced
57
 * to make entering numbers as painless as possible.
58
 * <br><br>
59
 * <b>Formatting:</b>
60
 * 
61
 * <ul>
62
 * <li><code>N:X:Y </code>- numeric field, accepts digits only
63
 * <li><code>H:X:Y </code>- hex field, accepts only hexadecimal digits
64
 * <li><code>A:X:Y </code>- alpha field, accepts only letters, no digits
65
 * <li><code>AN:X:Y</code>- alpha-numeric field, accepts digits and letters
66
 * </ul>
67
 * <b>Example:</b>
68
 * <br><br>
69
 * <code>"N:4:4 - H:6:6 - AN:3:3 x A:5:5"</code><br><br>
70
 * This formatting string will produce a serial number field consisting of
71
 * four separate input fields. The fisrt input field will accept four
72
 * numeric digits, the second six hexa-decimal digits, the third three
73
 * alpha-numeric digits and the fourth five letters. The first three input
74
 * fields will be separated by '-' and the third and fourth by 'x'. The
75
 * following snapshot was obtained with this setting: 
76
 * <br><br>
77
 * <img src="doc-files/RuleInputField-1.gif"/>
78
 *
79
 * @version  0.0.1 / 10/19/02
80
 * @author   Elmar Grom
81
 */
82
/*---------------------------------------------------------------------------*/
83
public class RuleInputField extends JComponent implements KeyListener,
84
                                                          FocusListener,
85
                                                          CaretListener,
86
                                                          ProcessingClient
87
{
88
  /** Used to specify the retsult format. This constant specifies to return
89
      the contents of all fields concatenated into one long string, with
90
      separation between each component. */
91
  public  static final int       PLAIN_STRING        = 1;
92
  /** Used to specify the retsult format. This constant specifies to return
93
      the contents of all fields together with all separators as specified
94
      in the field format concatenated into one long string. In this case
95
      the resulting string looks just like the user saw it during data entry */
96
  public  static final int       DISPLAY_FORMAT      = 2;
97
  /** Used to specify the retsult format. This constant specifies to return
98
      the contents of all fields concatenated into one long string, with
99
      a special separator string inserted in between the individual
100
      components. */
101
  public  static final int       SPECIAL_SEPARATOR   = 3;
102
  /** Used to specify the retsult format. This constant specifies to return
103
      the contents of all fields in a somehow modified way. How the content
104
      is modified depends on the operation performed by a encryption
105
      service class. The class must be provided at object instatiation. */
106
  public  static final int       ENCRYPTED           = 4;
107
  /** Used internally to identify the default setting for the return format. */
108
  private static int       DEFAULT             = DISPLAY_FORMAT;
109

    
110
  private Vector          items       = new Vector ();
111
  /** This <code>Vector</code> holds a reference to each input field, in the
112
      order in which they appear on the screen. */
113
  private Vector          inputFields = new Vector ();
114
  private boolean         hasParams   = false;
115
  private Map             validatorParams;
116
  private RuleTextField   activeField;
117
  private boolean         backstep = false;
118
  private Toolkit         toolkit;
119
  private String          separator;  
120
  private int             resultFormat        = DEFAULT;
121

    
122
  /** Holds an instance of the <code>Validator</code> if one was
123
      specified and available */  
124
  private Validator       validationService;
125
  /** Holds an instance of the <code>Processor</code> if one was specified
126
      and available */  
127
  private Processor       encryptionService;
128

    
129
  /**
130
   * @return true if this instance has any parameters to 
131
   * pass to the Validator instance.
132
   */
133
  public boolean hasParams()
134
  {
135
    return hasParams;
136
  }
137

    
138
 /*--------------------------------------------------------------------------*/
139
 /**
140
  * Constructs a rule input field.
141
  *
142
  * @param     format        a string that specifies the formatting and to a 
143
  *                          limited degree the behavior of this field.
144
  * @param     preset        a string that specifies preset values for specific
145
  *                          sub-fields.
146
  * @param     separator     a string to be used for separating the contents
147
  *                          of individual fields in the string returned by
148
  *                          <code>getText()</code>
149
  * @param     validator     A string that specifies a class to perform
150
  *                          validation services. The string must completely
151
  *                          identify the class, so that it can be instantiated.
152
  *                          The class must implement the <code>RuleValidator</code>
153
  *                          interface. If an attempt to instantiate this class
154
  *                          fails, no validation will be performed.
155
  * @param     validatorParams     A <code>java.util.Map</code> containing name/
156
  *                          value pairs, which will be forwarded to the validator. 
157
  * @param     processor     A string that specifies a class to perform
158
  *                          processing services. The string must completely
159
  *                          identify the class, so that it can be instantiated.
160
  *                          The class must implement the <code>Processor</code>
161
  *                          interface. If an attempt to instantiate this class
162
  *                          fails, no processing will be performed. Instead,
163
  *                          the text is returned in the default formatting.
164
  * @param     resultFormat  specifies in which format the resulting text
165
  *                          should be returned, wehn <code>getText()</code>
166
  *                          is called. The following values are legal:<br>
167
  *                          <ul>
168
  *                          <li>PLAIN_STRING     
169
  *                          <li>DISPLAY_FORMAT   
170
  *                          <li>SPECIAL_SEPARATOR
171
  *                          <li>ENCRYPTED        
172
  *                          </ul>
173
  * @param     toolkit       needed to gain access to <code>beep()</code>
174
  */
175
 /*--------------------------------------------------------------------------*/
176
        public RuleInputField(
177
                String format,
178
                String preset,
179
                String separator,
180
                String validator,
181
                Map validatorParams,
182
                String processor,
183
                int resultFormat,
184
                Toolkit toolkit)
185
        {
186
                this(
187
                        format,
188
                        preset,
189
                        separator,
190
                        validator,
191
                        processor,
192
                        resultFormat,
193
                        toolkit);
194
                this.validatorParams = validatorParams;
195
                this.hasParams = true;
196
        }
197

    
198
        /*--------------------------------------------------------------------------*/
199
        /**
200
         * Constructs a rule input field.
201
         *
202
         * @param     format        a string that specifies the formatting and to a 
203
         *                          limited degree the behavior of this field.
204
         * @param     preset        a string that specifies preset values for specific
205
         *                          sub-fields.
206
         * @param     separator     a string to be used for separating the contents
207
         *                          of individual fields in the string returned by
208
         *                          <code>getText()</code>
209
         * @param     validator     A string that specifies a class to perform
210
         *                          validation services. The string must completely
211
         *                          identify the class, so that it can be instantiated.
212
         *                          The class must implement the <code>RuleValidator</code>
213
         *                          interface. If an attempt to instantiate this class
214
         *                          fails, no validation will be performed.
215
         * @param     processor     A string that specifies a class to perform
216
         *                          processing services. The string must completely
217
         *                          identify the class, so that it can be instantiated.
218
         *                          The class must implement the <code>Processor</code>
219
         *                          interface. If an attempt to instantiate this class
220
         *                          fails, no processing will be performed. Instead,
221
         *                          the text is returned in the default formatting.
222
         * @param     resultFormat  specifies in which format the resulting text
223
         *                          should be returned, wehn <code>getText()</code>
224
         *                          is called. The following values are legal:<br>
225
         *                          <ul>
226
         *                          <li>PLAIN_STRING     
227
         *                          <li>DISPLAY_FORMAT   
228
         *                          <li>SPECIAL_SEPARATOR
229
         *                          <li>ENCRYPTED        
230
         *                          </ul>
231
         * @param     toolkit       needed to gain access to <code>beep()</code>
232
         */
233
        /*--------------------------------------------------------------------------*/
234
  public RuleInputField (String   format,
235
                         String   preset,
236
                         String   separator,
237
                         String   validator,
238
                         String   processor,
239
                         int      resultFormat,
240
                         Toolkit  toolkit)
241
  {
242
    this.toolkit      = toolkit;
243
    this.separator    = separator;
244
    this.resultFormat = resultFormat;
245

    
246
    com.izforge.izpack.gui.FlowLayout layout = new com.izforge.izpack.gui.FlowLayout ();
247
    layout.setAlignment (com.izforge.izpack.gui.FlowLayout.LEFT);
248
    setLayout (layout);
249

    
250
    // ----------------------------------------------------
251
    // attempt to create an instance of the Validator
252
    // ----------------------------------------------------
253
    try
254
    {
255
      validationService = (Validator)Class.forName (validator).newInstance ();
256
    }
257
    catch (Throwable exception)
258
    {
259
      validationService = null;
260
    }
261

    
262
    // ----------------------------------------------------
263
    // attempt to create an instance of the Processor
264
    // ----------------------------------------------------
265
    try
266
    {
267
      encryptionService = (Processor)Class.forName (processor).newInstance ();
268
    }
269
    catch (Throwable exception)
270
    {
271
      encryptionService = null;                   
272
    }
273

    
274
    // ----------------------------------------------------
275
    // create the fields and field separators
276
    // ----------------------------------------------------
277
    createItems (format);
278
    
279
    if ((preset != null) && (preset.length () > 0))
280
    {
281
      setFields   (preset);
282
    }
283

    
284
    // ----------------------------------------------------
285
    // set the focus to the first field
286
    // ----------------------------------------------------
287
    activeField = (RuleTextField)inputFields.elementAt (0);
288
    activeField.grabFocus ();
289
  }
290
 /*--------------------------------------------------------------------------*/
291
 /**
292
  * Returns the number of sub-fields composing this <code>RuleInputField</code>.
293
  *
294
  * @return    the number of sub-fields
295
  */
296
 /*--------------------------------------------------------------------------*/
297
  public int getNumFields ()
298
  {
299
    return (inputFields.size ());
300
  }
301
 /*--------------------------------------------------------------------------*/
302
 /**
303
  * Returns the contents of the field indicated by <code>index</code>.
304
  *
305
  * @param     index  the index of the sub-field from which the contents
306
  *                   is requested.
307
  *
308
  * @return    the contents of the indicated sub-field.
309
  *
310
  * @exception IndexOutOfBoundsException if the index is out of bounds.
311
  */
312
 /*--------------------------------------------------------------------------*/
313
  public String getFieldContents (int index) throws IndexOutOfBoundsException
314
  {
315
    if ((index < 0) || (index > (inputFields.size () - 1)))
316
    {
317
      throw (new IndexOutOfBoundsException ());
318
    }
319
    
320
    return (((JTextField)inputFields.elementAt (index)).getText ());
321
  }
322
 /*--------------------------------------------------------------------------*/
323
 /**
324
  * Returns the validator parameters, if any.  The caller should
325
  * check for the existence of validator parameters via the 
326
  * <code>hasParams()</code> method prior to invoking this method.
327
  * @return a java.util.Map containing the validator parameters.
328
  */
329
  public Map getValidatorParams()
330
  {
331
    return validatorParams;
332
  }
333

    
334
 /*---------------------------------------------------------------------------*/
335
 /**
336
  * Returns the field contents, assembled acording to the encryption and
337
  * separator rules.
338
  *
339
  * @return    the field contents
340
  */
341
 /*--------------------------------------------------------------------------*/
342
  public String getText ()
343
  {
344
    Object        item;
345
    StringBuffer  buffer = new StringBuffer ();
346
    int           size   = inputFields.size ();
347
    
348
    // ----------------------------------------------------
349
    // have the encryption service class perfrom the task
350
    // of assembling an output string. If we have no instance
351
    // of this class available set the formatting
352
    // instruction to the default setting.
353
    // ----------------------------------------------------
354
    if (resultFormat == ENCRYPTED)
355
    {
356
      if (encryptionService != null)
357
      {
358
        buffer.append (encryptionService.process (this));
359
      }
360
      else
361
      {
362
        resultFormat = DEFAULT;
363
      }
364
    }
365
    
366
    // ----------------------------------------------------
367
    // concatentate the field contents, with no separators
368
    // in between.
369
    // ----------------------------------------------------
370
    else if (resultFormat == PLAIN_STRING)
371
    {
372
      for (int i = 0; i < inputFields.size (); i++)
373
      {
374
        buffer.append (((JTextField)inputFields.elementAt (i)).getText ());
375
      }
376
    }
377

    
378
    // ----------------------------------------------------
379
    // concatenate the field contents and setarators, as
380
    // specified for the display of the field.
381
    // ----------------------------------------------------
382
    else if (resultFormat == DISPLAY_FORMAT)
383
    {
384
      for (int i = 0; i < items.size (); i++)
385
      {
386
        item = items.elementAt (i);
387
        if (item instanceof JTextField)
388
        {
389
          buffer.append (((JTextField)item).getText ());
390
        }
391
        else
392
        {
393
          buffer.append ((String)item);
394
        }
395
      }
396
    }
397

    
398
    // ----------------------------------------------------
399
    // concatenate the field contents and insert the
400
    // separator string in between.
401
    // ----------------------------------------------------
402
    else if (resultFormat == SPECIAL_SEPARATOR)
403
    {
404
      for (int i = 0; i < size; i++)
405
      {
406
        buffer.append (((JTextField)inputFields.elementAt (i)).getText ());
407
      
408
        if (i < (size - 1))
409
        {
410
          buffer.append (separator);
411
        }
412
      }
413
    }
414
    
415
    return (buffer.toString ());
416
  }
417
 /*--------------------------------------------------------------------------*/
418
 /**
419
  * Creates the items that make up this field. Both separators and input
420
  * fields are considered items. The items created are stored in
421
  * <code>items</code>. In addition, all fields are stored in
422
  * <code>inputFields</code>.
423
  *
424
  * @param     format  a string that specifies the layout of the input
425
  *            fields and separators.
426
  */
427
 /*--------------------------------------------------------------------------*/
428
 /*$
429
  * @design
430
  *
431
  * I used a simple StringTokenizer to break the format string into
432
  * individual tokens. The approach in building up the field is to consider
433
  * each token a potential definition for an input field. Therefore I
434
  * attempt to create an instance of FieldSpec from each token. FieldSpec
435
  * analyzes the token and if it does not represent a valid specification
436
  * for an input field throws an exception. If I catch an exception, I know
437
  * the token does not represent a valid field specification. In this case
438
  * I treat the token as a separator, even though this might not be what the
439
  * user had intended. However, this approach allows me to implement robust
440
  * behavior (no exception thrown) even though the user might have made a
441
  * mistake in the definition. The mistake should become immediately obvious
442
  * when testing the code, since a input field definition would show up as
443
  * separator between two fields.
444
  *--------------------------------------------------------------------------*/
445
  private void createItems (String format)
446
  {
447
    Object          item;
448
    JTextField      field;
449
    String          token;
450
    FieldSpec       spec;
451
    StringTokenizer tokenizer = new StringTokenizer (format);
452
    
453
    while (tokenizer.hasMoreTokens ())
454
    {
455
      token = tokenizer.nextToken ();
456
      try
457
      {
458
        spec  = new FieldSpec (token);
459
        field = new RuleTextField (spec.getColumns (), 
460
                                   spec.getEditLength (), 
461
                                   spec.getType (), 
462
                                   spec.getUnlimitedEdit (), 
463
                                   toolkit);
464
                                   
465
        // ------------------------------------------------
466
        // if the previous item is also a field, insert a
467
        // space as separator
468
        // ------------------------------------------------
469
        if (items.size () > 0)
470
        {
471
          item = items.lastElement ();
472
        
473
          if (item instanceof JTextField)
474
          {
475
            items.add (" ");
476
          }   
477
        }
478

    
479
        items.add (field);
480
        inputFields.add (field);
481
        field.addFocusListener  (this);
482
        field.addKeyListener    (this);
483
        field.addCaretListener  (this);
484
      }
485
      // --------------------------------------------------
486
      // if we were not successful creating an input field,
487
      // the token must be a separator or the definition
488
      // has an error. Simply insert it as separator,
489
      // when testing the installer the error should become
490
      // obvious to the developer.
491
      // --------------------------------------------------
492
      catch (Throwable exception)
493
      {
494
        if (items.size () == 0)
495
        {
496
          items.add (token);
497
        }
498
        else
499
        {
500
          item  = items.lastElement ();
501
        
502
          // ----------------------------------------------
503
          // if the previous item is also a separator,
504
          // simply concatenate the token with a space
505
          // inserted in between, don't add it as new
506
          // separator.
507
          // ----------------------------------------------
508
          if (item instanceof String)
509
          {
510
            items.setElementAt (item + " " + token, (items.size () - 1));
511
          }
512
          else
513
          {
514
            items.add (token);
515
          }
516
        }
517
      } 
518
    }
519

    
520
    // ----------------------------------------------------
521
    // add the fields and separators to the component
522
    // ----------------------------------------------------
523
    for (int i = 0; i < items.size (); i++)
524
    {
525
      item = items.elementAt (i);
526
      
527
      if (item instanceof String)
528
      {
529
        add (new JLabel ((String)item));
530
      }
531
      else
532
      {
533
        add ((JTextField)item);
534
      }
535
    }
536
  }
537
 /*--------------------------------------------------------------------------*/
538
 /**
539
  * Sets each field to a pre-defined value.
540
  *
541
  * @param     data   a <code>String</code> containing the preset values for
542
  *                   each field. The format of the string is as follows:
543
  *                   The content for the individuals fields must be separated
544
  *                   by whitespace. Each data block is preceeded by the index
545
  *                   of the field to set (counting starts at 0) followed by
546
  *                   a colon ':'and after that the actual data for the field.
547
  */
548
 /*--------------------------------------------------------------------------*/
549
  private void setFields (String data)
550
  {
551
        StringTokenizer tokenizer = new StringTokenizer (data);
552
        StringTokenizer tokenizer1 = null;
553
    String          token;
554
    String          indexString;
555
    String                    processorClass;
556
    int             index;
557
    boolean process = false;
558
    String[] vals = null;
559
    int i = 0;
560
    
561
    vals = new String[tokenizer.countTokens()];
562
    while (tokenizer.hasMoreTokens ())
563
    {
564
      token       = tokenizer.nextToken ();      
565
      indexString = token.substring (0, token.indexOf (':'));
566
      
567
      try
568
      {
569
        index     = Integer.parseInt (indexString);
570
        if (index < inputFields.size ())
571
        {
572
                String val = token.substring ((token.indexOf (':') + 1), token.length ());
573
                String className = "";
574
                if (val.indexOf(":")>-1){
575
                        className = val.substring(val.indexOf(":")+1);
576
                        val = val.substring(0, val.indexOf(":"));                        
577
                }
578
                
579
                if (!className.equals("") && !process){
580
                        process = true;
581
                }
582
                        vals[i] = val;
583
                        i++;
584
          ((JTextField)inputFields.elementAt (index)).setText (val);
585
        }
586
      }catch (Throwable exception)
587
          {
588
                  exception.printStackTrace();
589
          }
590
    }
591
    
592
        if (process){
593
                tokenizer = new StringTokenizer (data);
594
                while (tokenizer.hasMoreTokens ()){
595
                        token = tokenizer.nextToken ();      
596
                        indexString = token.substring (0, token.indexOf (':'));
597
                              
598
                      try{
599
                                index     = Integer.parseInt (indexString);
600
                                if (index < inputFields.size ()){
601
                                        String val = token.substring ((token.indexOf (':') + 1), token.length ());
602
                                        String className = "";
603
                                        String presult = "";
604
                                        if (val.indexOf(":")>-1){
605
                                                className = val.substring(val.indexOf(":")+1);
606
                                                val = val.substring(0, val.indexOf(":"));                        
607
                                        }
608
                
609
                                   if (!className.equals("")){
610
                                           Processor p = (Processor) Class.forName(className).newInstance();
611
                                                presult = p.process(this);
612
                                   }
613
                                           String[] td = new RE("\\*").split(presult);                                   
614
                                        ((JTextField)inputFields.elementAt (index)).setText (td[index]);
615
                                }
616
                      }catch (Throwable exception){
617
                              ;
618
                        }
619
                }
620
    }
621
  }
622
 
623
 /*--------------------------------------------------------------------------*/
624
 /**
625
  * This method validates the field content. Validating is performed through
626
  * a user supplied service class that provides the validation rules.
627
  *
628
  * @return    <code>true</code> if the validation passes or no implementation
629
  *            of a validation rule exists. Otherwise <code>false</code> is
630
  *            returned.
631
  */
632
 /*--------------------------------------------------------------------------*/
633
  public boolean validateContents ()
634
  {
635
    if (validationService != null)
636
    {
637
      return (validationService.validate (this));
638
    }
639
    else
640
    {
641
      return (true);
642
    }
643
  }
644

    
645
/*---------------------------------------------------------------------------*
646
                    Implementation for KeyListener
647
 *---------------------------------------------------------------------------*/
648

    
649
 /*--------------------------------------------------------------------------*/
650
 /**
651
  * This method is invoked when a key has been typed. The event occurs when
652
  * a key press is followed by a key release. 
653
  *
654
  * @param     event the key event forwarded by the system.
655
  */
656
 /*--------------------------------------------------------------------------*/
657
  public void keyTyped (KeyEvent event)
658
  {
659
  }
660
 /*--------------------------------------------------------------------------*/
661
 /**
662
  * This method is invoked when a key has been pressed. This method verifies
663
  * the condition of the input field in focus. Once the column count in the
664
  * field has reached the specified maximum, the rule specified for the field
665
  * in question is invoked. In case the test result is positive, focus is set
666
  * to the next field. If hte test result is negative, the field content is
667
  * marked and the caret set to the start of the field.
668
  *
669
  * @param     event the key event forwarded by the system.
670
  */
671
 /*--------------------------------------------------------------------------*/
672
  public void keyPressed (KeyEvent event)
673
  {
674
    if (event.getKeyCode () == KeyEvent.VK_BACK_SPACE)
675
    {
676
      int caretPosition = activeField.getCaretPosition ();
677
      
678
      if (caretPosition == 0)
679
      {
680
        int activeIndex = inputFields.indexOf (activeField);
681
        
682
        if (activeIndex > 0)
683
        {
684
          activeIndex--;
685
          backstep = true;
686
          activeField = (RuleTextField)inputFields.elementAt (activeIndex);
687
          activeField.grabFocus ();
688
        }
689
      }
690
    }
691
  }
692
 /*--------------------------------------------------------------------------*/
693
 /**
694
  * This method is invoked when a key has been released.
695
  *
696
  * @param     event the key event forwarded by the system.
697
  */
698
 /*--------------------------------------------------------------------------*/
699
  public void keyReleased (KeyEvent event)
700
  {
701
  }
702

    
703
/*---------------------------------------------------------------------------*
704
                    Implementation for FocusListener
705
 *---------------------------------------------------------------------------*/
706

    
707
 /*--------------------------------------------------------------------------*/
708
 /**
709
  * Invoked when a component gains the keyboard focus. 
710
  *
711
  * @param     event  the focus event forwardes by the sytem.
712
  */
713
 /*--------------------------------------------------------------------------*/
714
 /*$
715
  * @design     <- keep this tag in place and don't write on this line!
716
  *
717
  * Enter design related documentation here.
718
  *--------------------------------------------------------------------------*/
719
  public void focusGained (FocusEvent event)
720
  {
721
    activeField = (RuleTextField)event.getSource ();
722

    
723
    if (backstep)
724
    {
725
      activeField.setCaretPosition (activeField.getText ().length ());
726
      backstep = false;
727
    }
728
    else
729
    {
730
      activeField.selectAll ();
731
    }
732
  }
733
 /*--------------------------------------------------------------------------*/
734
 /**
735
  * Invoked when a component loses the keyboard focus. This method does
736
  * nothing, we are only interested in 'focus gained' events.
737
  *
738
  * @param     event  the focus event forwardes by the sytem.
739
  */
740
 /*--------------------------------------------------------------------------*/
741
  public void focusLost (FocusEvent event)
742
  {
743
  }
744
  
745
/*---------------------------------------------------------------------------*
746
                    Implementation for CaretListener
747
 *---------------------------------------------------------------------------*/
748
  
749
 /*--------------------------------------------------------------------------*/
750
 /**
751
  * Called when the caret position is updated.
752
  *
753
  * @param     event the caret event received from the text field
754
  */
755
 /*--------------------------------------------------------------------------*/
756
  public void caretUpdate (CaretEvent event)
757
  {
758
    String  text          = activeField.getText ();
759
    int     fieldSize     = activeField.getEditLength ();
760
    int     caretPosition = activeField.getCaretPosition ();
761
    int     selection     = activeField.getSelectionEnd () - activeField.getSelectionStart ();
762

    
763
    if ((!inputFields.lastElement ().equals (activeField)) && (!activeField.unlimitedEdit ()))
764
    {
765
      if ((text.length () == fieldSize) && (selection == 0) && (caretPosition == fieldSize) && !backstep)
766
      {
767
        activeField.transferFocus ();
768
      }
769
    }
770
  }
771

    
772
// ----------------------------------------------------------------------------
773
//
774
// ----------------------------------------------------------------------------
775
  private static class FieldSpec
776
  {
777
    private int     MIN_TOKENS     = 2;
778
    private int     MAX_TOKENS     = 3;
779
  
780
    private int     type;
781
    private int     columns;
782
    private int     editLength;
783
    private boolean unlimitedEdit = false;
784
    
785
    public FieldSpec (String spec) throws Exception
786
    {
787
      StringTokenizer tokenizer = new StringTokenizer (spec, ":");
788
      
789
      if ((tokenizer.countTokens () >= MIN_TOKENS) && (tokenizer.countTokens () <= MAX_TOKENS))
790
      {
791
        String token = tokenizer.nextToken ().toUpperCase ();
792
        // ------------------------------------------------
793
        // test the first token for a valid type identifier
794
        // if it's valid assign the token to the type.
795
        // ------------------------------------------------
796
        if (token.equals ("N"))
797
        {
798
          type = RuleTextField.N;
799
        }
800
        else if (token.equals ("H"))
801
        {
802
          type = RuleTextField.H;
803
        }
804
        else if (token.equals ("A"))
805
        {
806
          type = RuleTextField.A;
807
        }
808
        else if (token.equals ("O"))
809
        {
810
          type = RuleTextField.O;
811
        }
812
        else if (token.equals ("AN"))
813
        {
814
          type = RuleTextField.AN;
815
        }
816
        else
817
        {
818
          throw (new Exception ());
819
        }
820

    
821
        // ------------------------------------------------
822
        // test for a valid integer to define the size
823
        // of the field and assing to columns. 
824
        // ------------------------------------------------
825
        try
826
        {
827
          token   = tokenizer.nextToken ();
828
          columns = Integer.parseInt (token);
829
        }
830
        catch (Throwable exception)
831
        {
832
          throw (new Exception ());
833
        }        
834
        
835
        // ------------------------------------------------
836
        // test for a valid integer to define the edit
837
        // length and assign to editLength. If this fails
838
        // test for identifier for unlimited edit length.
839
        // If this works, set unlimitedEdit to true.
840
        // ------------------------------------------------
841
        try
842
        {
843
          token       = tokenizer.nextToken ().toUpperCase ();
844
          editLength  = Integer.parseInt (token);
845
        }
846
        catch (Throwable exception)
847
        {
848
          if (token.equals ("U"))
849
          {
850
            unlimitedEdit = true;
851
          }
852
          else
853
          {
854
            throw (new Exception ());
855
          }
856
        }
857

    
858
      }
859
      else
860
      {
861
        throw (new Exception ());
862
      }
863
    }
864
    
865
    public int getColumns ()
866
    {
867
      return (columns);
868
    }
869
    
870
    public int getEditLength ()
871
    {
872
      return (editLength);
873
    }
874
    
875
    public int getType ()
876
    {
877
      return (type);
878
    }
879
    
880
    public boolean getUnlimitedEdit ()
881
    {
882
      return (unlimitedEdit);
883
    }
884
    
885
  }
886
// ----------------------------------------------------------------------------
887

    
888
}
889
/*---------------------------------------------------------------------------*/