Previous Page TOC Index Next Page

Chapter 26

Phone book and telephone dialer applications

In this chapter we go through the design of an interactive online telephone book application. First of all, we need to decide which features we want to include in the online telephone book. Of course, we want it to display names and telephone numbers. It would be a nice feature to have a telephone book applet that dials selected numbers. Also, we will want to keep all telephone information on the Internet so that it will be easier to keep this information up-to-date and enable users to access this information from different computer platforms.

We can summarize features we want to be implemented in the telephone book application:

Here are the implementation-specific details:

Application Design

Strategic decisions we need to make:

Once we selected Java and Web technology as our implementation base, the answer about where to store the data apparently is clear: We will keep it as a document on a Web server. The format does not make a big difference. It could be an HTML document or simply a text file, as long as we can access it over the Net. We will use a very simple format. Name or address information will be delimited from the phone numbers by space or tab symbols. Separate records will be delimited by end-of-line markers. Here is an example of a data file:

Jim  (314) 935-81-34 <EOL>

Gene 0-117-095-158-5544 <EOL>

How can we dial a phone number? Our first idea would be to simply send the AT command sequence to a modem and have it dial the number over the interface with a telephone line. But what if you do not have a modem attached to your computer or it is busy because you are connected to a BBS or an Internet service provider? A better way would be to dial the number by playing telephone dialing tones on the computer speaker. We always can create or record dialing tones (also called DTMF tones, for Dual Tone Multi-Frequency) and use them when we need to dial a number.

Now let’s think about the user interface. Definitely, we will need to display telephone numbers and a searchable list where the user can select a name or address. We will need a dial button. Also, it would be nice to have something like a telephone button pad so that users could enter a phone number that is not found in the telephone book.

We can start designing application components and creating a skeleton for our program. First of all, to have a valid Java application accessible from the Internet browser, we need to include an Applet class. Then, we need a class that incorporates user controls: buttons, edit boxes, and list boxes. Let’s call it PhoneControls. To include the functionality of the telephone button pad, we will create a third class called ButtonPad.

The PhoneDial class, derived from the Java Applet class, implements the functionality of Java interactive application capable of communicating with Java-enabled Internet browsers. We will need to customize the default behavior of the Applet class in order to bring telephone book functionality to our users. At this time, the PhoneDial applet does almost nothing. It creates a PhoneControls class that will have telephone book controls, adding this to the center of its own window. Then it passes start and stop notification events to the PhoneControl class in order to enable controls when Applet is started and disable them when it is about to finish.

public class PhoneDial extends Applet {

     PhoneControls controls;

     public void init( ) //applet initialization function

        {

                 String strParam = getParameter(“PHONEBOOK”); //get argument  “PHONEBOOK”

               String strPhoneBook = (strParam == null) ? “phonebook.html” : strParam; //use the default telephone book document name if  argument not found

                 controls = new PhoneControls( );  //create controls

                 add(“Center”, controls); //add controls to the applet

     }

        public void start( ) //applet starting

         {

          controls.enable( ); //enable controls on applet start

         }

         public void stop( ) //applet is about to be closed

         {

          controls.disable( ); //disable controls 

         }

     public static void main(String args[]) 

         {

        Frame f = new Frame(“PhoneDial”); //create applet frame

        PhoneDial     phoneDial = new PhoneDial( ); //create a new applet class

        phoneDial.init( ); //init applet

        phoneDial.start( ); //start applet

        f.add(“Center”, phoneDial); //add applet to the center of allocated window

        f.resize(150, 200); //resize to preferred dimensions

        f.show( ); //show applet 

         }

}

The function main( ) does a very important job for the applet: It creates a frame for our application and starts a thread where the application actually is running. At first it might seem a little strange. Why should we care about creating a thread for an application if it already is running? The key to understanding this is in the fact that we should return control from the main function, and must do it as fast as possible in order to free up the Internet browser for other useful tasks. At the same time, we will need to keep our application running to process user input, update the screen when necessary, and so on. Luckily, we do not need to write any code to start a thread. This is the default behavior of the Applet class.

