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

  1. /************************************************************************
  2.  * JT3Conf (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 rend.*;
  14. import AppCtrls;
  15. import NewDlg;
  16.  
  17.  
  18. /////////////////////////////////////////////////////////////////////////
  19. //  CLASS: JT3Conf
  20. //
  21. //  PURPOSE: TAPI 3.0 test program
  22. //  DATE:    July 22, 1997
  23. //
  24. //  DESCRIPTION:
  25. //      Applet/application that allows the user to join, create, and
  26. //      delete conferences using TAPI 3.0.  Conference listings are
  27. //      retrieved using the Rendezvous Controls.
  28. //
  29. /////////////////////////////////////////////////////////////////////////
  30.  
  31. public class JT3Conf extends Applet
  32.     implements TapiConstants,   // misc. constants
  33.                DISCONNECT_CODE  // DC_xxx constants
  34. {
  35.     // Application name.
  36.     public static final String APP_NAME = "Java TAPI 3.0 Conferencer";
  37.  
  38.     // Maximum number of video window terminals.
  39.     private int m_MaxVideoWnds = 5;
  40.  
  41.     // True if running as stand alone app.
  42.     public boolean m_fStandAlone = false;
  43.  
  44.     // Parent frame of the app.
  45.     private Frame m_ParentFrame = null;
  46.  
  47.     // Resource Wizard generated UI.
  48.     private final AppCtrls ctrls = new AppCtrls(this);
  49.  
  50.     // Main interface to the TAPI component.
  51.     private ITTAPI m_Tapi = null;
  52.  
  53.     // The conference directory component.
  54.     private ITConferenceDirectory m_Directory = null;
  55.  
  56.     // The current call or null if there isn't one.
  57.     private ITBasicCallControl m_Call = null;
  58.  
  59.  
  60.     /////////////////////////////////////////////////////////////////////
  61.     // init
  62.     //
  63.     // Performs applet initialization.
  64.     /////////////////////////////////////////////////////////////////////
  65.     public void init()
  66.     {
  67.         // select a font to use (ctrls needs this)
  68.         Font font = new Font("Dialog", Font.PLAIN, 8);
  69.         this.setFont(font);
  70.  
  71.         // setup the UI generated by the Resource Wizard
  72.         ctrls.CreateControls();
  73.         ctrls.tfStatusBox.setEditable(false);
  74.         DisableControls();
  75.  
  76.         // get parent frame to use for message boxes
  77.         Container parent = getParent();
  78.         while ((parent != null) && (!(parent instanceof Frame))) {
  79.             parent = parent.getParent();
  80.         }
  81.         m_ParentFrame = (Frame) parent;
  82.  
  83.         // resize the frame if running as standalone app
  84.         if (m_fStandAlone) {
  85.             m_ParentFrame.pack();
  86.             m_ParentFrame.setResizable(false);
  87.         }
  88.  
  89.         // create and initialize TAPI component
  90.         SetStatusMessage("Initializing TAPI 3.0...");
  91.         try {
  92.             m_Tapi = new TAPI();
  93.             m_Tapi.Initialize();
  94.         }
  95.         catch (ComException e) {
  96.             DoMessage("Fatal Error: Could not initialize TAPI 3.0");
  97.             m_Tapi = null;
  98.             if (m_fStandAlone) {
  99.                 System.exit(0);
  100.             }
  101.             else {
  102.                 SetStatusMessage("Could not initialize TAPI 3.0");
  103.                 return;
  104.             }
  105.         }
  106.  
  107.         // initialize the conference directory
  108.         SetStatusMessage("Initializing conference directory...");
  109.         try {
  110.             m_Directory = new ConferenceDirectory();
  111.             m_Directory.Init(
  112.                             null,   // use default server
  113.                             null    // use default path
  114.                             );
  115.         }
  116.         catch (ComException e) {
  117.             DoMessage("Fatal Error: Could not initialize conference directory");
  118.             m_Tapi.Shutdown();
  119.             m_Tapi = null;
  120.             if (m_fStandAlone) {
  121.                 System.exit(0);
  122.             }
  123.             else {
  124.                 SetStatusMessage("Could not initialize conference directory");
  125.                 return;
  126.             }
  127.         }
  128.  
  129.         // get initial data and display it
  130.         SetStatusMessage("Enumerating conferences...");
  131.         if (!EnumerateConferences()) {
  132.             DoMessage("Fatal Error: Could not enumerate conferences");
  133.             m_Tapi.Shutdown();
  134.             m_Tapi = null;
  135.             if (m_fStandAlone) {
  136.                 System.exit(0);
  137.             }
  138.             else {
  139.                 SetStatusMessage("Could not enumerate conferences");
  140.                 return;
  141.             }
  142.         }
  143.         SetStatusMessage("Ready");
  144.  
  145.         // app initialized... enable controls
  146.         ctrls.lstConferences.enable();
  147.         ctrls.btnJoin.enable();
  148.         ctrls.btnNew.enable();
  149.         ctrls.btnDelete.enable();
  150.         ctrls.btnRefresh.enable();
  151.     }
  152.  
  153.     /////////////////////////////////////////////////////////////////////
  154.     // stop
  155.     //
  156.     // Called when the user leaves the applet's webpage.
  157.     /////////////////////////////////////////////////////////////////////
  158.     public void stop()
  159.     {
  160.         if (m_Call != null) {
  161.             DisconnectTheCall(DC_NORMAL);
  162.         }
  163.  
  164.         ctrls.btnJoin.enable();
  165.         ctrls.btnHangup.disable();
  166.         ctrls.btnDelete.enable();
  167.         ctrls.lstConferences.enable();
  168.         SetStatusMessage("Ready");
  169.     }
  170.  
  171.     /////////////////////////////////////////////////////////////////////
  172.     // destroy
  173.     //
  174.     // Called when the applet is destroyed by the browser.
  175.     /////////////////////////////////////////////////////////////////////
  176.     public void destroy()
  177.     {
  178.         try {
  179.             if (m_Tapi != null) {
  180.                 m_Tapi.Shutdown();
  181.             }
  182.         }
  183.         catch (ComException e) {
  184.             e.printStackTrace();
  185.             DoMessage("An error occurred while trying to shutdown TAPI");
  186.         }
  187.     }
  188.  
  189.     /////////////////////////////////////////////////////////////////////
  190.     // action
  191.     //
  192.     // Event.ACTION_EVENT event handler.
  193.     /////////////////////////////////////////////////////////////////////
  194.     public boolean action(Event evt, Object arg)
  195.     {
  196.         if (arg.equals("Join")) {
  197.             // join button pressed
  198.             if (JoinTheConference()) {
  199.                 ctrls.btnJoin.disable();
  200.                 ctrls.btnHangup.enable();
  201.                 ctrls.btnDelete.disable();
  202.                 ctrls.lstConferences.disable();
  203.                 SetStatusMessage("Connected to " + GetSelectedConfName());
  204.             }
  205.             else {
  206.                 DoMessage("You were unable to join the conference");
  207.                 SetStatusMessage("Ready");
  208.             }
  209.         }
  210.         else if (arg.equals("Hangup")) {
  211.             // hangup button pressed
  212.             if (!DisconnectTheCall(DC_NORMAL)) {
  213.                 DoMessage("An error occurred while disconnecting, " +
  214.                           "but it will be ignored");
  215.             }
  216.             ctrls.btnJoin.enable();
  217.             ctrls.btnHangup.disable();
  218.             ctrls.btnDelete.enable();
  219.             ctrls.lstConferences.enable();
  220.             SetStatusMessage("Disconnected");
  221.         }
  222.         else if (arg.equals("New")) {
  223.             // new button pressed
  224.             NewDlg newDlg = new NewDlg(m_ParentFrame, m_Directory);
  225.             newDlg.show();
  226.             if (newDlg.GetButtonId() == NewDlg.CREATE) {
  227.                 ITConference conf = newDlg.GetConference();
  228.                 if (conf != null) {
  229.                     ctrls.lstConferences.addItem(conf.getName());
  230.                 }
  231.                 else {
  232.                     DoMessage("The conference failed to be created");
  233.                 }
  234.             }
  235.         }
  236.         else if (arg.equals("Delete")) {
  237.             // delete button pressed
  238.             int index = ctrls.lstConferences.getSelectedIndex();
  239.             if (index == -1)
  240.                 DoMessage("You must select a conference first");
  241.             else {
  242.                 String name = GetSelectedConfName();
  243.                 try {
  244.                     m_Directory.DeleteConference(name);
  245.                     ctrls.lstConferences.delItem(index);
  246.                     SetStatusMessage("Conference " + name + " deleted");
  247.                 }
  248.                 catch (ComException e) {
  249.                     DoMessage("Could not delete " + name);
  250.                 }
  251.             }
  252.         }
  253.         else if (arg.equals("Refresh")) {
  254.             // refresh button pressed
  255.             EnumerateConferences();
  256.             SetStatusMessage("Ready");
  257.         }
  258.         else {
  259.             return super.action(evt, arg);
  260.         }
  261.         return true;
  262.     }
  263.  
  264.     /////////////////////////////////////////////////////////////////////
  265.     // EnumerateConferences
  266.     //
  267.     // Finds all conferences on and adds their names to the conferences
  268.     // listbox.  Returns true on success and false if there was an error.
  269.     /////////////////////////////////////////////////////////////////////
  270.     private boolean EnumerateConferences()
  271.     {
  272.         IEnumVariant enumVar;
  273.         Variant[]    pVar = new Variant[1];
  274.         int[]        pInt = new int[1];
  275.         ITConference conf;
  276.         
  277.         ctrls.lstConferences.clear();
  278.  
  279.         try {
  280.             enumVar = (IEnumVariant) m_Directory.get_NewEnum();
  281.  
  282.             while (true) {
  283.                 // get the next conference (packaged in a variant)
  284.                 enumVar.Next(1, pVar, pInt);
  285.                 if (pInt[0] == 0)
  286.                     break;
  287.                 pInt[0] = 0;
  288.  
  289.                 // get the conference from the variant
  290.                 conf = (ITConference) pVar[0].toObject();
  291.  
  292.                 // display the conference name and store its interface
  293.                 ctrls.lstConferences.addItem(conf.getName());
  294.             }
  295.             return true;
  296.         }
  297.         catch (ComException e) {
  298.             e.printStackTrace();
  299.             return false;
  300.         }
  301.     }
  302.  
  303.     /////////////////////////////////////////////////////////////////////
  304.     // JoinTheConference
  305.     //
  306.     // Joins the selected conference.  The steps required to join a
  307.     // conference are the same as those for making a one-to-one call.
  308.     /////////////////////////////////////////////////////////////////////
  309.     private boolean JoinTheConference()
  310.     {
  311.         ITAddress         srcAddr;
  312.         String            destAddr;
  313.         ITTerminal[]      staticTerms, dynamicTerms, temp;
  314.         ITMediaTerminal[] mediaTerms;
  315.         SafeArray         sa;
  316.         Variant           var;
  317.  
  318.         // get the destination address
  319.         destAddr = GetSelectedConfName();
  320.         if (destAddr == null) {
  321.             DoMessage("You must select a conference first");
  322.             return false;
  323.         }
  324.         
  325.         // get the source address (an interface)
  326.         srcAddr = GetAddress(ADDRESSTYPE_CONFERENCENAME);
  327.         if (srcAddr == null) {
  328.             DoMessage("No local address supports conferencing");
  329.             return false;
  330.         }
  331.         
  332.         // get static terminals
  333.         staticTerms = GetStaticTerminals(srcAddr);
  334.         if (staticTerms == null) {
  335.             DoMessage("No static terminals were found");
  336.             return false;
  337.         }
  338.  
  339.         // get Video Window Terminals (dynamic terminals)
  340.         dynamicTerms = GetVideoWndTerms(srcAddr, m_MaxVideoWnds);
  341.         if (dynamicTerms == null && m_MaxVideoWnds > 0) {
  342.             DoMessage("No dynamic terminals could be created");
  343.             return false;
  344.         }
  345.  
  346.         // put terminals into a single array
  347.         temp = new ITTerminal[staticTerms.length + dynamicTerms.length];
  348.         System.arraycopy(staticTerms, 0, temp, 0, staticTerms.length);
  349.         System.arraycopy(dynamicTerms, 0, temp, staticTerms.length, dynamicTerms.length);
  350.  
  351.         // create media-terminals
  352.         mediaTerms = CreateMediaTerminals(temp);
  353.         if (mediaTerms == null) {
  354.             DoMessage("Failed to create media-terminals");
  355.             return false;
  356.         }
  357.  
  358.         try {
  359.             // Note that SelectMediaTerminals requires you to package the
  360.             // media-terminals you intend to select in the following way:
  361.             // 1. Each media-terminal must be placed in a variant,
  362.             // 2. the varaints must then be placed in a safearray, and
  363.             //    finally,
  364.             // 3. the safearray must be placed in a variant and passed
  365.             //    to select media-terminals.
  366.  
  367.             // create a safearray to put the media-terminals into
  368.             sa = new SafeArray(Variant.VariantObject, mediaTerms.length);
  369.  
  370.             // package each media-terminal into a variant and store it
  371.             // in the safearray
  372.             for (int i=0; i < mediaTerms.length; i++) {
  373.                 sa.setVariant(i, new Variant(
  374.                                             Variant.VariantObject,
  375.                                             mediaTerms[i]
  376.                                             ));
  377.             }
  378.  
  379.             // put the safearray in a variant
  380.             var = new Variant(sa, false);
  381.  
  382.             // create a call between srcAddr and destAddr
  383.             m_Call = srcAddr.CreateCall(destAddr);
  384.  
  385.             // attach the media-terminals to the call
  386.             m_Call.SelectMediaTerminals(var);
  387.  
  388.             // make the call (true = synchronous)
  389.             m_Call.Connect(true);
  390.             return true;
  391.         }
  392.         catch (Exception e) {
  393.             e.printStackTrace();
  394.             m_Call = null;
  395.             return false;
  396.         }
  397.     }
  398.  
  399.     /////////////////////////////////////////////////////////////////////
  400.     // DisconnectTheCall
  401.     //
  402.     // Disconnects the call using the given disconnect code.  Disconnect
  403.     // codes are defined in the DisconnectCode interface.
  404.     /////////////////////////////////////////////////////////////////////
  405.     public boolean DisconnectTheCall(int code)
  406.     {
  407.         if (m_Call == null)
  408.             return true;
  409.  
  410.         try {
  411.             m_Call.Disconnect(code);
  412.             return true;
  413.         }
  414.         catch (ComException e) {
  415.             e.printStackTrace();
  416.             return false;
  417.         }
  418.         finally {
  419.             m_Call = null;
  420.  
  421.             // force a garbage collect.  This will ensure that terminals
  422.             // get released (unless you have references to them!), etc.
  423.             // If you do not do this you may have effects such as video
  424.             // windows lingering after a call has disconnected.
  425.             System.gc();
  426.         }
  427.     }
  428.  
  429.     /////////////////////////////////////////////////////////////////////
  430.     // GetStaticTerminals
  431.     //
  432.     // Returns an array of static terminals on the given address.  If no
  433.     // static terminals are found then null is returned.
  434.     /////////////////////////////////////////////////////////////////////
  435.     private ITTerminal[] GetStaticTerminals(ITAddress address)
  436.     {
  437.         ITTerminalSupport termSupp;
  438.         Variant           var;
  439.         ITCollection      itc;
  440.         ITTerminal[]      terminals;
  441.  
  442.         if (address == null)
  443.             return null;
  444.  
  445.         try {
  446.             // get the terminal support interface on the address
  447.             termSupp = (ITTerminalSupport) address;
  448.  
  449.             // get the collection interface for static terminals
  450.             var = termSupp.getStaticTerminals();
  451.             itc = (ITCollection) var.toDispatch();
  452.  
  453.             if (itc.getCount() == 0)
  454.                 return null;
  455.  
  456.             // create storage for the terminals
  457.             terminals = new ITTerminal[itc.getCount()];
  458.  
  459.                                 // NOTE: this needs to be modified if the
  460.                                 //      machine has multiple static terminals.
  461.                                 //      the correct way to select terminals
  462.                                 //      is to select only default terminals
  463.                                 
  464.             for (int i=1; i <= itc.getCount(); i++) {
  465.                 // get the next static terminal and store it
  466.                 var = itc.getItem(i);
  467.                 terminals[i-1] = (ITTerminal) var.toObject();
  468.             }
  469.             return terminals;
  470.         }
  471.         catch (Exception e) {
  472.             e.printStackTrace();
  473.             return null;
  474.         }
  475.     }
  476.  
  477.     /////////////////////////////////////////////////////////////////////
  478.     // GetVideoWndTerms
  479.     //
  480.     // Returns an array of Video Window Terminals on the given address,
  481.     // or null if there was an error.  count is the number of Video
  482.     // Window Terminals that should be returned.
  483.     //
  484.     // Video Window Terminals are dynamic terminals.  Dynamic terminals
  485.     // are different from static terminals in that there is no set
  486.     // number that may exist at any particular time.
  487.     //
  488.     // Static terminals are (usually) tied to hardware devices (eg,
  489.     // microphones, speakers, etc) and, therefore, have a specific count.
  490.     // There is no specific maximum to the number of dynamic terminals
  491.     // (eg, video windows, files, etc) that may be created.
  492.     /////////////////////////////////////////////////////////////////////
  493.     private ITTerminal[] GetVideoWndTerms(ITAddress address, int count)
  494.     {
  495.         ITTerminalSupport termSupp;
  496.         ITTerminal[]      terminals;
  497.  
  498.         if (address == null || count < 1)
  499.             return null;
  500.  
  501.         terminals = new ITTerminal[count];
  502.  
  503.         try {
  504.             // get the terminal support interface on the address
  505.             termSupp = (ITTerminalSupport) address;
  506.  
  507.             // create the video window terminals
  508.             for (int i=0; i < count; i++) {
  509.                 terminals[i] = termSupp.CreateTerminal(CLSID_String_VideoWindowTerm);
  510.             }
  511.             return terminals;
  512.         }
  513.         catch (ComException e) {
  514.             e.printStackTrace();
  515.             return null;
  516.         }
  517.     }
  518.                 
  519.     /////////////////////////////////////////////////////////////////////
  520.     // CreateMediaTerminals
  521.     //
  522.     // Takes an array of terminals and creates media-terminals from them.
  523.     // The media-terminals are returned on success; null is returned on
  524.     // failure.
  525.     //
  526.     // Media-terminals are the association of a terminal object and the
  527.     // mediatype that it will use.  In this case, the first mediatype
  528.     // supported by each terminal is used.
  529.     /////////////////////////////////////////////////////////////////////
  530.     private ITMediaTerminal[] CreateMediaTerminals(ITTerminal[] terminals)
  531.     {
  532.         ITMediaTerminal[] mediaTerms;
  533.         ITMediaSupport    mediaSupp;
  534.         Variant           var;
  535.         ITCollection      itc;
  536.         String            mediaType;
  537.  
  538.         if (terminals == null || terminals.length == 0)
  539.             return null;
  540.  
  541.         mediaTerms = new ITMediaTerminal[terminals.length];
  542.  
  543.         try {
  544.             for (int i=0; i < terminals.length; i++) {
  545.                 // get the media support interface on the terminal
  546.                 mediaSupp = (ITMediaSupport) terminals[i];
  547.  
  548.                 // get the collection interface for mediatypes
  549.                 var = mediaSupp.getMediaTypes();
  550.                 itc = (ITCollection) var.toDispatch();
  551.  
  552.                 if (itc.getCount() < 1)
  553.                     continue;
  554.                 
  555.                 // get the first mediatype (mediatypes are string GUIDs)
  556.                 var = itc.getItem(1);
  557.                 mediaType = var.toString();
  558.                 
  559.                 // create a media-terminal and store it.
  560.                 mediaTerms[i] = m_Tapi.CreateMediaTerminal(
  561.                                                           mediaType,
  562.                                                           terminals[i]
  563.                                                           );
  564.             }
  565.             return mediaTerms;
  566.         }
  567.         catch (Exception e) {
  568.             e.printStackTrace();
  569.             return null;
  570.         }
  571.     }
  572.  
  573.     /////////////////////////////////////////////////////////////////////
  574.     // GetAddress
  575.     //
  576.     // Returns an interface to the first local address that supports the
  577.     // given address type.  If an error occurs or the given address type
  578.     // is not supported by any local addresses, null is returned.
  579.     // Address type constants are defined in the TapiConstants interface.
  580.     /////////////////////////////////////////////////////////////////////
  581.     private ITAddress GetAddress(int addressType)
  582.     {
  583.         Variant      var;
  584.         ITCollection itcAddr, itcType;
  585.         ITAddress    address;
  586.         int          type;
  587.  
  588.         try {
  589.             // get the collection interface for addresses
  590.             var = m_Tapi.getAddresses();
  591.             itcAddr = (ITCollection) var.toDispatch();
  592.  
  593.             for (int i=1; i <= itcAddr.getCount(); i++) {
  594.                 // get the next address
  595.                 var = itcAddr.getItem(i);
  596.                 address = (ITAddress) var.toObject();
  597.  
  598.                 // get the collection interface for address types
  599.                 var = address.getAddressTypes();
  600.                 itcType = (ITCollection) var.toDispatch();
  601.  
  602.                 for (int j=1; j <= itcType.getCount(); j++) {
  603.                     // get the next address type
  604.                     var = itcType.getItem(j);
  605.                     type = var.toInt();
  606.  
  607.                     // if it's the type we're looking for then return
  608.                     // the address
  609.                     if (type == addressType)
  610.                         return address;
  611.                 }
  612.             }
  613.  
  614.             // no address supports the type we're looking for
  615.             return null;
  616.         }
  617.         catch (ComException e) {
  618.             e.printStackTrace();
  619.             return null;
  620.         }
  621.     }
  622.  
  623.     /////////////////////////////////////////////////////////////////////
  624.     // GetSelectedConfName
  625.     //
  626.     // Returns the name of the currently selected conference.
  627.     /////////////////////////////////////////////////////////////////////
  628.     private String GetSelectedConfName()
  629.     {
  630.         return ctrls.lstConferences.getSelectedItem();
  631.     }
  632.  
  633.     /////////////////////////////////////////////////////////////////////
  634.     // DisableControls
  635.     //
  636.     // Disables all of the app's controls.
  637.     /////////////////////////////////////////////////////////////////////
  638.     private void DisableControls()
  639.     {
  640.         ctrls.lstConferences.disable();
  641.         ctrls.btnJoin.disable();
  642.         ctrls.btnHangup.disable();
  643.         ctrls.btnNew.disable();
  644.         ctrls.btnDelete.disable();
  645.         ctrls.btnRefresh.disable();
  646.     }
  647.  
  648.     /////////////////////////////////////////////////////////////////////
  649.     // SetStatusMessage
  650.     //
  651.     // Displays messages in the status box.
  652.     /////////////////////////////////////////////////////////////////////
  653.     private void SetStatusMessage(String msg)
  654.     {
  655.         ctrls.tfStatusBox.setText(msg);
  656.     }
  657.  
  658.     /////////////////////////////////////////////////////////////////////
  659.     // DoMessage
  660.     //
  661.     // Displays messages in a message box.
  662.     /////////////////////////////////////////////////////////////////////
  663.     private void DoMessage(String msg)
  664.     {
  665.         AwtUIMessageBox msgbox = new AwtUIMessageBox(
  666.                                             m_ParentFrame,
  667.                                             APP_NAME,
  668.                                             msg,
  669.                                             AwtUIMessageBox.EXCLAMATION,
  670.                                             UIButtonBar.OK
  671.                                             );
  672.         msgbox.doModal();
  673.     }
  674.  
  675.     /////////////////////////////////////////////////////////////////////
  676.     // main
  677.     //
  678.     // Standalone application entry point.  Not called for applets.
  679.     /////////////////////////////////////////////////////////////////////
  680.     public static void main(String[] args)
  681.     {
  682.         JT3Conf applet = new JT3Conf();
  683.  
  684.         AppFrame frame = new AppFrame(APP_NAME, applet);
  685.         frame.show();
  686.  
  687.         applet.m_fStandAlone = true;
  688.         applet.init();
  689.     }
  690. }
  691.  
  692.  
  693. /////////////////////////////////////////////////////////////////////////
  694. //  CLASS: AppFrame
  695. //
  696. //  DESCRIPTION:
  697. //      Frame for standalone application.
  698. //
  699. /////////////////////////////////////////////////////////////////////////
  700.  
  701. class AppFrame extends Frame
  702. {
  703.     private Applet m_App = null;
  704.  
  705.     public AppFrame(String title, Applet applet)
  706.     {
  707.         super(title);
  708.         m_App = applet;
  709.         this.add(applet);
  710.     }
  711.     
  712.     public boolean handleEvent(Event evt)
  713.     {
  714.         if (evt.id == Event.WINDOW_DESTROY) {
  715.             // since a browser would close the applet by calling stop and
  716.             // destroy, we should also.
  717.             m_App.stop();
  718.             m_App.destroy();
  719.             System.exit(0);
  720.         }
  721.  
  722.         return super.handleEvent(evt);
  723.     }
  724. }
  725.