home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 10 / ioProg_10.iso / soft / platsdk / inetwork.exe / TAPI-S.cab / 99jt3rec.java < prev    next >
Encoding:
Java Source  |  1997-09-10  |  25.4 KB  |  726 lines

  1. /************************************************************************
  2.  * JT3Rec (by John W. Gibbs)
  3.  *
  4.  * Copyright (c) 1997 Microsoft Corporation, All Rights Reserved.
  5.  ***********************************************************************/
  6.  
  7. import java.awt.*;
  8. import java.applet.*;
  9. import java.util.*;
  10. import com.ms.com.*;
  11. import com.ms.ui.*;
  12. import tapi3.*;
  13. import AppCtrls;
  14.  
  15.  
  16. /////////////////////////////////////////////////////////////////////////
  17. //  CLASS: JT3Rec
  18. //
  19. //  PURPOSE: TAPI 3.0 test program
  20. //  DATE:    July 17, 1997
  21. //
  22. //  DESCRIPTION:
  23. //      Applet/application that allow the user to answer incoming calls
  24. //      using TAPI 3.0.
  25. //
  26. /////////////////////////////////////////////////////////////////////////
  27.  
  28. public class JT3Rec extends Applet
  29.     implements TapiConstants,       // misc. constants
  30.                DISCONNECT_CODE      // DC_xxx constants
  31. {
  32.     // Application name.
  33.     public static final String s_strAppName = "Java TAPI 3.0 Receiver";
  34.  
  35.     // True if running as stand alone app.
  36.     public boolean m_fStandAlone = false;
  37.  
  38.     // Parent frame of the app.
  39.     private Frame m_ParentFrame = null;
  40.  
  41.     // Resource Wizard generated UI.
  42.     public final AppCtrls ctrls = new AppCtrls(this);
  43.  
  44.     // Main interface to the TAPI component.
  45.     private ITTAPI m_Tapi = null;
  46.  
  47.     // The currently connected call or null if there isn't one.
  48.     public ITBasicCallControl m_Call = null;
  49.  
  50.     // Stores mediatype identifiers (string GUIDs) for the mediatypes
  51.     // in the mediatypes listbox.  If a mediatype is supported by a
  52.     // local address then it will be on this list.
  53.     private Vector m_MediaTypes = new Vector();
  54.  
  55.     // Collection of CallNot objects.  One notifier is created for each
  56.     // address when the Listen button is pressed.  The notifier will
  57.     // be called by TAPI 3.0 when an incoming call arrives.
  58.     private Vector m_CallNotifiers = new Vector();
  59.  
  60.  
  61.     /////////////////////////////////////////////////////////////////////
  62.     // init
  63.     //
  64.     // Performs applet initialization.
  65.     /////////////////////////////////////////////////////////////////////
  66.     public void init()
  67.     {
  68.         // select a font to use (ctrls needs this)
  69.         Font font = new Font("Dialog", Font.PLAIN, 8);
  70.         this.setFont(font);
  71.  
  72.         // setup the UI generated by the Resource Wizard
  73.         ctrls.CreateControls();
  74.         ctrls.lstMediaTypes.setMultipleSelections(true);
  75.         ctrls.tfStatusBox.setEditable(false);
  76.         DisableControls();
  77.         if (m_fStandAlone) {
  78.             ctrls.btnClose.enable();
  79.         }
  80.  
  81.         // get parent frame to use for message boxes
  82.         Container parent = getParent();
  83.         while ((parent != null) && (!(parent instanceof Frame))) {
  84.             parent = parent.getParent();
  85.         }
  86.         m_ParentFrame = (Frame) parent;
  87.  
  88.         // resize the frame if running as standalone app
  89.         if (m_fStandAlone) {
  90.             m_ParentFrame.pack();
  91.             m_ParentFrame.setResizable(false);
  92.         }
  93.  
  94.         // initialize TAPI component
  95.         SetStatusMessage("Initializing TAPI 3.0...");
  96.         try {
  97.             m_Tapi = new TAPI();
  98.             m_Tapi.Initialize();
  99.         }
  100.         catch (ComException e) {
  101.             DoMessage("Fatal Error: Could not initialize TAPI 3.0");
  102.             m_Tapi = null;
  103.             if (m_fStandAlone) {
  104.                 System.exit(0);
  105.             }
  106.             else {
  107.                 SetStatusMessage("Could not initialize TAPI 3.0");
  108.                 return;
  109.             }
  110.         }
  111.  
  112.         // get initial data and display it
  113.         SetStatusMessage("Enumerating mediatypes...");
  114.         if (!EnumerateMediaTypes()) {
  115.             DoMessage("Warning: Enumeration of mediatypes failed on some address(es)");
  116.         }
  117.         SetStatusMessage("Ready");
  118.  
  119.         // app initialized... enable controls
  120.         ctrls.lstMediaTypes.enable();
  121.         ctrls.btnListen.enable();
  122.     }
  123.  
  124.     /////////////////////////////////////////////////////////////////////
  125.     // stop
  126.     //
  127.     // Called when the user leaves the applet's webpage.
  128.     /////////////////////////////////////////////////////////////////////
  129.     public void stop()
  130.     {
  131.         StopListeningForCalls();
  132.  
  133.         if (m_Call != null) {
  134.             DisconnectTheCall(DC_NORMAL);
  135.         }
  136.  
  137.         ctrls.btnStop.disable();
  138.         ctrls.btnHangup.disable();
  139.         ctrls.btnListen.enable();
  140.         ctrls.lstMediaTypes.enable();
  141.         SetStatusMessage("Ready");
  142.     }
  143.  
  144.     /////////////////////////////////////////////////////////////////////
  145.     // destroy
  146.     //
  147.     // Called when the applet is destroyed by the browser.
  148.     /////////////////////////////////////////////////////////////////////
  149.     public void destroy()
  150.     {
  151.         try {
  152.             if (m_Tapi != null) {
  153.                 m_Tapi.Shutdown();
  154.             }
  155.         }
  156.         catch (ComException e) {
  157.             e.printStackTrace();
  158.             DoMessage("An error occurred while trying to shutdown TAPI");
  159.         }
  160.     }
  161.  
  162.     /////////////////////////////////////////////////////////////////////
  163.     // action
  164.     //
  165.     // Event.ACTION_EVENT event handler.
  166.     /////////////////////////////////////////////////////////////////////
  167.     public boolean action(Event evt, Object arg)
  168.     {
  169.         if (arg.equals("Listen")) {
  170.             // listen button pressed
  171.             if (StartListeningForCalls()) {
  172.                 ctrls.btnListen.disable();
  173.                 ctrls.btnStop.enable();
  174.                 ctrls.lstMediaTypes.disable();
  175.                 SetStatusMessage("Listening for incoming calls");
  176.             }
  177.             else {
  178.                 DoMessage("Could not start listening");
  179.                 SetStatusMessage("Calls are not being monitored");
  180.             }
  181.         }
  182.         else if (arg.equals("Stop")) {
  183.             // stop button pressed
  184.             StopListeningForCalls();
  185.             ctrls.btnListen.enable();
  186.             ctrls.btnStop.disable();
  187.             ctrls.lstMediaTypes.enable();
  188.             SetStatusMessage("Calls are not being monitored");
  189.         }
  190.         else if (arg.equals("Answer")) {
  191.             // answer button pressed
  192.             if (AnswerTheCall()) {
  193.                 ctrls.btnStop.disable();
  194.                 ctrls.btnHangup.enable();
  195.                 SetStatusMessage("Connected");
  196.             }
  197.             else {
  198.                 ctrls.btnStop.enable();
  199.                 DoMessage("The call could not be answered");
  200.                 SetStatusMessage("Listening for incoming calls");
  201.             }
  202.             ctrls.btnAnswer.disable();
  203.             ctrls.btnReject.disable();
  204.  
  205.         }
  206.         else if (arg.equals("Reject")) {
  207.             // reject button pressed
  208.             if (DisconnectTheCall(DC_REJECTED)) {
  209.                 DoMessage("The call has been rejected");
  210.             }
  211.             else {
  212.                 DoMessage("An error occurred while rejecting the " +
  213.                           "call, but it will be ignored");
  214.             }
  215.             ctrls.btnAnswer.disable();
  216.             ctrls.btnReject.disable();
  217.             ctrls.btnStop.enable();
  218.             SetStatusMessage("Listening for incoming calls");
  219.         }
  220.         else if (arg.equals("Hangup")) {
  221.             // hangup button pressed
  222.             if (DisconnectTheCall(DC_NORMAL)) {
  223.                 DoMessage("The call has been disconnected");
  224.             }
  225.             else {
  226.                 DoMessage("An error occurred while disconnecting, " +
  227.                           "but it will be ignored");
  228.             }
  229.             ctrls.btnHangup.disable();
  230.             ctrls.btnStop.enable();
  231.             SetStatusMessage("Listening for incoming calls");
  232.         }
  233.         else if (arg.equals("Close")) {
  234.             // close button pressed.  This button is enabled only when
  235.             // running as an application.  Since a browser would close
  236.             // the applet by calling stop and destroy, we should also.
  237.             this.stop();
  238.             this.destroy();
  239.             System.exit(0);
  240.         }
  241.         else
  242.             return super.action(evt, arg);
  243.         return true;
  244.     }
  245.  
  246.     /////////////////////////////////////////////////////////////////////
  247.     // EnumerateMediaTypes
  248.     //
  249.     // Finds all mediatypes supported by local addresses and adds their
  250.     // description to the mediatypes listbox and their string GUID
  251.     // itentifiers to the m_MediaTypes vector.
  252.     /////////////////////////////////////////////////////////////////////
  253.     private boolean EnumerateMediaTypes()
  254.     {
  255.         Variant        var;
  256.         ITCollection   itcAddr, itcMedia;
  257.         ITAddress      address;
  258.         ITMediaSupport mediaSupp;
  259.         String         mediaType;
  260.  
  261.         m_MediaTypes.removeAllElements();
  262.  
  263.         try {
  264.             // get the collection interface for addresses
  265.             var = m_Tapi.getAddresses();
  266.             itcAddr = (ITCollection) var.toDispatch();
  267.             
  268.             // Walk through the collection.  Note that collections start
  269.             // at index 1 and end at index itc.getCount().
  270.             for (int i=1; i <= itcAddr.getCount(); i++) {
  271.                 // get the next address
  272.                 var = itcAddr.getItem(i);
  273.                 address = (ITAddress) var.toObject();
  274.                 mediaSupp = (ITMediaSupport) address;
  275.  
  276.                 // get the collection interface for mediatypes
  277.                 var = mediaSupp.getMediaTypes();
  278.                 itcMedia = (ITCollection) var.toDispatch();
  279.                 
  280.                 for (int j=1; j <= itcMedia.getCount(); j++) {
  281.                     // get the next mediatype
  282.                     mediaType = itcMedia.getItem(j).toString();
  283.  
  284.                 // NOTE: currently java receiver applet has only 
  285.                 //       audio media type enabled for beta1
  286.  
  287.                     if (mediaType.equals(TAPIMEDIATYPE_String_VideoIn)||
  288.             mediaType.equals(TAPIMEDIATYPE_String_VideoOut))
  289.                         continue;
  290.                     
  291.                     // display the media name and store its string GUID,
  292.                     // if we haven't already
  293.                     if (!m_MediaTypes.contains(mediaType)) {
  294.                         ctrls.lstMediaTypes.addItem(GetMediaName(mediaType));
  295.                         m_MediaTypes.addElement(mediaType);
  296.                     }
  297.                 }
  298.             }
  299.             return true;
  300.         }
  301.         catch (ComException e) {
  302.             e.printStackTrace();
  303.             return false;
  304.         }
  305.     }
  306.  
  307.     /////////////////////////////////////////////////////////////////////
  308.     // StartListeningForCalls
  309.     //
  310.     // Takes the selected mediatypes and sets all addresses to listen
  311.     // for incoming calls using those mediatypes.  If at least one
  312.     // address succeeds to start listening then true is returned,
  313.     // otherwise, false is returned.
  314.     /////////////////////////////////////////////////////////////////////
  315.     public boolean StartListeningForCalls()
  316.     {
  317.         Variant        var;
  318.         ITCollection   itc;
  319.         ITAddress      address;
  320.         ITMediaSupport mediaSupp;
  321.         int[]          indexes;
  322.         Object         temp;
  323.         Vector         mediaTypes = new Vector();
  324.         boolean        isListening = false;
  325.  
  326.         try {
  327.             // get indexes for selected mediatypes
  328.             indexes = ctrls.lstMediaTypes.getSelectedIndexes();
  329.  
  330.             // get the collection interface for addresses
  331.             var = m_Tapi.getAddresses();
  332.             itc = (ITCollection) var.toDispatch();
  333.             
  334.             for (int i=1; i <= itc.getCount(); i++) {
  335.                 // get the next address
  336.                 var = itc.getItem(i);
  337.                 address = (ITAddress) var.toObject();
  338.                 mediaSupp = (ITMediaSupport) address;
  339.  
  340.                 // retrieve mediatypes supported by the current address
  341.                 for (int j=0; j < indexes.length; j++) {
  342.                     temp = m_MediaTypes.elementAt(indexes[j]);
  343.                     if (mediaSupp.QueryMediaType((String) temp)) {
  344.                         mediaTypes.addElement(temp);
  345.                     }
  346.                 }
  347.  
  348.                 if (ListenOnThisAddress(address, mediaTypes)) {
  349.                     isListening = true;
  350.                 }
  351.  
  352.                 mediaTypes.removeAllElements();
  353.             }
  354.             return isListening;
  355.         }
  356.         catch (ComException e) {
  357.             e.printStackTrace();
  358.             return isListening;
  359.         }
  360.     }
  361.  
  362.     /////////////////////////////////////////////////////////////////////
  363.     // ListenOnThisAddress
  364.     //
  365.     // Performs the steps involved in setting up an address to listen
  366.     // for calls. Setting up an application to listen for calls is a
  367.     // two step process.
  368.     //
  369.     // First, the app must call RegisterCallTypes on the address that
  370.     // it wants calls on.  This will tell the address which mediatypes
  371.     // it should listen for.
  372.     //
  373.     // Second, it must register it's implementation of the
  374.     // ITCallNotification interface with the address.  This interface
  375.     // specifies only one method, CallEventNotification, which is called
  376.     // by TAPI whenever a call event occurs.
  377.     /////////////////////////////////////////////////////////////////////
  378.     public boolean ListenOnThisAddress(ITAddress address, Vector mediaTypes)
  379.     {
  380.         SafeArray                 sa;
  381.         Variant                   var;
  382.         IConnectionPointContainer cpc;
  383.         IConnectionPoint[]        cp = new IConnectionPoint[1];
  384.         CallNot                   callnot;
  385.         int[]                     dwCookie = new int[1];
  386.         
  387.         if (address == null || !address.getServiceProviderName().equals("h323.tsp") ||
  388.             mediaTypes == null || mediaTypes.size() == 0)
  389.             return false;
  390.  
  391.         try {
  392.             // RegisterCallTypes expects the mediatypes to be placed into
  393.             // a safearray and the safearray into a variant.  If null is
  394.             // specified for the array, the address will listen for all
  395.             // of its supported mediatypes.
  396.  
  397.             sa = new SafeArray(Variant.VariantString, mediaTypes.size());
  398.  
  399.             for (int i=0; i < mediaTypes.size(); i++) {
  400.                 sa.setString(i, (String) mediaTypes.elementAt(i));
  401.             }
  402.  
  403.             var = new Variant(sa, false);
  404.  
  405.             address.RegisterCallTypes(
  406.                         false,  // msgs for outgoing calls
  407.                         true,   // want to be owner
  408.                         false,  // don't want to be monitor
  409.                         var     // array of owner mediatypes
  410.                         );
  411.  
  412.             // find the connection point for the ITCallNotification
  413.             // interface.  Refer to the COM ConnectionPoint documentation
  414.             // for more details.
  415.             cpc = (IConnectionPointContainer) address;
  416.             cpc.FindConnectionPoint(ITCallNotification.iid, cp);
  417.  
  418.             callnot = new CallNot(this);
  419.  
  420.             // if the Advise method succeeds, then the address will start
  421.             // listening for calls.
  422.             cp[0].Advise(
  423.                         callnot,    // sink object
  424.                         dwCookie    // connection handle (retval)
  425.                         );
  426.  
  427.             // we save the call notification object.  When we release
  428.             // it, call notification will stop.  Normally we would also
  429.             // save the dwCookie value but since TAPI 3.0 does not
  430.             // support Unadvise for the ITCallNotification interface,
  431.             // we can safely discard it.
  432.             m_CallNotifiers.addElement(callnot);
  433.             return true;
  434.         }
  435.         catch (Exception e) {
  436.             e.printStackTrace();
  437.             return false;
  438.         }
  439.     }
  440.  
  441.     /////////////////////////////////////////////////////////////////////
  442.     // StopListeningForCalls
  443.     //
  444.     // Sets all addresses to ignore incoming calls.  To ignore incoming
  445.     // calls we release the call notification objects for each address.
  446.     /////////////////////////////////////////////////////////////////////
  447.     public void StopListeningForCalls()
  448.     {
  449.         m_CallNotifiers.removeAllElements();
  450.  
  451.         // force a garbage collect.  This will ensure that the
  452.         // notification objects are released.
  453.         System.gc();
  454.     }
  455.  
  456.     /////////////////////////////////////////////////////////////////////
  457.     // AnswerTheCall
  458.     //
  459.     // Answers the incoming call.
  460.     /////////////////////////////////////////////////////////////////////
  461.     public boolean AnswerTheCall()
  462.     {
  463.         ITAddress       address;
  464.         ITMediaSupport  mediaSupp;
  465.         int[]           indexes;
  466.         String          temp;
  467.         Vector          mediaTypes = new Vector();
  468.         SafeArray       sa;
  469.         ITMediaTerminal mediaTerm;
  470.         Variant         var;
  471.  
  472.         if (m_Call == null)
  473.             return false;
  474.  
  475.         try {
  476.             // get local address participating in the call
  477.             address = ((ITCallInfo) m_Call).getAddress();
  478.             
  479.             // get the media support interface on the address
  480.             mediaSupp = (ITMediaSupport) address;
  481.  
  482.             // get indexes for selected mediatypes
  483.             indexes = ctrls.lstMediaTypes.getSelectedIndexes();
  484.  
  485.             // filter those supported by the current address
  486.             for (int i=0; i < indexes.length; i++) {
  487.                 temp = (String) m_MediaTypes.elementAt(indexes[i]);
  488.                 if (mediaSupp.QueryMediaType(temp)) {
  489.                     mediaTypes.addElement(temp);
  490.                 }
  491.             }
  492.  
  493.             // create a safearray to put the media-terminals into
  494.             sa = new SafeArray(Variant.VariantObject, mediaTypes.size());
  495.  
  496.             // create media-terminals, package each in a variant, and
  497.             // store them in the safearray
  498.             for (int i=0; i < mediaTypes.size(); i++) {
  499.                 mediaTerm = GetMediaTerminal(address, (String) mediaTypes.elementAt(i));
  500.                 if (mediaTerm != null) {
  501.                     sa.setVariant(i, new Variant(
  502.                                                 Variant.VariantObject,
  503.                                                 mediaTerm
  504.                                                 ));
  505.                 }
  506.             }
  507.  
  508.             // put the safearray in a variant
  509.             var = new Variant(sa, false);
  510.  
  511.             // select the media-terminals and answer
  512.             m_Call.SelectMediaTerminals(var);
  513.             m_Call.Answer();
  514.             return true;
  515.         }
  516.         catch (Exception e) {
  517.             e.printStackTrace();
  518.             return false;
  519.         }
  520.     }
  521.  
  522.     /////////////////////////////////////////////////////////////////////
  523.     // DisconnectTheCall
  524.     //
  525.     // Disconnects the call using the given disconnect code.
  526.     /////////////////////////////////////////////////////////////////////
  527.     public boolean DisconnectTheCall(int code)
  528.     {
  529.         ITBasicCallControl call;
  530.  
  531.         if (m_Call == null)
  532.             return true;
  533.  
  534.         call = m_Call;
  535.  
  536.         try {
  537.             // during the call to Disconnect, the call notifier will
  538.             // receive a CS_DISCONNECTED state.  To indicate that
  539.             // Disconnect has already been called on the local side we
  540.             // set m_Call to null (see CallNot for details).
  541.             m_Call = null;
  542.             call.Disconnect(code);
  543.             return true;
  544.         }
  545.         catch (ComException e) {
  546.             e.printStackTrace();
  547.             return false;
  548.         }
  549.         finally {
  550.             call = null;
  551.  
  552.             // force a garbage collect.  This will ensure that terminals
  553.             // get released (unless you have references to them!), etc.
  554.             // If you do not do this you may have effects such as video
  555.             // windows lingering after a call has disconnected.
  556.             System.gc();
  557.         }
  558.     }
  559.  
  560.     /////////////////////////////////////////////////////////////////////
  561.     // GetMediaTerminal
  562.     //
  563.     // Returns a media-terminal for the given mediatype on the specified
  564.     // address.  Media-terminals are the association of a terminal
  565.     // (static or dynamic) and the mediatype that it will use.
  566.     //
  567.     // The only dynamic terminal supported by this method is the video
  568.     // window terminal.
  569.     /////////////////////////////////////////////////////////////////////
  570.     public ITMediaTerminal GetMediaTerminal(
  571.                                            ITAddress address,
  572.                                            String mediaType
  573.                                            )
  574.     {
  575.         ITTerminalSupport termSupp;
  576.         ITTerminal        terminal;
  577.         String             VideoWindowMediaType;
  578.  
  579.         if (address == null || mediaType == null)
  580.             return null;
  581.  
  582.         try {
  583.             termSupp = (ITTerminalSupport) address;
  584.  
  585.             if (mediaType.equals(TAPIMEDIATYPE_String_VideoIn)) {
  586.                 terminal = termSupp.CreateTerminal(CLSID_String_VideoWindowTerm);
  587.             }
  588.             else {
  589.                 terminal = termSupp.GetDefaultTerminal(mediaType);
  590.             }
  591.  
  592.             // terminal could be null here and CreateMediaTerminal
  593.             // will not complain about it (ie, "null terminals" are
  594.             // valid).  We do not want any null terminals.
  595.             if (terminal == null)
  596.                 return null;
  597.  
  598.             return m_Tapi.CreateMediaTerminal(mediaType, terminal);
  599.         }
  600.         catch (ComException e) {
  601.             e.printStackTrace();
  602.             return null;
  603.         }
  604.     }
  605.  
  606.     /////////////////////////////////////////////////////////////////////
  607.     // GetMediaName
  608.     //
  609.     // Returns a descriptive name for the given mediatype.
  610.     /////////////////////////////////////////////////////////////////////
  611.     public String GetMediaName(String mediaType)
  612.     {
  613.         if (mediaType.equals(TAPIMEDIATYPE_String_AudioOut))
  614.             return "Audio Out";
  615.  
  616.         if (mediaType.equals(TAPIMEDIATYPE_String_AudioIn))
  617.             return "Audio In";
  618.  
  619.         if (mediaType.equals(TAPIMEDIATYPE_String_VideoOut))
  620.             return "Video Out";
  621.  
  622.         if (mediaType.equals(TAPIMEDIATYPE_String_VideoIn))
  623.             return "Video In";
  624.  
  625.         if (mediaType.equals(TAPIMEDIATYPE_String_DataModem))
  626.             return "Data Modem";
  627.  
  628.         if (mediaType.equals(TAPIMEDIATYPE_String_G3Fax))
  629.             return "Group III Fax";
  630.  
  631.         return "Unknown mediatype"; // just in case
  632.     }
  633.  
  634.     /////////////////////////////////////////////////////////////////////
  635.     // DisableControls
  636.     //
  637.     // Disables all of the app's controls.
  638.     /////////////////////////////////////////////////////////////////////
  639.     private void DisableControls()
  640.     {
  641.         ctrls.lstMediaTypes.disable();
  642.         ctrls.btnListen.disable();
  643.         ctrls.btnStop.disable();
  644.         ctrls.btnAnswer.disable();
  645.         ctrls.btnReject.disable();
  646.         ctrls.btnHangup.disable();
  647.         ctrls.btnClose.disable();
  648.     }
  649.  
  650.     /////////////////////////////////////////////////////////////////////
  651.     // SetStatusMessage
  652.     //
  653.     // Displays messages in the status box.
  654.     /////////////////////////////////////////////////////////////////////
  655.     public synchronized void SetStatusMessage(String msg)
  656.     {
  657.         ctrls.tfStatusBox.setText(msg);
  658.     }
  659.  
  660.     /////////////////////////////////////////////////////////////////////
  661.     // DoMessage
  662.     //
  663.     // Displays messages in a message box.
  664.     /////////////////////////////////////////////////////////////////////
  665.     private void DoMessage(String msg)
  666.     {
  667.         AwtUIMessageBox msgbox = new AwtUIMessageBox(
  668.                                             m_ParentFrame,
  669.                                             s_strAppName,
  670.                                             msg,
  671.                                             AwtUIMessageBox.EXCLAMATION,
  672.                                             UIButtonBar.OK
  673.                                             );
  674.         msgbox.doModal();
  675.     }
  676.  
  677.     /////////////////////////////////////////////////////////////////////
  678.     // main
  679.     //
  680.     // Standalone application entry point.  Not called for applets.
  681.     /////////////////////////////////////////////////////////////////////
  682.     public static void main(String[] args)
  683.     {
  684.         JT3Rec applet = new JT3Rec();
  685.  
  686.         AppFrame frame = new AppFrame(s_strAppName, applet);
  687.         frame.show();
  688.  
  689.         applet.m_fStandAlone = true;
  690.         applet.init();
  691.     }
  692. }
  693.  
  694.  
  695. ////////////////////////////////////////////////////////////////////////////////
  696. //  CLASS: AppFrame
  697. //
  698. //  DESCRIPTION:
  699. //      Frame for standalone application.
  700. //
  701. ////////////////////////////////////////////////////////////////////////////////
  702.  
  703. class AppFrame extends Frame
  704. {
  705.     private Applet m_App = null;
  706.  
  707.     public AppFrame(String title, Applet applet)
  708.     {
  709.         super(title);
  710.         m_App = applet;
  711.         this.add(applet);
  712.     }
  713.  
  714.     public boolean handleEvent(Event evt)
  715.     {
  716.         if (evt.id == Event.WINDOW_DESTROY) {
  717.             // since a browser would close the applet by calling stop and
  718.             // destroy, we should also.
  719.             m_App.stop();
  720.             m_App.destroy();
  721.             System.exit(0);
  722.         }
  723.  
  724.         return super.handleEvent(evt);
  725.     }
  726. }