7.1 The TextTuttle class

The class diagram for the TextTuttle class is presented in Figure 7.1.

Figure 7.1 The TextTuttle class diagram.

The constructor has the same effect as the Tuttle constructor, requesting a tuttle drawing area with the dimensions specified and passing the identity of the applet for use by the tuttle. The other public attributes shown on the diagram are the manifest values of all the commands which the TextTuttle will respond to. The identifyCommand() method will attempt to return the manifest value of the command contained in the String argument command, or the value UNKNOWN, if it cannot be recognised. The remaining method, doCommand(), will take a complete command String and attempt to execute it. If it is possible for the TextTuttle to process the instruction, doCommand() will return an empty String in comment, otherwise it will contain an explanation of why the instruction could not be obeyed. The class diagram also shows two private methods called doCommand() and identifyColor() whose use will be described below. The implementation of this class, as far as the end of the constructor, is as follows.

0001  // Filename TextTuttle.java. 0002  // Extends the Tuttle class by providing a text  0003  // interface for its commands. 0004  // 0005  // Written for the Java Interface Book Chapter 7. 0006  // Fintan Culwin, v 0.2, August 1997. 0007   0008  package Tuttles; 0009   0010  import java.awt.*; 0011  import java.applet.*; 0012  import java.util.StringTokenizer; 0013   0014  import Tuttles.Tuttle; 0015   0016  public class TextTuttle extends Tuttle { 0017   0018  public static final int UNKNOWN         = -1; 0019  public static final int FORWARD         = 0; 0020  public static final int BACKWARD        = 1; 0021  public static final int TURN_RIGHT      = 2; 0022  public static final int TURN_LEFT       = 3; 0023  public static final int FOREGROUND      = 4; 0024  public static final int BACKGROUND      = 5; 0025  public static final int PEN_UP          = 6; 0026  public static final int PEN_DOWN        = 7; 0027  public static final int CLEAR           = 8; 0028  public static final int RESET           = 9; 0029  public static final int CLEAR_AND_RESET = 10; 0030  public static final int EXIT            = 11; 0031  public static final int MAX_COMMANDS    = 11; 0032   0033  private static final String[] commands =  0034                         { "fd", "bd", "tr", "tl", 0035                           "fg", "bg", "pu", "pd",  0036                           "cl", "rs", "cr",  0037                           "exit" }; 0038   0039   0040     public TextTuttle(  Applet applet, int width, int height) {  0041        super( applet, width, height);       0042     } // End TextTuttle constructor.

The manifest values for the commands are enumerated on lines 0018 to 0031, with delimiting values for UNKNOWN commands and for the maximum number of commands. The declaration of the String array commands[], on lines 0033 to 0037, provides the corresponding two letter abbreviation for each command, apart from the "exit" command. Finally, in this part, the constructor is implemented as a dispatching call of the parent, Tuttle, constructor. The doCommand() method relies upon the identifyCommand() method; the implementation of these two methods is as follows.