We want to add a frame and possibly resize the applet to the dimensions we think would be optimal for our application. We do not expect that we will always get these dimensions. Actually, the browser will negotiate the real size to allocate for the applet during initialization. The application-desired size might be overridden when the actual space available is not large enough or when dimensions are specified in the HTML document that includes calls to the applet.

The last function call we want to add to the main function is show( ). It will send a request to the Internet browser notifying it that our application is ready to be displayed and will cause it to update the part of the screen allocated for our applet.

Two other classes, PhoneControls and ButtonPad, are derived from the Panel class and inherit the functionality of that group of controls. ButtonPad will include telephone buttons and PhoneControls class will include all other elements of user interface: text box for telephone number, list box for selection telephone number from the list of persons and organizations, and the “dial” button that initiate process of dialing selected number.

class PhoneControls extends Panel    //class that will incorporate user controls

{

 ButtonPad controlsButtonPad; //declare class with telephone-style buttons

  

   public PhoneControls( ) // PhoneControls  class constructor

   {

       //TO DO: Add buttons “0” to “9”, “*” and “#”

   }

}

class ButtonPad extends Panel  //class with telephone button pad keys

{

    public ButtonPad( ) // ButtonPad class constructor

    {

       //TO DO: Add text box for telephone number, list box and “Dial” button

    }

}

At this time, we included only empty constructors for PhoneControls and ButtonPad classes and placed the ButtonPad variable declaration into the PhoneControls. Note that we have not actually created a new ButtonPad class. We do not need that unless we actually have some buttons in it.

At this time we can compile our project and create an HTML file to test it out. We do not need to have anything in this page but a call to the PhoneDial applet:

<title>PhoneBook</title>

<hr>

<applet code=PhoneDial.class width=400 height=400>

</applet>

<hr>

It is no surprise that our application does nothing at this point except display a gray square.

Interface Design

Now we need to forget that we are computer programmers and become an artist for a moment. We need to place our controls so that they will be easy to find. We do not have too many of them—just a button pad, a window where we want to edit the phone number, and a box where we can select a person or organization we want to call. The more people involved in interface design, the more solutions you will have. One of the possible solutions for the user interface is shown on Figure 26.1.

Figure FIGURE 26.1.

User interface for the Phone Book and Telephone Dialer application.

Now we can go back to coding and start from the button pad control. First, we need to select the layout. Because all buttons have the same size, GridLayout is the natural choice. We create a GridLayout class and declare the dimensions (four rows and three columns as on your telephone pad) and a gap between buttons.

GridLayout bag = new GridLayout(4, 3, 1, 1);

Now we can assign this layout to our panel as follows:

setLayout(bag);

At this time we can add buttons. To do this, we will create a button, set a label for it, and then add this button into our control panel. We use a small case statement to handle labels for the buttons on the bottom row differently—instead of sequential numbers we need to add * , 0, and # to these buttons.

for(int i= 0; i<12; i++)

