home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 July / Chip_1998-07_cd.bin / zkuste / JBuilder / BDK / Win / bdk_sep97.exe / _SETUP.1 / BeanBox.java < prev    next >
Encoding:
Java Source  |  1997-09-17  |  38.5 KB  |  1,392 lines

  1. package sun.beanbox;
  2.  
  3. /**
  4.  * The BeanBox is a reference container for JavaBeans.  It has two purposes.
  5.  * First, it allows bean developers to check that their bean correctly
  6.  * implements the various bean APIs.  Second, it provides a reference example
  7.  * container that can be copied and modified freely.
  8.  * <p>
  9.  * The BeanBox allows beans to be manipulated visually.  You can use the
  10.  * associated property sheet to edit the exposed properties, you can use the
  11.  * edit/events menu to connect events from am event source to an event sink,
  12.  * or you can use the edit/customize menu to test a customizer.
  13.  * <p>
  14.  * The BeanBox is itself a bean, and you can recursively embed a BeanBox
  15.  * inside a BeanBox.  At the top-level, a BeanBox is embedded inside a
  16.  * BeanBoxFrame, which handles things like the MenuBar.
  17.  */
  18.  
  19. import java.awt.*;
  20. import java.awt.event.*;
  21. import java.applet.*;
  22. import java.io.*;
  23. import java.util.*;
  24. import java.beans.*;
  25. import java.net.*;
  26. import java.lang.reflect.Method;
  27. import sunw.beanbox.AppletSupport;
  28.  
  29. public class BeanBox extends Panel implements Serializable, Runnable, 
  30.         MouseListener, MouseMotionListener {
  31.  
  32.     static final long serialVersionUID = -1930952830824256715L; 
  33.  
  34.     /**
  35.      * Initialize a new BeanBox.
  36.      */
  37.  
  38.     public BeanBox() {
  39.     setLayout(null);
  40.     addMouseListener(this);
  41.     addMouseMotionListener(this);
  42.     }
  43.  
  44.     /**
  45.      * Update the MenuBar for the current beanBox and focus bean.
  46.      */
  47.  
  48.     public synchronized void updateMenuBar(MenuBar bar) {
  49.     BeanBoxFrame frame = getFrame();
  50.     
  51.     if (bar.getMenuCount() == 0) {
  52.         // Create the basic menus.  These are bean/beanbox independent.
  53.  
  54.         Menu m = new Menu("File");
  55.         addMenuItem(frame, m, new MenuItem("Save..."));
  56.         addMenuItem(frame, m, new MenuItem("SerializeComponent..."));
  57.         addMenuItem(frame, m, new MenuItem("MakeApplet..."));
  58.         addMenuItem(frame, m, new MenuItem("Load..."));
  59.         addMenuItem(frame, m, new MenuItem("LoadJar..."));
  60.         addMenuItem(frame, m, new MenuItem("Print"));
  61.         addMenuItem(frame, m, new MenuItem("Clear"));
  62.         addMenuItem(frame, m, new MenuItem("Exit"));
  63.         bar.add(m);
  64.  
  65.         m = new Menu("Edit");
  66.         addMenuItem(frame, m, new MenuItem("Cut"));
  67.         addMenuItem(frame, m, new MenuItem("Copy"));
  68.         addMenuItem(frame, m, new MenuItem("Paste"));
  69.         addMenuItem(frame, m, new MenuItem("Report..."));
  70.         bar.add(m);
  71.  
  72.         m = new Menu("View");
  73.         bar.add(m);
  74.  
  75.         m = new Menu("Help");
  76.         addMenuItem(frame, m, new MenuItem("About..."));
  77.         addMenuItem(frame, m, new MenuItem("Documentation..."));
  78.         bar.setHelpMenu(m);
  79.     }
  80.  
  81.     Menu editMenu = bar.getMenu(1);
  82.  
  83.     // Remove any bean-specific menu items from the edit menu.
  84.     for (int i = 0; i < editMenu.getItemCount(); i++) {
  85.         String label = editMenu.getItem(i).getLabel();
  86.         if (label.equals("Customize...") || label.equals("Events") ||
  87.             label.equals("Bind property...")) {
  88.         editMenu.remove(i);
  89.         i--;
  90.         }
  91.     }
  92.     customizerClass = null;
  93.     getFrame().setCustomizer(null);
  94.     eventMap = null;
  95.     methodMap = null;
  96.  
  97.     resetViewMenu();
  98.  
  99.     // Take a look at the current focus bean, and create appropriate
  100.     // menu items for its events, customizer, etc.
  101.  
  102.     try {
  103.         Object bean = BeanBoxFrame.getCurrentBean();
  104.         BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
  105.  
  106.         try {
  107.         BeanDescriptor bd = bi.getBeanDescriptor();
  108.             customizerClass = bd.getCustomizerClass();
  109.         if (customizerClass != null) {
  110.             addMenuItem(frame, editMenu, new MenuItem("Customize..."));
  111.         }
  112.         } catch (Exception ex) {
  113.         error("Couldn't initialize customizer", ex);
  114.         }
  115.  
  116.         java.beans.EventSetDescriptor esd[] = bi.getEventSetDescriptors();
  117.         boolean bindable = false;
  118.         if (esd.length > 0) {
  119.             Menu eventMenu = new Menu("Events");
  120.         eventMap = new Hashtable();
  121.         methodMap = new Hashtable();
  122.         // We create a separate menu for each event listener interface,
  123.         // with a menu item for each event handler method.
  124.             for (int i = 0; i < esd.length; i++) {
  125.             String dname = esd[i].getDisplayName();
  126.             Menu methodMenu = new Menu(dname);
  127.             eventMap.put(methodMenu, esd[i]);
  128.             Method methods[] = esd[i].getListenerMethods();
  129.             for (int j = 0; j < methods.length; j++) {
  130.             String mname = methods[j].getName();
  131.             MenuItem mi = new MenuItem(mname);
  132.             addMenuItem(frame, methodMenu, mi);
  133.             methodMap.put(mi, methods[j]);
  134.                 }
  135.             eventMenu.add(methodMenu);
  136.             if (esd[i].getName().equals("propertyChange")) {
  137.             bindable = true;
  138.             }
  139.             }
  140.             editMenu.add(eventMenu);
  141.         }
  142.  
  143.         if (bindable) {
  144.         addMenuItem(frame, editMenu, new MenuItem("Bind property..."));
  145.         }
  146.  
  147.     } catch (IntrospectionException ex) {
  148.         error("Caught unexpected exception while building event menu", ex);
  149.     }
  150.     }
  151.  
  152.     private void addMenuItem(BeanBoxFrame frame, Menu m, MenuItem mi) {
  153.     // Register the BeanBoxFrame as the event handler.
  154.     mi.addActionListener(frame);
  155.     // Add the menuitem to the menu
  156.     m.add(mi);
  157.     }
  158.  
  159.     /**
  160.      * Provide an identifier for serializing this object
  161.      */
  162.     private synchronized String serFileName(Object o) {
  163.     if (o == null) {
  164.         // distinguished root-component
  165.         return BeanBoxFrame.getTmpDir()+File.separator+"___comp_ROOT.ser";
  166.     } else {
  167.         String s = (String) serNames.get(o);
  168.         if (s == null) {
  169.         String name = "___comp_"+HookupManager.getId()+".ser";
  170.         s = BeanBoxFrame.getTmpDir()+File.separator+name;
  171.         serNames.put(o, s);
  172.         }
  173.         return s;
  174.     }
  175.     }
  176.  
  177.     /**
  178.      * This method is currently unused
  179.      */
  180.  
  181.     private boolean generateManifestTemplate(File file) {
  182.     File dir = new File(file.getParent());
  183.     if (dir != null) {
  184.         dir.mkdirs();
  185.     }
  186.     OutputStream os;
  187.     try {
  188.         os = new FileOutputStream(file);
  189.         PrintWriter pos = new PrintWriter(os);
  190.  
  191.         int count = getComponentCount();
  192.         for (int i = 0; i < count; i++) {
  193.         Wrapper w = Wrapper.findWrapper(getComponent(i));
  194.         pos.println("Name: "+serFileName(w).replace(File.separatorChar, '/'));
  195.         pos.println("Java-Bean: True");
  196.         pos.println();
  197.         }
  198.         pos.flush();
  199.         pos.close();
  200.  
  201.     } catch (Exception ex) {
  202.         error("Problems creating manifest template file", ex);
  203.         return false;
  204.     }
  205.     return true;
  206.     }
  207.  
  208.     /**
  209.      * This implements the "save" menu item.  This stores away the
  210.      * current state of the BeanBox to a named file.
  211.      *
  212.      * Note: The format is builder-dependent.
  213.      */
  214.     public void save() {
  215.     // Write a JAR file that contains all the hookups and a
  216.     // single serialized stream.
  217.     // Then, on load, read the components and mock-up the AppletStub.
  218.  
  219.     FileDialog fd = new FileDialog(getFrame(), "Save File", FileDialog.SAVE);
  220.     // the setDirectory() is not needed, except for a bug under Solaris...
  221.     fd.setDirectory(System.getProperty("user.dir"));
  222.     fd.setFile(defaultStoreFile);
  223.     fd.show();
  224.     String fname = fd.getFile();
  225.     if (fname == null) {
  226.         return;
  227.     }
  228.     String dname = fd.getDirectory();
  229.     File file = new File(dname, fname);        
  230.  
  231.     try {
  232.         // create the single ObjectOutputStream
  233.         File serFile = new File(serFileName(null));
  234.         File dir = new File(serFile.getParent());
  235.         if (dir != null) {
  236.         dir.mkdirs();
  237.         }
  238.         // we could use a JarEntrySource here to avoid writing the ser file
  239.         FileOutputStream f = new FileOutputStream(serFile);
  240.         ObjectOutputStream oos = new ObjectOutputStream(f);
  241.         writeContents(oos);
  242.         oos.close();
  243.  
  244.         String[] hookups;
  245.         hookups = HookupManager.getHookupFiles();
  246.         String[] files = new String[hookups.length+1];
  247.         System.arraycopy(hookups, 0, files, 1, hookups.length);
  248.         files[0] = serFileName(null);
  249.  
  250.         JarAccess.create(new FileOutputStream(file),
  251.                  files);
  252.     } catch (Exception ex) {
  253.         error("Save failed", ex);
  254.        }
  255.     }
  256.  
  257.     /**
  258.      * This implements the "serializeComponent" menu item.
  259.      * The selected component is serialized to the chosen file
  260.      */
  261.     private void serializeComponent() {
  262.     FileDialog fd = new FileDialog(getFrame(), "Serialize Component into File", FileDialog.SAVE);
  263.     // needed for a bug under Solaris...
  264.     fd.setDirectory(System.getProperty("user.dir"));
  265.     fd.setFile(defaultSerializeFile);
  266.     fd.show();
  267.     String fname = fd.getFile();
  268.     if (fname == null) {
  269.         return;
  270.     }
  271.     String dname = fd.getDirectory();
  272.     File file = new File(dname, fname);
  273.  
  274.     Wrapper w = BeanBoxFrame.getCurrentWrapper();
  275.  
  276.     try {
  277.         FileOutputStream f = new FileOutputStream(file);
  278.         ObjectOutputStream oos = new ObjectOutputStream(f);
  279.         // Ask the Wrapper to serialize the "naked" bean.
  280.         // as in copy()
  281.         w.writeNakedBean(oos);
  282.         oos.close();
  283.     } catch (Exception ex) {
  284.         error("Serialization of Component failed", ex);
  285.     }
  286.     }
  287.  
  288.     /**
  289.      * This implements the "makeApplet" menu item.
  290.      */
  291.     private void makeApplet() {
  292.     Object bb = BeanBoxFrame.getTopBox();
  293.     if (bb.getClass() != BeanBox.class) {
  294.         error("Internal error.  getTopBox is not a BeanBox");
  295.         return;
  296.     }
  297.         MakeAppletDialog d = new MakeAppletDialog(getFrame(), (BeanBox) bb);
  298.     }
  299.  
  300.  
  301.     /**
  302.      * This implements the "load" menu item.  This loads the BeanBox state
  303.      * from a named file.
  304.      */
  305.     private void load() {
  306.     removeAll();
  307.     FileDialog fd = new FileDialog(getFrame(), "Load File", FileDialog.LOAD);
  308.     // needed for a bug under Solaris...
  309.     fd.setDirectory(System.getProperty("user.dir"));
  310.     fd.setFile(defaultStoreFile);
  311.     fd.show();
  312.     String fname = fd.getFile();
  313.     if (fname == null) {
  314.         return;
  315.     }
  316.     String dname = fd.getDirectory();
  317.     File file = new File(dname, fname);
  318.  
  319.     JarLoader jl = null;
  320.     try {
  321.         jl = new JarLoader(file.getPath());
  322.         if (jl == null) {
  323.         System.err.println("file name passed is not a valid JarFile");
  324.         return;
  325.         }
  326.     } catch (Exception ex) {
  327.         System.err.println("caught an exception while trying to load "+file.getPath());
  328.         ex.printStackTrace();
  329.         return;
  330.     }
  331.  
  332.     JarInfo ji = jl.loadJar();
  333.     // OK, loaded all the classes -- now, instantiate them...
  334.  
  335.     try {
  336.         // get the one object as a bean...
  337.         ClassLoader cl = jl.getLoader();
  338.         InputStream is = cl.getResourceAsStream(serFileName(null).replace(File.separatorChar, '/'));
  339.         ObjectInputStream ois = new ObjectInputStreamWithLoader(is, cl);
  340.  
  341.         // Read all the contained beans into this BeanBox.
  342.         readContents(ois);
  343.  
  344.     } catch (Exception ex) {
  345.         ex.printStackTrace();
  346.         return;
  347.     }
  348.     }
  349.  
  350.     
  351.     // Support for serialization
  352.  
  353.     private void writeContents(java.io.ObjectOutputStream s)
  354.                 throws java.io.IOException {
  355.     int count = getComponentCount();
  356.  
  357.     // We unhook all the event wiring from the beans while
  358.     // they are being written out.
  359.         for (int i=0; i<count; i++) {
  360.         Wrapper w = (Wrapper) getComponent(i);
  361.         w.removeListeners();
  362.     }
  363.  
  364.     // Now actually write out all the wrappers.
  365.     s.writeInt(count);
  366.     for (int i = 0; i < count; i++) {
  367.         Wrapper w = (Wrapper) getComponent(i);
  368.         s.writeObject(w);
  369.     }
  370.  
  371.     // Now reattach all the event wiring.
  372.         for (int i=0; i<count; i++) {
  373.         Wrapper w = (Wrapper) getComponent(i);
  374.         w.attachListeners();    
  375.     }
  376.     }
  377.  
  378.  
  379.     private void readContents(java.io.ObjectInputStream ois)
  380.                 throws java.lang.ClassNotFoundException,
  381.                    java.io.IOException {
  382.  
  383.     removeAll();
  384.  
  385.     ClassLoader cl = SimpleClassLoader.ourLoader;
  386.  
  387.         int count = ois.readInt();
  388.  
  389.         for (int i=0; i<count; i++) {
  390.         Component c = (Component) ois.readObject();
  391.         Wrapper w = (Wrapper) c;
  392.  
  393.         Object bean = w.getBean();
  394.         if (bean instanceof Applet) {
  395.         // Assign an AppletStub
  396.         AppletSupport.assignStub((Applet) bean, cl, bean.getClass());
  397.         }
  398.  
  399.         // Add the new component to our AWT container.
  400.         add(c);
  401.         c.invalidate();
  402.  
  403.         if (bean instanceof Applet) {
  404.         // start the Applet.
  405.         ((Applet)bean).start();
  406.         }
  407.     }
  408.  
  409.     // We need to wait until the entire graph has been read back in
  410.     // before we can redo the wiring.
  411.         for (int i=0; i<count; i++) {
  412.         Wrapper w = (Wrapper) getComponent(i);
  413.         w.attachListeners();    
  414.     }
  415.     }
  416.  
  417.     // Support for serialization
  418.  
  419.     private void writeObject(java.io.ObjectOutputStream oos)
  420.                 throws java.io.IOException {
  421.     writeContents(oos);
  422.     }
  423.  
  424.     private void readObject(java.io.ObjectInputStream ois)
  425.                 throws java.lang.ClassNotFoundException,
  426.                    java.io.IOException {
  427.     readContents(ois);
  428.     }
  429.  
  430.     /* 
  431.      * Support for printing
  432.      * Print the current content of this Beanbox
  433.      */
  434.     private void print() {
  435.  
  436.             PrintJob pj = Toolkit.getDefaultToolkit().getPrintJob(ourFrame, 
  437.             "Printing Test", (Properties)null);
  438.  
  439.             if (pj != null) {
  440.             Graphics g;
  441.         Dimension pageDim = pj.getPageDimension();
  442.         int pageRes = pj.getPageResolution();
  443.         boolean lastFirst = pj.lastPageFirst();
  444.  
  445.         Graphics gr  = pj.getGraphics();
  446.         if (gr!=null) {
  447.         // We print all components one after the other in the
  448.         // same page.           
  449.           int count = getComponentCount();
  450.           for (int i=0; i<count; i++) {
  451.             Wrapper wr = (Wrapper) getComponent(i);
  452.             Object bean = wr.getBean();
  453.             if (bean instanceof Component) {
  454.               Component c;
  455.               c= (Component) Beans.getInstanceOf(bean, Component.class);
  456.               Dimension d = c.getSize();
  457.               Point o = wr.getLocation();
  458.               Image offScreen = c.createImage(d.width, d.height);
  459.               c.paint(offScreen.getGraphics());
  460.               gr.drawImage(offScreen, o.x, o.y, Color.white, null);
  461.             }
  462.           }
  463.         }
  464.         else 
  465.             System.err.println("Could not get Graphics handle.");
  466.                  
  467.         gr.dispose();
  468.             pj.end();
  469.  
  470.             } else {
  471.             System.err.println("PrintJob cancelled.");
  472.         }    
  473.     }
  474.  
  475.     /**
  476.      * This implements the "loadJar" menu item.
  477.      * Load the contents of a JAR file
  478.      */
  479.     private void loadJar() {
  480.     FileDialog fd = new FileDialog(getFrame(), "Load from JAR File", FileDialog.LOAD);
  481.     // the setDirectory() is not needed, except for a bug under Solaris...
  482.     fd.setDirectory(System.getProperty("user.dir"));
  483.     fd.setFile(defaultStoreFile);
  484.     fd.show();
  485.     String fname = fd.getFile();
  486.     if (fname == null) {
  487.         return;
  488.     }
  489.     String dname = fd.getDirectory();
  490.     File file = new File(dname, fname);
  491.  
  492.     Timer tim = new Timer();
  493.     Frame starter = new StartFrame();
  494.  
  495.     BeanBoxFrame.getToolBox().addBeansInJar(file.getPath());
  496.     if (BeanBoxFrame.showTimes()) {
  497.         System.err.println("loadJar time => "+tim.elapsed());
  498.     }
  499.     starter.dispose();
  500.     }
  501.  
  502.     /**
  503.      * Serialize the current focus bean to our clipboard file, and
  504.      * then remove it from the BeanBox.
  505.      */
  506.  
  507.     private void cut() {
  508.     Wrapper wrapper = BeanBoxFrame.getCurrentWrapper();
  509.     Object bean = wrapper.getBean();
  510.     if (bean != BeanBoxFrame.getTopBox()) {
  511.         copy();
  512.         Container parent = wrapper.getParent();
  513.         BeanBoxFrame.setCurrentComponent(null);
  514.         if (parent != null) {
  515.         parent.remove(wrapper);
  516.         }
  517.         wrapper.cleanup();
  518.     }
  519.     }
  520.  
  521.     /**
  522.      * Print a report on the current focus bean.
  523.      */
  524.     private void report() {
  525.     Object bean = BeanBoxFrame.getCurrentBean();
  526.     if (bean == null) {
  527.         System.out.println("No current focus.");
  528.         return;
  529.     }
  530.     Report.report(bean.getClass());
  531.     }
  532.  
  533.     /**
  534.      * Serialize the current focus bean to our clipboard file.
  535.      */
  536.     private void copy() {
  537.     Wrapper wrapper = BeanBoxFrame.getCurrentWrapper();
  538.  
  539.     BeanBoxFrame.setClipLabel(null);
  540.     BeanBoxFrame.setClipName(null);
  541.     try {
  542.         File f = new File(BeanBoxFrame.getClipFileName());
  543.         File dir = new File(f.getParent());
  544.         dir.mkdirs();
  545.             FileOutputStream fos = new FileOutputStream(f);
  546.             ObjectOutputStream oos = new ObjectOutputStream(fos);
  547.         // Ask the Wrapper to serialize the "naked" bean.
  548.         // This causes the Wrapper to remove all listeners
  549.         // before serializing, and add them back after.
  550.         wrapper.writeNakedBean(oos);
  551.         oos.close();
  552.         fos.close();
  553.             BeanBoxFrame.setClipLabel(wrapper.getBeanLabel());
  554.             BeanBoxFrame.setClipName(wrapper.getBeanName());
  555.     } catch (Exception ex) {
  556.         error("Copy failed", ex);
  557.        }
  558.  
  559.     }
  560.  
  561.     /**
  562.      * Read in a bean from our clipboard file and insert it into
  563.      * the BeanBox.
  564.      */
  565.     private void paste() {
  566.     synchronized (this) {
  567.         mouseClickEvent = null;
  568.         }
  569.     try {
  570.         // Set the insert cursor before reading the clipboard.
  571.         setCursor(crosshairCursor);
  572.  
  573.         SimpleClassLoader loader = SimpleClassLoader.ourLoader;
  574.         MyProducer p = new MyProducer(BeanBoxFrame.getClipFileName());
  575.         String clipName = BeanBoxFrame.getClipName();
  576.         String beanLabel = BeanBoxFrame.getClipLabel();
  577.  
  578.         Object bean = loader.instantiate(clipName, p);
  579.         doInsert(bean, beanLabel, clipName, true);
  580.     } catch (Exception ex) {
  581.         error("Paste failed", ex);
  582.        }
  583.     }
  584.  
  585.     /**
  586.      * Implementation method to make a connection between two beans.
  587.      * We draw a rubber banded line from a source bean until the mouse
  588.      * is clicked on a target bean.
  589.      * @return  the selected target bean.
  590.      */
  591.  
  592.     private synchronized Wrapper getConnection(Wrapper sourceWrapper) {
  593.     connectionSource = sourceWrapper.getChild();
  594.  
  595.     // Wait for a mouse click.
  596.     mouseClickEvent = null;
  597.     while (mouseClickEvent == null) {
  598.         try {
  599.             wait();
  600.         } catch (InterruptedException ex) {
  601.             connectionSource = null;
  602.             return null;
  603.         }
  604.     }
  605.     connectionSource = null;
  606.     Component target = mouseClickEvent.getComponent();
  607.         return Wrapper.findWrapper(target);
  608.     }
  609.  
  610.     /**
  611.      * Bind a source property to a target property.
  612.      */
  613.     void doBind() {
  614.  
  615.     Wrapper sourceWrapper = BeanBoxFrame.getCurrentWrapper();
  616.     Object bean = sourceWrapper.getBean();
  617.  
  618.     PropertyNameDialog dialog = new PropertyNameDialog(getFrame(),
  619.                 bean, "Select source property", null, true);
  620.     PropertyDescriptor sourceProperty = dialog.getResult();
  621.     if (sourceProperty == null) {
  622.         return;
  623.     }
  624.  
  625.     Wrapper targetWrapper = getConnection(sourceWrapper);
  626.     if (targetWrapper == null) {
  627.         return;
  628.     }    
  629.      Object target = targetWrapper.getBean();
  630.  
  631.     dialog = new PropertyNameDialog(getFrame(),
  632.          target, "Select target property",
  633.          sourceProperty.getPropertyType(), false);
  634.  
  635.     PropertyDescriptor targetProperty = dialog.getResult();
  636.  
  637.     if (targetProperty == null) {
  638.         return;
  639.     }
  640.  
  641.         PropertyHookupManager.attach(sourceWrapper,
  642.                      sourceProperty.getName(),
  643.                      sourceProperty.getReadMethod(),
  644.                      targetWrapper,
  645.                      targetProperty.getWriteMethod());
  646.     }
  647.  
  648.     /**
  649.      * Create an event connection from source to target
  650.      */
  651.  
  652.     void doEventHookup(ActionEvent evt) {    
  653.     Wrapper sourceWrapper = BeanBoxFrame.getCurrentWrapper();
  654.  
  655.     MenuItem mi = (MenuItem)evt.getSource();
  656.     Menu parent = (Menu)mi.getParent();
  657.  
  658.     EventSetDescriptor esd = (EventSetDescriptor) eventMap.get(parent);
  659.         Method meth = (Method) methodMap.get(mi);
  660.  
  661.     if (esd == null || meth == null) {
  662.         return;
  663.     }
  664.  
  665.     Wrapper targetWrapper = getConnection(sourceWrapper);
  666.     if (targetWrapper == null) {
  667.         return;
  668.     }    
  669.  
  670.         new EventTargetDialog(getFrame(), sourceWrapper, targetWrapper, esd, meth);
  671.     }
  672.  
  673.     /**
  674.      * Get the address of a target component relative to the 
  675.      * current BeanBox.
  676.      */
  677.  
  678.     private Rectangle getLocalCoordinates(Component c) {
  679.     int width = c.getSize().width;
  680.     int height = c.getSize().height;
  681.     int x = 0;
  682.     int y = 0;
  683.     for (;;) {
  684.         if (c == null) {
  685.         return new Rectangle(0,0,0,0);
  686.         }
  687.         if (c == this) {
  688.         return new Rectangle(x, y, width, height);
  689.         }
  690.         x += c.getLocation().x;
  691.         y += c.getLocation().y;
  692.         c = c.getParent();
  693.     }
  694.     }
  695.  
  696.     /**
  697.      * Paint a rubber-banded line from our current connection
  698.      * source "connectionSource" to the specified newX, newY.
  699.      */
  700.  
  701.     private synchronized void paintConnection(int newX, int newY) {
  702.     unpaintConnection();
  703.  
  704.     Graphics g = getGraphics();
  705.     if (g == null) {
  706.         return;
  707.     }
  708.     g.setColor(Color.red);
  709.  
  710.     Component comp = connectionSource;
  711.     if (comp == null) {
  712.         return;
  713.     }
  714.  
  715.     Rectangle b = getLocalCoordinates(comp);
  716.     int x2 = b.x + (b.width/2);
  717.     int y2 = b.y + (b.height/2);
  718.     g.drawLine(newX, newY, x2, y2);
  719.     g.drawLine(newX+1, newY+1, x2+1, y2+1);
  720.  
  721.     oldX1 = newX;
  722.     oldX2 = x2;
  723.     oldY1 = newY;
  724.     oldY2 = y2;
  725.     }
  726.  
  727.     /**
  728.      * Erase any outstanding connection rubber-band line.
  729.      */
  730.  
  731.     private void unpaintConnection() {
  732.     Graphics g = getGraphics();
  733.     if (g == null || oldX1 < 0) {
  734.         return;
  735.     }
  736.     g.setColor(getBackground());
  737.     g.drawLine(oldX1, oldY1, oldX2, oldY2);
  738.     g.drawLine(oldX1+1, oldY1+1, oldX2+1, oldY2+1);
  739.     oldX1 = -1;
  740.     }
  741.  
  742.     /**
  743.      * Repaint the current beanbox. Actually all we need to do
  744.      * is take note that any rubber-band lines or boxes have 
  745.      * been removed.
  746.      */
  747.     public void paint(Graphics g) {
  748.     if (oldX1 >= 0) {
  749.         paintConnection(oldX1, oldY1);
  750.     }
  751.     oldRubberBox = null;
  752.     super.paint(g);
  753.     }
  754.  
  755.     //----------------------------------------------------------------------
  756.  
  757.     // Mouse listener methods.
  758.     //
  759.     // Note that in general these methods must NOT be "synchronized" or we
  760.     // risk serious deadlock problems.
  761.     //
  762.     // At this level we mostly just do rubber-banding and simple
  763.     // move/resize handling.
  764.  
  765.     public void mouseClicked(MouseEvent evt) {
  766.     // To workaround #4039858 we do mouseClicked processing in mouseRelease
  767.     // and do nothing here.
  768.     }
  769.  
  770.     public void mousePressed(MouseEvent evt) {
  771.     mousePressedWhen = evt.getWhen();
  772.     // If we're in the middle of making a connection then clear the line.
  773.     if (connectionSource != null) {
  774.         unpaintConnection();
  775.         repaint();
  776.     }
  777.     }
  778.  
  779.     public void mouseReleased(MouseEvent evt) {
  780.  
  781.     long deltaWhen = (evt.getWhen() - mousePressedWhen);
  782.     mousePressedWhen = 0;
  783.  
  784.     int x = evt.getX();
  785.     int y = evt.getY();
  786.  
  787.     // If we're in the middle of a move, complete the move.
  788.     if (moveChild != null) {
  789.         // Make sure the event coordinates are relative to the child.
  790.         if (evt.getComponent() == this) {
  791.         x -= moveChild.getLocation().x;
  792.         y -= moveChild.getLocation().y;
  793.         }
  794.         // OK, insert the current object at the mouse.
  795.         deleteRubberBox();
  796.         finishMove(x, y);
  797.         return;
  798.     }
  799.  
  800.         // If we're in the middle of a resize, complete the resize.
  801.     if (resizeChild != null) {
  802.         // Make sure the event coordinates are relative to the child.
  803.         if (evt.getComponent() == this) {
  804.         x -= resizeChild.getLocation().x;
  805.         y -= resizeChild.getLocation().y;
  806.         }
  807.         deleteRubberBox();
  808.         finishResize(x, y);
  809.         return;
  810.         }
  811.  
  812.     // Because of bug #4039858 we get a bogus mouseClicked and mouseReleased
  813.     // event when a menuItem is selected.  Therefore we manually check
  814.     // if there has been a mousePressed within the preceeding 5 seconds before
  815.     // the mouseRelease, and only then do we treat it as a genuine mouse
  816.     // click.                        KGH 4/3/97
  817.     if (deltaWhen < 5000) {
  818.         // OK, treat this as a genuine mouse click.    
  819.         // Wakeup anyway who is waiting for a mouse down.
  820.         synchronized (this) {
  821.     
  822.             mouseClickEvent = new MouseEvent(evt.getComponent(), evt.getID(),
  823.                 evt.getWhen(), evt.getModifiers(), evt.getX(), evt.getY(),
  824.                  evt.getClickCount(), evt.isPopupTrigger());
  825.             notifyAll();
  826.  
  827.             // set the new focus, unless we're in the middle of an insert.
  828.             if (getCursor() != crosshairCursor) {
  829.                 Component target = evt.getComponent();
  830.                 BeanBoxFrame.setCurrentComponent(target);
  831.         }
  832.         }
  833.     }
  834.     }
  835.  
  836.     public void mouseEntered(MouseEvent evt) {
  837.     }
  838.  
  839.     public void mouseExited(MouseEvent evt) {
  840.     }
  841.  
  842.     public synchronized void mouseDragged(MouseEvent evt) {
  843.     int x = evt.getX();
  844.     int y = evt.getY();
  845.  
  846.     // If we're in the middle of a move, draw a rubber banded box.
  847.     if (moveChild != null) {
  848.         // Make sure the event coordinates are relative to the child.
  849.         if (evt.getComponent() == this) {
  850.         x -= moveChild.getLocation().x;
  851.         y -= moveChild.getLocation().y;
  852.         }
  853.         drawRubberBox(getMoveBox(x, y));
  854.     }
  855.  
  856.         // If we're in the middle of a resize, draw a rubber-banded
  857.     // resize box.
  858.     if (resizeChild != null) {
  859.         // Make sure the event coordinates are relative to the child.
  860.         if (evt.getComponent() == this) {
  861.         x -= resizeChild.getLocation().x;
  862.         y -= resizeChild.getLocation().y;
  863.         }
  864.         drawRubberBox(getResizeBox(x, y));
  865.         }
  866.     }
  867.  
  868.     public synchronized void mouseMoved(MouseEvent evt) {
  869.     // If we're in the middle of making a connection then do 
  870.     // the rubber-banding of the connection line.
  871.     if (connectionSource != null) {
  872.         Component c = evt.getComponent();
  873.         int x = evt.getX();
  874.         int y = evt.getY();
  875.         while (c != this && c != null) {
  876.         x += c.getLocation().x;
  877.         y += c.getLocation().y;
  878.             c = c.getParent();
  879.         }
  880.         if (c != null) {
  881.             paintConnection(x, y);
  882.         }
  883.     }
  884.     
  885.     }
  886.  
  887.     //----------------------------------------------------------------------
  888.  
  889.     /**
  890.      * This method is called from a menuWorkerThread to execute
  891.      * the work associated with a given menu event.  Note that a
  892.      * new MenuWorkerThread is created for each menu event, so they
  893.      * can afford to block while they work their way through the
  894.      * processing associated with the menu action.
  895.      */
  896.  
  897.     void doMenuItem(ActionEvent evt) {
  898.  
  899.     MenuItem mi = (MenuItem)evt.getSource();
  900.     Menu parent = (Menu)mi.getParent();
  901.     String label = mi.getLabel();
  902.  
  903.     if (parent == null) {
  904.         System.err.println("domenuItem: disconnected MenuItem " + mi);
  905.         return;
  906.     }
  907.  
  908.     if (parent.getLabel().equals("File")) {
  909.         if (label.equals("Exit")) {
  910.            System.exit(0);
  911.         } else if (label.equals("Clear")) {
  912.             removeAll();
  913.             BeanBoxFrame.setCurrentComponent(null);
  914.         } else if (label.equals("Save...")) {
  915.             save();
  916.         } else if (label.equals("SerializeComponent...")) {
  917.             serializeComponent();
  918.         } else if (label.equals("MakeApplet...")) {
  919.         makeApplet();
  920.         } else if (label.equals("Load...")) {
  921.             load();
  922.         } else if (label.equals("LoadJar...")) {
  923.             loadJar();
  924.         } else if (label.equals("Print")) {
  925.             print();
  926.         }
  927.     } else if (parent.getLabel().equals("Edit")) {
  928.         if (label.equals("Cut")) {
  929.             cut();
  930.         } else if (label.equals("Copy")) {
  931.             copy();
  932.         } else if (label.equals("Customize...")) {
  933.         if (customizerClass != null) {
  934.             try {
  935.                 Customizer customizer = (Customizer) customizerClass.newInstance();
  936.                 BeanBoxFrame frame = getFrame();
  937.             Object bean = frame.getCurrentBean();
  938.                 customizer.setObject(bean);
  939.                 frame.setCustomizer(customizer);
  940.                 new CustomizerDialog(frame, customizer, bean);
  941.             } catch (Exception ex) {
  942.             System.err.println("Couldn't instantiate customizer: " + ex);
  943.             }
  944.         }
  945.         } else if (label.equals("Bind property...")) {
  946.         // Bind a source property to a target property.
  947.         doBind();
  948.         } else if (label.equals("Paste")) {
  949.             paste();
  950.         } else if (label.equals("Report...")) {
  951.         report();
  952.         }
  953.  
  954.     } else if (parent.getLabel().equals("View")) {
  955.         if (label.equals("Disable Design Mode")) {
  956.         BeanBoxFrame.setDesignTime(false);
  957.             BeanBoxFrame.getCurrentComponent().getParent().repaint();
  958.         } else if (label.equals("Enable Design Mode")) {
  959.         BeanBoxFrame.setDesignTime(true);
  960.             BeanBoxFrame.getCurrentComponent().getParent().repaint();
  961.         } else if (label.equals("Hide Invisible Beans")) {
  962.         BeanBoxFrame.setHideInvisibleBeans(true);
  963.         } else if (label.equals("Show Invisible Beans")) {
  964.         BeanBoxFrame.setHideInvisibleBeans(false);
  965.         }
  966.  
  967.         resetViewMenu();
  968.  
  969.     } else if (parent.getLabel().equals("Help")) {
  970.         if (label.equals("About...")) {
  971.         // This pops up a modal dialog.
  972.         new AboutDialog(getFrame());
  973.         } else if (label.equals("Documentation...")) {
  974.         // This pops up a modal dialog.
  975.         File cwd = new File(System.getProperty("user.dir"));
  976.         File pwd = new File(cwd.getParent());
  977.         File readme = new File(pwd, "README.html");
  978.         String mess = "Use a web browser to view the online documentation starting at\n"
  979.             + "file://" + readme;
  980.         new MessageDialog(getFrame(), "Documentation", mess);
  981.         }
  982.  
  983.     } else {
  984.         // The only place left is the "events" submenu.
  985.         // Create an event hookup from a source to a target.
  986.         doEventHookup(evt);
  987.     }    
  988.     }
  989.  
  990.     /**
  991.      * Insert a given Component instance into the current BeanBox.
  992.      */
  993.  
  994.     public void doInsert(Object bean, String beanLabel, String beanName, boolean useOldClick) {
  995.  
  996.         // Change the cursor to indicate an "insert".  (We may already
  997.     // have done this, but that's OK.)
  998.  
  999.     setCursor(crosshairCursor);
  1000.  
  1001.     // Wait for a mouse down event.
  1002.     MouseEvent evt;
  1003.     synchronized (this) {
  1004.         if (!useOldClick) {
  1005.             mouseClickEvent = null;
  1006.         }
  1007.         while (mouseClickEvent == null) {
  1008.             try {
  1009.                 wait();
  1010.             } catch (InterruptedException ex) {
  1011.             break;
  1012.             }
  1013.         }
  1014.         evt = mouseClickEvent;
  1015.     }
  1016.  
  1017.     // Revert to the default cursor.
  1018.     setCursor(defaultCursor);
  1019.  
  1020.     if (evt == null) {
  1021.         // We were interrupted.
  1022.         return;
  1023.     }
  1024.  
  1025.     // If its a BeanBox, color it a darker shade than the current.
  1026.     // Nested BeanBoxes are currently disabled - epll.
  1027.     if (bean instanceof BeanBox) {
  1028.         BeanBox bb = (BeanBox)bean;
  1029.         bb.setSize(400,200);
  1030.         int r = getBackground().getRed();
  1031.         int g = getBackground().getGreen();
  1032.         int b = getBackground().getBlue();
  1033.         Color newColor = new Color((r*9)/10, (g*9)/10, (b*9)/10);
  1034.         bb.setBackground(newColor);
  1035.     }
  1036.  
  1037.     // Create a Wrapper for the child
  1038.     Wrapper child = new Wrapper(bean, beanLabel, beanName);
  1039.  
  1040.     // Insert and reshape the child component.
  1041.     add(child);
  1042.     int childWidth = child.getPreferredSize().width;
  1043.     int childHeight = child.getPreferredSize().height;
  1044.     int x = evt.getX() - childWidth/2;
  1045.     int y = evt.getY() - childHeight/2;
  1046.     child.setBounds(x, y, childWidth, childHeight);
  1047.  
  1048.     if (Beans.isInstanceOf(bean, Applet.class)) {
  1049.         Applet apl = (Applet) Beans.getInstanceOf(bean, Applet.class);
  1050.         apl.start();
  1051.     }
  1052.  
  1053.     // Make the child the focus.
  1054.         BeanBoxFrame.setCurrentComponent(child);
  1055.  
  1056.     // Notice that we do not attach mouse event listeners to the child
  1057.     // or to the wrapped bean.  This allows them to use the old
  1058.         // AWT event model if the bean is a transitional bean.
  1059.     // We rely on the wrapper calling our MouseListener and
  1060.         // MouseMotionListener methods when mouse events happen.
  1061.     }
  1062.  
  1063.     //----------------------------------------------------------------------
  1064.  
  1065.     /**
  1066.      * Schedule a menu item to be executed asynchronously in the BeanBox's
  1067.      * menu handling thread.
  1068.      */
  1069.  
  1070.     public synchronized void queueMenuItem(ActionEvent evt) {
  1071.  
  1072.     if (events == null) {
  1073.         events = new Vector();
  1074.     }
  1075.     events.addElement(evt);
  1076.     notifyAll();
  1077.     if (eventThread == null) {
  1078.         eventThread = new Thread(this);
  1079.         eventThread.start();
  1080.     }
  1081.     }
  1082.  
  1083.     // Main method for our internal MenuItem handling thread.
  1084.     // This guy lets us minimize the amount of work we do in the AWT event 
  1085.     // thread, which reduces the risk of deadlock.
  1086.     public void run() {
  1087.     for (;;) {
  1088.         // Wait for an event.
  1089.         ActionEvent evt;
  1090.         synchronized (this) {
  1091.         while (events.size() == 0) {
  1092.             try {
  1093.                 wait();
  1094.             } catch (InterruptedException ix) {
  1095.             }
  1096.         }
  1097.         evt = (ActionEvent) events.elementAt(0);
  1098.         events.removeElementAt(0);
  1099.         }
  1100.         // now process the event.
  1101.         try {
  1102.         doMenuItem(evt);
  1103.         } catch (Throwable ex) {
  1104.         System.err.println("BeanBox caught exception "+ex+" while processing: "+evt.getActionCommand());
  1105.         System.err.println("  msg: "+ex.getMessage());
  1106.         if (ex instanceof ExceptionInInitializerError) {
  1107.             ExceptionInInitializerError ex2 =
  1108.             (ExceptionInInitializerError) ex;
  1109.             Throwable e = ex2.getException();
  1110.             e.printStackTrace();
  1111.         }
  1112.         }
  1113.     }
  1114.     }
  1115.  
  1116.     //----------------------------------------------------------------------
  1117.  
  1118.     /**
  1119.      * Someone has done a mouse button down on the "wrapper" around the bean.
  1120.      * This starts a move that will be terminated when they release the
  1121.      * mouse button.  We will draw a rubbed-banded box to indicate the
  1122.      * current move position.
  1123.      */
  1124.  
  1125.     void startMove(Wrapper child, int x, int y) {
  1126.     moveChild = child;
  1127.     moveStartX = x;
  1128.     moveStartY = y;
  1129.     }
  1130.  
  1131.     /**
  1132.      * Figure out the on-screen box to be drawn to represent the proposed
  1133.      * new move location of a bean we're moving.
  1134.      */
  1135.  
  1136.     Rectangle getMoveBox(int mx, int my) {
  1137.  
  1138.     int x = moveChild.getLocation().x;
  1139.     int y = moveChild.getLocation().y;
  1140.     int w = moveChild.getSize().width;
  1141.     int h = moveChild.getSize().height;
  1142.     x = x + mx - moveStartX;    
  1143.     y = y + my - moveStartY;
  1144.     return new Rectangle(x, y, w, h);
  1145.     }
  1146.  
  1147.     /**
  1148.      * Complete a move started with "startMove".
  1149.      */
  1150.  
  1151.     void finishMove(int mx, int my) {
  1152.     Rectangle box = getMoveBox(mx, my);
  1153.     moveChild.setBounds(box.x, box.y, box.width, box.height);
  1154.     deleteRubberBox();
  1155.     moveChild = null;
  1156.     }
  1157.  
  1158.     //----------------------------------------------------------------------
  1159.  
  1160.     /**
  1161.      * Someone has done a mouse button down on a corner of the "wrapper"
  1162.      * around the bean.  This starts a resize sequence that will be
  1163.      * terminated when they release the mouse button.  We will draw a 
  1164.      * rubbed-banded box to indicate the proposed resize shape..
  1165.      */
  1166.  
  1167.     void startResize(Wrapper child, int x, int y, Cursor cursor) {
  1168.     resizeStartX = child.getLocation().x + x;
  1169.     resizeStartY = child.getLocation().y + y;
  1170.     resizeChild = child;
  1171.     resizeCursor = cursor;
  1172.     }
  1173.  
  1174.     /**
  1175.      * Figure out the box to draw to imndicate the result of an
  1176.      * in-progress resize.  This is slightly complicated because
  1177.      * it depends on which corner they picked-up to begin the
  1178.      * resize.
  1179.      */
  1180.     Rectangle getResizeBox(int mx, int my) {
  1181.  
  1182.     int x = resizeChild.getLocation().x;
  1183.     int y = resizeChild.getLocation().y;
  1184.     int w = resizeChild.getSize().width;
  1185.     int h = resizeChild.getSize().height;
  1186.     if (resizeCursor == nwResizeCursor) {
  1187.         w = w - mx;
  1188.         h = h - my;
  1189.         x = x + mx;
  1190.         y = y + my;
  1191.         } else if (resizeCursor == swResizeCursor) {
  1192.         w = w - mx;
  1193.         h = my;
  1194.         x = x + mx;
  1195.         } else if (resizeCursor == neResizeCursor) {
  1196.         w = mx;
  1197.         h = h - my;
  1198.         y = y + my;
  1199.         } else if (resizeCursor == seResizeCursor) {
  1200.         w = mx;
  1201.         h = my;
  1202.     }
  1203.     if (w < 10) {
  1204.         w = 10;
  1205.     }
  1206.     if (h < 10) {
  1207.         h = 10;
  1208.     }
  1209.     return new Rectangle(x, y, w, h);
  1210.     }
  1211.  
  1212.     /** 
  1213.      * Complete a resize begin with startResize.
  1214.      */
  1215.  
  1216.     void finishResize(int mx, int my) {
  1217.     Rectangle box = getResizeBox(mx, my);
  1218.     resizeChild.setBounds(box.x, box.y, box.width, box.height);
  1219.     resizeChild.doLayout();
  1220.     deleteRubberBox();
  1221.     resizeChild = null;
  1222.     }
  1223.  
  1224.     //----------------------------------------------------------------------
  1225.  
  1226.     private void drawRubberBox(Rectangle box) {
  1227.     Graphics g = getGraphics();
  1228.     if (g == null) {
  1229.         return;
  1230.     }
  1231.     // First remove any existing rubber box.
  1232.     deleteRubberBox();
  1233.     // Now draw the new rubber box.
  1234.     g.setColor(Color.red);
  1235.     g.drawRect(box.x, box.y, box.width, box.height);    
  1236.     oldRubberBox = box;
  1237.     }
  1238.  
  1239.     private void deleteRubberBox() {
  1240.     if (oldRubberBox != null) {
  1241.         Graphics g = getGraphics();
  1242.         if (g == null) {
  1243.             return;
  1244.         }
  1245.         g.setColor(getBackground());
  1246.         g.drawRect(oldRubberBox.x, oldRubberBox.y, 
  1247.             oldRubberBox.width, oldRubberBox.height);    
  1248.         oldRubberBox = null;
  1249.     }
  1250.     }
  1251.  
  1252.     //----------------------------------------------------------------------
  1253.  
  1254.     void resetViewMenu() {
  1255.     BeanBoxFrame frame = getFrame();
  1256.     Menu viewMenu = getFrame().getMenuBar().getMenu(2);
  1257.     viewMenu.removeAll();
  1258.     if (Beans.isDesignTime()) {
  1259.         addMenuItem(frame, viewMenu, new MenuItem("Disable Design Mode"));
  1260.     } else {
  1261.         addMenuItem(frame, viewMenu, new MenuItem("Enable Design Mode"));
  1262.     }
  1263.     if (BeanBoxFrame.getHideInvisibleBeans()) {
  1264.         addMenuItem(frame, viewMenu, new MenuItem("Show Invisible Beans"));
  1265.     } else {
  1266.         addMenuItem(frame, viewMenu, new MenuItem("Hide Invisible Beans"));
  1267.     }
  1268.     }
  1269.  
  1270.     //----------------------------------------------------------------------
  1271.  
  1272.     /**
  1273.      * Figure out the top-level BeanBoxFrame that contains the current
  1274.      * BeanBox.
  1275.      */
  1276.  
  1277.     private synchronized BeanBoxFrame getFrame() {
  1278.     if (ourFrame != null) {
  1279.         return ourFrame;
  1280.     }
  1281.     Component c = this;
  1282.     while (c != null) {
  1283.         if (c instanceof BeanBoxFrame) {
  1284.         ourFrame = (BeanBoxFrame) c;
  1285.         return ourFrame;
  1286.         }
  1287.         c = c.getParent();
  1288.     }
  1289.     // This should never happen
  1290.     throw new Error("Couldn't find frame ?!?");
  1291.     }
  1292.  
  1293.     //----------------------------------------------------------------------
  1294.  
  1295.     // Log an error.
  1296.  
  1297.     void error(String message, Exception ex) {
  1298.     String mess = message + ":\n" + ex;
  1299.     System.err.println(message);
  1300.     ex.printStackTrace();
  1301.     // Popup an ErrorDialog with the given error message.
  1302.     new ErrorDialog(getFrame(), mess);
  1303.  
  1304.     }
  1305.  
  1306.     void error(String message) {
  1307.     System.err.println(message);
  1308.     // Popup an ErrorDialog with the given error message.
  1309.     new ErrorDialog(getFrame(), message);
  1310.  
  1311.     }
  1312.  
  1313.     private static boolean debug = false;
  1314.  
  1315.     static void debug(String msg) {
  1316.     if (debug) {
  1317.         System.err.println("BeanBox:: "+msg);
  1318.     }
  1319.     }
  1320.  
  1321.     //----------------------------------------------------------------------
  1322.  
  1323.     transient BeanBoxFrame ourFrame;
  1324.  
  1325.     transient Component connectionSource;
  1326.     transient int oldX1 = -1;
  1327.     transient int oldX2;
  1328.     transient int oldY1;
  1329.     transient int oldY2;
  1330.     transient Rectangle oldRubberBox;
  1331.   
  1332.     transient Hashtable methodMap;   // maps MenuItems to Methods
  1333.     transient Hashtable eventMap;   // maps Menus to EventSetDescriptors
  1334.     transient Class customizerClass;
  1335.  
  1336.     private static Hashtable serNames = new Hashtable();
  1337.  
  1338.     // If moveChild is non-null, we're moving that child
  1339.     transient Wrapper moveChild;
  1340.     transient int moveStartX;
  1341.     transient int moveStartY;
  1342.  
  1343.     // If resizeChild is non-null, we're resizing that child
  1344.     transient Wrapper resizeChild;
  1345.     transient Cursor resizeCursor;
  1346.     transient int resizeStartX;
  1347.     transient int resizeStartY;
  1348.  
  1349.     private final static int padX = 10;
  1350.     private final static int padY = 10;
  1351.  
  1352.     private final static String defaultStoreFile = "beanbox.tmp";
  1353.     private final static String defaultSerializeFile = "example.ser";
  1354.  
  1355.     // We keep a private event queue and a thread to process them.
  1356.     transient private Thread eventThread;
  1357.     transient private Vector events;
  1358.  
  1359.     // MouseClickEvent describes the moset recent mouse click event.
  1360.     private transient MouseEvent mouseClickEvent;
  1361.     private transient long mousePressedWhen = 0;
  1362.  
  1363.     // Shorthands for the cursors.
  1364.     private static Cursor nwResizeCursor = Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR);
  1365.     private static Cursor neResizeCursor = Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR);
  1366.     private static Cursor swResizeCursor = Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR);
  1367.     private static Cursor seResizeCursor = Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR);
  1368.     private static Cursor crosshairCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
  1369.     private static Cursor defaultCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  1370. }
  1371.  
  1372.  
  1373. /**
  1374.  * Auxiliary class to deliver the InputStream
  1375.  */
  1376.  
  1377. class MyProducer implements InputStreamProducer {
  1378.     private String name;
  1379.  
  1380.     public MyProducer(String fileName) {
  1381.     this.name = fileName;
  1382.     }
  1383.  
  1384.     public synchronized InputStream getInputStream() {
  1385.     try {
  1386.         return new FileInputStream(name);
  1387.     } catch (Exception ex) {
  1388.         return null;
  1389.     }
  1390.     }
  1391. }
  1392.