0045     public String doCommand( String theCommand) {  0046      0047     StringTokenizer tokenizer = new StringTokenizer( theCommand); 0048     String          firstTerm = null; 0049     String          theReply;    0050   0051     int thisCommand = UNKNOWN; 0052      0053        if ( tokenizer.hasMoreTokens()) {  0054           firstTerm   = tokenizer.nextToken().toLowerCase(); 0055           thisCommand = identifyCommand( firstTerm); 0056            0057           if ( thisCommand == UNKNOWN ) {  0058              theReply = new String( "The command " + firstTerm +  0059                                     " is not known!"); 0060           } else {  0061              theReply = dispatchCommand( thisCommand, tokenizer);        0062           } // End if. 0063        } else {  0064           theReply = new String( "There does not seem to be a command given!"); 0065        } // End if. 0066        return theReply; 0067     } // End doCommand. 0068   0069   0070     public int identifyCommand( String toIdentify) {  0071      0072     int thisCommand = MAX_COMMANDS; 0073     int identified  = UNKNOWN; 0074      0075       while ( ( identified  == UNKNOWN) && 0076               ( thisCommand != UNKNOWN) ){ 0077          if ( toIdentify.equals( commands[ thisCommand])) {  0078             identified = thisCommand; 0079          } else {  0080             thisCommand--; 0081          } // End if.             0082       } // End while. 0083       return identified; 0084     } // End identifyCommand.

The doCommand() method commences, on line 0047, by constructing a StringTokenizer instance called tokenizer which will be used to split its single String argument, theCommand, into its constituent parts. The provision of a suitable command to this method is the responsibility of the tuttle text interfaces, as will be described below.

Having initialised the tokenizer, on line 0053, the tokenizer hasMoreTokens() method is used to make sure that theCommand is not empty and, if it is, theReply is prepared with a suitable message on line 0064. Otherwise the firstTerm is obtained from the tokenizer on line 0054 and identified, using identifyCommand(), on line 0055. If the firstTerm is not identified a suitable reply is placed into theReply on lines 0058 and 0059. If this is not the case then the firstTerm has been identified as a valid command and it is processed by the private dispatchCommand() method, on line 0061, passing as the second argument the tokenizer which still contains any remaining terms. In this case the String returned by dispatchCommand() is stored in theReply to be returned as the result of the doCommand() method, on line 0066.

The identifyCommand() method, on lines 0070 to 0084, is a sequential search of the commands[] array. It returns the appropriate manifest value identifying the command contained in its toIdentify argument, or the value UNKNOWN if it does not contain a valid command. Should additional commands be added during maintenance, then additional manifest values can be added to the list and their string representation to the commands[] array, and this method will still operate correctly.

The dispatchCommand() method has the responsibility of checking any arguments of the Tuttle command and returning an appropriate message should too many, too few or an inappropriate argument be supplied. If the arguments do prove to be acceptable the appropriate method of the parent, Tuttle, class should be called and an empty String returned.

The first part of its implementation, as follows, is concerned with processing those commands which require a single integer argument: forwards, backwards, turn left and turn right. .

0087     private String dispatchCommand( int             theCommand,  0088                                     StringTokenizer arguments){  0089                                        0090     StringBuffer theResponse = new StringBuffer( ""); 0091     boolean      processed   = false; 0092                                           0093       switch( theCommand) {  0094        0095       case FORWARD: 0096       case BACKWARD: 0097       case TURN_RIGHT: 0098       case TURN_LEFT: 0099          if (arguments.countTokens() == 1) {  0100          int toStepOrTurn;         0101              try {  0102                 toStepOrTurn = Integer.parseInt( arguments.nextToken()); 0103                 switch ( theCommand) { 0104                 case FORWARD:  0105                    this.forward( toStepOrTurn); 0106                    break; 0107                 case BACKWARD: 0108                    this.backward( toStepOrTurn); 0109                    break;  0110                 case TURN_RIGHT: 0111                    this.turnRight( toStepOrTurn); 0112                    break;                                       0113                 case TURN_LEFT: 0114                    this.turnLeft( toStepOrTurn); 0115                    break;                   0116                 } // End switch. 0117                 processed = true;           0118              } catch ( NumberFormatException exception) {  0119                 processed = false;                     0120              } // End try/ catch. 0121          } // End if. 0122          if ( !processed) {  0123             theResponse.append( commands[ theCommand] +   0124                          " should be followed by a single number."); 0125          } // End if.  0126          break;

The switch structure starting on line 0093 is controlled by the manifest value of theCommand, passed to dispatchCommand() from the doCommand() method. On lines 0095 to 0098 the first branch of the outer switch statement starting on line 0093 lists, as case selectors, the manifest values of the commands which require a single integer argument.

The processing of these commands commences, on line 0099, with a check to make sure that only a single argument remains in the StringTokenizer instance called arguments, which was passed from the doCommand() method. If this is so then, on line 0102, an attempt is made, within a try/ catch structure, to interpret this argument as an integer and store it in the local variable toStepOrTurn. Assuming that an exception is not throw a second inner switch structure, between lines 0103 and 0116, dispatches to a call of the appropriate Tuttle method passing the value of toStepOrTurn as its argument. The final stage of the try part of the try/ catch structure sets the processed flag true.

If the command has not been processed, either because there are too many or too few arguments, or because the single argument does not contain an integer value, the value of processed will be false, unchanged from its declaration on line 0091. This will cause a suitable message to be placed into the StringBuffer theResponse, on lines 0123 to 0124. Finally, on line 0126, this part of the switch structure which started on line 0093 is completed with a break statement.

For example if the doCommand() method were called with the String "fd 30". The fd part of the command would be extracted and identified by identifyCommand() as the manifest value FORWARD. This will cause dispachCommand() to be called with FORWARD as its first, theCommand, argument and the StringTokenizer, still containing "30" as its second argument. The value FORWARD will match the selector on line 0095 and cause the switch branch commencing on line 0099 to be executed. The if condition on line 0099 would evaluate true and so the trycatch structure on line 0101 would be attempted. As "30" can be interpreted as the integer value 30, no exception would be thrown on line 0102 and the inner switch structure on line 0103 would be considered. The value FORWARD in theCommand would cause line 0105 to be executed. This is a call of the Tuttle forward() method, inherited by the TextTuttle class, and will result in the tuttle moving forwards 30 steps. The next line to be executed would be line 0117 setting the value of the processed flag true and avoiding any message being placed into theResponse on lines 0123 and 0124.

Alternatively if the command received by the doCommand() method were "fd" or "fd 30 please", the command would still be identified as FORWARD but the if condition on line 0099 would be false and result in lines 0123 and 0124 placing a suitable message in theResponse. This would also happen if the command were "fd please": the condition on line 0099 would now be true but the attempted conversion of "please" to an integer, on line 0102 would throw a NumberFormatException which, when it was caught on line 0118, would set the processed flag to cause the message to be placed in to theResponse, as before.

The next part of the dispatchCommand() method processes those actions which require no arguments: pen up, pen down, reset, clear and clear and reset. Its implementation, which follows, is similar to the previous fragment.

0128       case PEN_UP: 0129       case PEN_DOWN: 0130       case RESET: 0131       case CLEAR: 0132       case CLEAR_AND_RESET: 0133          if (arguments.countTokens() == 0) {  0134             switch ( theCommand) { 0135             case PEN_UP: 0136                this.setPenUp(); 0137                break; 0138             case PEN_DOWN: 0139                this.setPenDown(); 0140                break; 0141             case RESET:         0142                this.resetTuttle(); 0143                break;  0144             case CLEAR:         0145                this.clearTuttleArea(); 0146                break;                    0147             case CLEAR_AND_RESET:         0148                this.clearAndReset(); 0149                break;  0150             } // End switch. 0151             processed = true;    0152          } // End if. 0153          if ( !processed) {  0154              theResponse.append( commands[ theCommand] +  0155                           " should not  be followed by anything.");          0156          } // End if.                                                          0157          break;

Line 0133 ensures that no arguments have been supplied and if this is so then an inner switch structure, between lines 0134 to 0150 dispatches to a call of the appropriate parent Tuttle method. Should any arguments be supplied then lines 0154 to 0155 will place an appropriate message in theResponse. The next part of the method deals with the foreground and background commands, which require a single argument identifying one of the six acceptable Tuttle colors.

0159       case FOREGROUND: 0160       case BACKGROUND: 0161          if (arguments.countTokens() == 1) {  0162          Color theColor;  0163             theColor = identifyColor( arguments.nextToken().toLowerCase()); 0164             if ( theColor != null) {  0165                if ( theCommand == FOREGROUND) {  0166                   this.setForeground( theColor); 0167                } else {  0168                   this.setBackground( theColor); 0169                } // End if. 0170                processed = true; 0171             } // End if. 0172          } // End if. 0173          if ( !processed) {  0174             theResponse.append( commands[ theCommand] +  0175                          " should only be followed by white, black, red, " +  0176                          "blue, green or yellow.");                         0177          } // End if.      0178          break; 0179       } // End switch. 0180       return theResponse.toString(); 0181    } // End dispatchCommand.

Line 0164 uses the private identifyColor() method to decide if a valid color name has been supplied in the single argument. The implementation of the identifyColor() method is given below. If the color name is recognized the appropriate tuttle command is called, otherwise a message is placed into theResponse. The dispatchCommand() method concludes, on line 0180, by returning the String contained in theResponse, which will be empty if the command has been passed to the tuttle or will contain a suitable message otherwise.

0185     private Color identifyColor( String possibleColor) {  0186   0187     Color theColor = null; 0188        if ( possibleColor.equals( "black")) {  0189           theColor = Color.black; 0190        } else if ( possibleColor.equals( "white")) {        0191           theColor = Color.white; 0192        } else if ( possibleColor.equals( "yellow")) {   0193           theColor = Color.yellow;   0194        } else if ( possibleColor.equals( "green")) {   0165           theColor = Color.green; 0196        } else if ( possibleColor.equals( "red")) {   0197           theColor = Color.red;          0198        } else if ( possibleColor.equals( "blue")) {   0199           theColor = Color.blue;          0200        } // End if.         0201        return theColor; 0202     } // End IdentifyColor.

The dispatchCommand() method does not attempt to process the exit command because, as explained in the previous chapter, exiting from an application must be the responsibility of a translation module not of an application module. The processing of the exit command will be described in the two text interfaces later in this chapter.

This completes the implementation of the TextTuttle class but a complete demonstration of its effectiveness cannot be provided until the CommandLineTuttle interface is considered later in this chapter. However a partial demonstration is contained with the TextMenuTuttle class which follows.



7.2 The TextMenuTuttle interface

Chapter 7 Text based user interfaces

A Java GUI programmer's primer
Java GUI Programmers Primer, A
ISBN: 0139088490
EAN: 2147483647
Year: 1998
Pages: 85
Authors: Fintan Culwin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net