{

       Button b = new Button(“ “);

       if (i<9)

          setLabel(“   “+String.valueOf(i+1)+”   “);

       else

          switch(i)

          {

           case 9: 

               b.setLabel(“*”);

               break;

           case 10: 

               b.setLabel(“0”);

               break;

           case 11: 

               b.setLabel(“#”);

               break;

          }

       add(b);

}

Now when the button pad is ready, we can place it on the main control panel and start adding other controls. First, we need to declare control elements in the PhoneControl class as follows:

TextField textPhone;

   Button       buttonDial;

   List       listPhone;

We will use the variable textPhone for the text control with the phone number, buttonDial for the large Dial button on the bottom of our form, and listPhone for the list box control where the user can look up the person or organization to call.

For the PhoneControl, we cannot select the same layout used for the button pad because all controls are of different sizes. We have a choice between CardLayout, GridBagLayout, FlowLayout, and BorderLayout. Of course, CardLayout does not fit—we do not want to have the user flipping cards until finding the right control; it is more appropriate for options in setup dialogs. FlowLayout just places controls one after another—we do not want that either. With the GridBagLayout, you have the most control over the placement of interface elements, but for this flexibility you will have to pay with extra coding. You will have to set up values that control placement to the GridBagConstraints class. It is not entirely a complex job but just a little boring. We will use BorderLayout because it is simple enough and allows us to control component placement in terms of North, South, East, West, and Center. Now we can set up layout and add our controls to the PhoneControls panel, as follows:

setLayout(new BorderLayout( ));

     htPhones = new Hashtable( );

     listPhone = new List(5, false);

     add(“East”, listPhone);

     add(“North”, textPhone =  new TextField(“”, 12));

     add(“West”, controls = new ButtonPad( ));

     add(“South”, buttonDial =  new Button(“Dial”));

The whole program at this point is shown in Listing 26.1.

/*

 *  Phone Book Application

 */

import java.awt.*;

import java.applet.*;

public class PhoneDial extends Applet 

{

    PhoneControls controls;

     public void init( )

    {

          setLayout(new BorderLayout( ));

          controls = new PhoneControls( ); 

          add(“Center”, controls); 

    }

    public void start( )

    {

          controls.enable( );

    }

    public void stop( ) 

    {

          controls.disable( );

    }

}

    

    public static void main(String args[]) 

    {

              

      Frame f = new Frame(“PhoneDial”); //create an application frame

      PhoneDial     phoneDial = new PhoneDial( );

      phoneDial.init( ); //init application

      phoneDial.start( ); //start application

      f.add(“Center”, phoneDial); //add application to the frame

      f.resize(150, 200); //resize frame

      f.show( ); //show frame

    }

}

    

class PhoneControls extends Panel

{

   Applet    appletParent;

   ButtonPad controls;

   TextField textPhone;

   Button    buttonDial;

   List      listPhone;

   public  PhoneControls(Applet appParent, String strPhBook)

   {

         appletParent= appParent;

     setLayout(new BorderLayout( ));

     htPhones = new Hashtable( ); //create a hash table for phone numbers

     listPhone = new List(5, false); //create a list to display names

          add(“East”, listPhone); //add list box control

     add(“North”, textPhone =  new TextField(“”, 12)); //create and add field for                                                         //the telephone number

     add(“West”, controls = new ButtonPad( ));//add button pad panel

     add(“South”, buttonDial =  new Button(“Dial”)); //create “Dial” button

   }

}

class ButtonPad extends Panel 

{

    public ButtonPad( )

    {

     //create GridBag layout with 4 rows and 3 columns, 1 pixel gap between      //elements

     GridLayout bag = new GridLayout(4,3, 1, 1);

     

     //set layout to ButtonPad panel

     setLayout(bag);

     

     for(int i= 0; i<12; i++)

     {

       //create a new button

       Button b = new Button(“ “);

       

       //set labels to button

       if (i<9)

         b.setLabel(“   “+String.valueOf(i+1)+”   “);

       else

          switch(i)

          {

           case 9: 

                    b.setLabel(“*”);

               break;

           case 10: 

                    b.setLabel(“0”);

               break;

                   case 11: 

                     b.setLabel(“#”);

               break;

          }

     //add button to the ButtonPad

     add(b);

    }

     

   }

}

Handling User Input

Now, when we have all of our controls in place, we can start adding some real functionality to our applet. First, we need to handle user input. We can do this by handling events that take place when the user pushes buttons or selects an item from the list box.

To do this we will create an Action()method in the PhoneControl applet. It will replace the default Action() method in the Control class that does nothing but pass event notification to the parent class. This function has two arguments. The first argument is the instance of the Event class that includes information about the type of the event, coordinates of the pointer, and event time stamp as well as a bunch of other useful data. The second argument is an event-dependent argument. For the push button events, this argument is a string with a button label that tell us which button causes the event to be fired.

The action method should return a true value when it processes an event, and no other action needs to be done based on this event. It should return a false value when the parent class needs to be notified in order to process the event again. For example, if we wanted to see which button was pressed in the ButtonPad class and at the same time wanted to handle the same push-the-button events in the PhoneControls class, we would implement the action method in the ButtonPad class so that it returned a false value on button notification events.

Here is the code that handles button events:

public boolean action(Event ev, Object arg)

{

          if (ev.target instanceof Button) 

          {

                   String label = (String)arg;

               if (label.equals(“Dial”))

                 DialPhone(textPhone.getText( ).trim( ));

               else

                 textPhone.setText(textPhone.getText( ).trim( )+label.trim( ));

                         

                   return true;

          }

}

First we determine what kind of event we are working with and whether this event is caused by pushing a dial button. We will call the function DialPhone( ) that will dial a phone number shown by textPhone control. Because the user can enter some spaces around the phone number, we want to trim them out before passing the argument to the DialPhone function. Don’t worry about the implementation for the DialPhone function at this time—we will code it later.

If the user selects a button from the button pad, we will append the label from this button to the phone number in textControl. This simply enters the data from the button pad into the phone number field.

Before writing the code that will handle the selection of the list box, we need to think how the phone numbers are stored in our application. Probably, we do not want to show both phone numbers and names at the same time in the listPhone control. It makes more sense to show just the name of the person or organization and leave the phone number information off-screen unless a particular item in the list is selected.

To store the association between names and phone numbers, we will use a hash table. We can populate it from the phone book file and then do a lookup in this table to find the phone number associated with the selected name. To use a hash table we need to import the java.util.Hashtable class into our project and include a variable of Hashtable type called htPhones into the PhoneControl class.

To handle events resulting from the phone number selection on the button pad, we will add the following code to the action method:

if (ev.target instanceof List) 

{

textPhone.setText((String)htPhones.get(listPhone.getSelectedItem())); 

       return true;

}

After detecting that the event was created by the list box control we look up the item that is selected on the listPhone. We then use the selected name to get the phone number associated with it from the hash table and pass this phone number to the textPhone control.

This is all we need to do to handle user input.

How to Get Names and Phone Numbers Over the Net

Our goal is to write a function that will get a document with phone information over the Net.

To create a network connection, we will need to create an instance of the URL class. There are several constructors for the URL class, and we will choose one with two arguments: base network address and relative address. For the base address we will use the address of our applet, which we can obtain through the call to the getDocumentBase() method of applet class. The relative address will be the actual name for the file we want to get and it will be an argument passed to our applet.

After creating a URL connection, we can open a stream to get access to the data.

The following code will open an input stream to the network file strPhoneBook:

//declare an input stream object

     InputStream is = null;

     //declare URL

     URL urlPhBook;

     try   

     {

          //open connection to file with name strPhoneBook

          urlPhBook = new URL(appletParent.getDocumentBase( ), strPhoneBook);

         

                    //open an input stream

            is =  urlPhBook.openStream( );

          /* 

                   *  Do something useful here

          */

                   //close input stream

                   is.close( );

     }

     catch (MalformedURLException e) 

     {

          //report exception

     }

Note that we have to catch and handle MalformedURLException in our application because the applet does not have a default handler for most network exceptions. We will not perform any detailed processing of the exception, but will just report it to the user.

Parsing Names and Phone Numbers

The file with names and phone numbers that we keep on the Net will have a very simple format. Each record in this file has two fields: a name or an address, and a phone number. Records will be separated by line separators, either carriage return or a combination of carriage return and line feed so that both UNIX and PC users can use their favorite text editors. Fields in a record will be separated by space or tab symbols. Also, we want to have comments in our file so we will ignore all lines starting with the # symbol and everything after double forward slashes. Here is an example of the phone file acceptable by the applet:

#Our simple phone book

work  (314) 994 1976

home (314) 863-6688

FAX  314-537-5542   // my work FAX number

To parse the file with phone records, we will use the StreamTokenizer class. StreamTokenizer incorporates a simple parser that will help us to split an input stream into the sequence of tokens. The tokenizer requires a buffered stream on the input so we need to construct a BufferedInputStream based on our InputStream class.

The following code creates a buffered input stream with 4KB of memory allocated for the buffer and an instance of the StreamTokenizer class called st.

StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(is, 4000));

Before the StreamTokenizer can do any useful jobs, we need to define what symbols will be acceptable as regular characters, how we want to designate comments, and whether we want to handle end-of-line symbols differently from others:

st.eolIsSignificant(true);       //end of line is a significant symbol

st.commentChar(‘#’);            //comments will start with ‘#’ symbol

st.slashSlashComments(true); //allow C++ -style comments (//)

st.wordChars(‘(‘, ‘)’);     //  ‘(‘ and  ‘)’ are regular characters

st.wordChars(‘-’, ‘z’);    //  ‘-’, numbers and letters are regular characters

Now we can write an input stream-parsing function that will put name information into the list control and phone numbers into the hash table, as follows:

int nCnt = 0;   //record counter

     htPhones.clear( ); //clear the hash table

 scan:

     while (true)  //main paring loop

          switch (st.nextToken( )) //what is our next token?

          {

           case StreamTokenizer.TT_EOF: //end of file

                 break scan;  //get out of the loop

           default: //unknown token

               break;

              case StreamTokenizer.TT_WORD: //word (any sequence of                                                   //characters from the union of                                                  //intervals 0..9, A-Z, a-z, or                                                  //characters ‘)’, ‘(‘ or ‘-’)

               String strRecord = st.sval; //text: name or address

               String strValue = “”;

               st.nextToken();  //get next token

               while (st.ttype != StreamTokenizer.TT_EOL &&

                       st.ttype != StreamTokenizer.TT_EOF) //parse to the end of line or to the                                             //end of file - whichever comes first

               {  

                    if (st.ttype == StreamTokenizer.TT_WORD)  //text characters from the                                                     //phone number: ‘-’, ‘(‘ or ‘)’                                                     //symbols

                 {

                         strValue = strValue + st.sval;

                 }

                 else 

                   if (st.ttype == StreamTokenizer.TT_NUMBER) //numbers from the                                                               //phone number

                   {

                       strValue = strValue + String.valueOf(st.nval);

                   } 

                 st.nextToken( );

               }

               nCnt++; //increment phone records counter 

               lb.addItem(strRecord, nCnt); //add name or address to the list box

               htPhones.put(strRecord, strValue); //add phone number to the hash                                                   //table

          

               break; //parse next record

          }//end of parsing loop

It’s Time to Dial a Number—the DialPhone( ) Function

The only major piece of code we need to write at this point is the DialPhone() function. This function is called when a user presses the Dial button. The only argument for this function is the phone number the user wants to dial. This function should play the DTMF tones corresponding to this number.

The DTMF signal is a direct algebraic summation of the amplitudes of two waves of different frequencies. For instance, 1 is coded as the sum of the 1209 Hz and 697 Hz signals. A full list of DTMF tones is shown in Table 26.1. We do not want to generate and mix tones on the sound card, so we will use prerecorded audio files with DTMF signals. It is possible to use WaveGen or a similar sound file generating program to generate these files. Assume that you already have audio files and have placed those files in the /audio/ subdirectory.

Table 26.1. DTMF tones.

Telephone key High tone [Hz] Low tone [Hz] Filename
0 1336 941 0.au
1 1209 697 1.au
21336 697 2.au
3 1477 697 3.au
4 1209 770 4.au
5 1336 770 5.au
6 1477 770 6.au
7 1209 852 7.au
8 1336 852 8.au
9 1477 852 9.au
* 1209 941 star.au
# 1477 941 pound.au

To play a DTMF sequence corresponding to a telephone number, we want to separate the string with the telephone number into the array of characters and then play the sequence of audio clips with tones based on the appropriate characters.

To separate a string Phone into array sepPhone[], we will use the getChars( ) function from the String class:

char sepPhone[];

sepPhone =  new char [phone.length( )];

phone.getChars(0, phone.length( ), sepPhone, 0);

To play an audio clip from the Java applet you need to call the play( ) function, which takes two arguments: the URL that specifies the directory on the Web server with the audio file and the string with the name of the audio file. To get the URL we can call getCodeBase( ), which returns the URL of our applet. The filename we use is based on the telephone key we want to play.

Of course, we do not want to play anything other than the keys from the telephone panel, so we ignore all of the characters from the sepPhone array other than numbers or * and # characters.

for (int i = 0; i < phone.length( ); i++)  //loop throughout all keys from sepPhone                                           //array

{

   if ((sepPhone[i] >= ‘0’) && (sepPhone[i] <= ‘9’)) //if we have a valid numeric                                                      //key    

       appletParent.play(appletParent.getCodeBase( ), “audio/”+sepPhone[i]+”.au”);  //play one of files 0.au to 9.au base on sepPhone[i] character

   else if (sepPhone[i] == ‘*’) //star key

       appletParent.play(appletParent.getCodeBase( ), “audio/star.au”);   //play star.au file

          else if (sepPhone[i] == ‘#’) //pound key

            appletParent.play(appletParent.getCodeBase( ), “audio/pound.au”);  //play pound.au file

}

Add Information Functions

Like in an auto body shop when the work is almost done, a little more effort needs to be done to make the results look nice. For our application, we will add getAppletInfo( ) and getParameterInfo( ) functions, and add functions to show the current application status—it always pays to be nice to users.

The function getAppletInfo( ) should return a string with copyright, version, and author information. It potentially could be used by Internet browsers to identify applets that could cause problems and reject them. The code is as follows:

public String getAppletInfo( )

{

    return “Phone Book and Dialer. Copyright (C) 1995, 1996 Gene Leybzon”;

}

The function getParameterInfo( ) returns a two-dimensional string array with a description of applet arguments. Each row of this array has a parameter name, type, and description. Because we have just one parameter for our applet, we will return the 1-by-3 array, as follows:

public String[][] getParameterInfo( )

{

       String[][] info = 

       {

         {“phonebook”,      “url”,           “phone directory file”}

       };

       return info;

}

To show applet messages we will use the ShowStatus( ) function that takes a string and puts it into the Applet context. Depending on the Internet browser this information could be shown as a browser information panel or in a separate window with the Java applet log.

Add some more comments and we are done. Listing 26.2 contains the final revision of PhoneDial applet source code.

/* Phone Book Applet

 */

import java.awt.*;

import java.applet.*;

import java.io.StreamTokenizer;

import java.io.InputStream;

import java.io.BufferedInputStream;

import java.net.URL;

import java.net.MalformedURLException;

import java.util.Hashtable;

public class PhoneDial extends Applet {

/* Phone Book applet */     

    PhoneControls controls;

    public void init( )

    {

         String strParam = getParameter(“PHONEBOOK”);     

         String strPhoneBook = (strParam == null) ? “phonebook.html” : strParam;

     

         setLayout(new BorderLayout( ));

         controls = new PhoneControls(this, strPhoneBook);

         add(“Center”, controls);

    }

    public void start( )

    {

          controls.enable( );

    }

    public void stop( ) 

    {

          controls.disable( ) 

    }

    public String getAppletInfo( )

    {

          return “Phone Book and Dialer. Copyright (C) Gene Leybzon, 1995, 1996”;

    }

    public String[][] getParameterInfo( )

    {

       String[][] info = 

       {

         {“phonebook”,      “url”,           “phone directory file”},

       };

       return info;

    }

    public boolean handleEvent(Event e)

    {

       if (e.id == Event.WINDOW_DESTROY)

       {

         System.exit(0);

       }

       return false;

    }

    public static void main(String args[]) 

    {

      Frame f = new Frame(“PhoneDial”);

      PhoneDial     phoneDial = new PhoneDial( );

      phoneDial.init( );

      phoneDial.start( );

      f.add(“Center”, phoneDial);

      f.resize(150, 200);

      f.show( );

    }

}

    

class PhoneControls extends Panel

/* Phone Book Controls */

{

   Applet    appletParent;

   ButtonPad controls;

   TextField textPhone;

   Button    buttonDial;

   List      listPhone;

   Hashtable htPhones;   

   public  PhoneControls(Applet appParent, String strPhBook)

   {

     appletParent= appParent;

     setLayout(new BorderLayout( ));

     htPhones = new Hashtable( );

     listPhone = new List(5, false);

     add(“East”, listPhone);

     FillListBox(listPhone, strPhBook);

     listPhone.select(1);

     add(“North”, textPhone =  new TextField(“”, 12));

     add(“West”, controls = new ButtonPad());

     add(“South”, buttonDial =  new Button(“Dial”));

   }

   public boolean action(Event ev, Object arg) 

   {

     if (ev.target instanceof Button) 

     {

          String label = (String)arg;

          if (label.equals(“Dial”))

             DialPhone(textPhone.getText( ).trim( ));

          else

             textPhone.setText(textPhone.getText( ).trim( )+label.trim( ));

                         

          return false;

     }

     if (ev.target instanceof List)

     {

             textPhone.setText((String)htPhones.get(listPhone.getSelectedItem( )));

             return false;

     }

     return false;

   }

    public void DialPhone(String phone)

    /* Play DTMF tone sequence */

    {

       char sepPhone[];

       sepPhone =  new char [phone.length( )];

       phone.getChars(0, phone.length( ), sepPhone, 0);

       

       appletParent.showStatus(“Dial in progress ...” + phone);

       for (int i = 0; i < phone.length( ); i++)

       {

         if ((sepPhone[i] >= ‘0’) && (sepPhone[i] <= ‘9’))

         {

           appletParent.play(appletParent.getCodeBase( ) ,“audio”+sepPhone[i]+”.au”);

         }

         else 

           if (sepPhone[i] == ‘*’)

             appletParent.play(appletParent.getCodeBase( ), “audio/star.au”);     

         else 

           if (sepPhone[i] == ‘#’)

                appletParent.play(appletParent.getCodeBase( ), “audio/pound.au”);     

       }

    }

    public void FillListBox(List lb, String strPhoneBook)

    /* Get document strPhoneBook from the net and fill list box control */

    {

     InputStream is = null;

          

     URL urlPhBook;

     try 

     {

     urlPhBook = new URL(appletParent.getDocumentBase( ), strPhoneBook);

     try

     {

     is =  urlPhBook.openStream( );

     StreamTokenizer st = new StreamTokenizer(new BufferedInputStream(is, 4000));

     st.eolIsSignificant(true);

     st.commentChar(‘#’);

     st.slashSlashComments(true); 

     st.wordChars(‘(‘, ‘)’);

     st.wordChars(‘-’, ‘z’);

 

     int nCnt = 0;

     htPhones.clear( );

 scan:

      while (true)

          switch (st.nextToken( )) 

          {

           case StreamTokenizer.TT_EOF:

                                 break scan;

           default:

                           break;

           case StreamTokenizer.TT_WORD:

               String strRecord = st.sval;

               String strValue = “”;

               st.nextToken();

               while (st.ttype != StreamTokenizer.TT_EOL &&

                         st.ttype != StreamTokenizer.TT_EOF)

               {  

                 if (st.ttype == StreamTokenizer.TT_WORD) 

                 {

                         strValue = strValue + st.sval;

                 }

                 else 

                   if (st.ttype == StreamTokenizer.TT_NUMBER)

                   {

                       strValue = strValue + String.valueOf(st.nval);

                   } 

                 st.nextToken( );

               }

               nCnt++;

               lb.addItem(strRecord, nCnt);

               htPhones.put(strRecord, strValue);

          

               break;

            }

          is.close( );

     }

     

     catch(Exception e)

     {

       String message = e.toString();

       appletParent.showStatus(“Exception ...” + message);

     }

     }

     

     catch (MalformedURLException e) 

     {

           String message = e.toString( );

           appletParent.showStatus(“Exception ...” + message);

     }

     }

}

class ButtonPad extends Panel 

/* Telephone button pad controls */

{

    public ButtonPad( )

    {

     GridLayout bag = new GridLayout(4,3, 1, 1);

     setLayout(bag);

     for(int i= 0; i<12; i++)

     {

       Button b = new Button(“ “);

       if (i<9)

          b.setLabel(“   “+String.valueOf(i+1)+”   “);

       else

          switch(i)

          {

           case 9: 

               b.setLabel(“*”);

               break;

           case 10: 

               b.setLabel(“0”);

               break;

           case 11: 

               b.setLabel(“#”);

               break;

          }

          add(b);

     }

    }

}

Summary

In this chapter we get through the process of designing and implementing a real-world Java application — telephone book and phone number dialer. We have used Java AWT library to create a user interface, and Java applet methods to get information from the Internet and play sound files. Other topics we have discussed include interface layout management, input stream parsing, and event handling.


Previous Page TOC Index Next Page