BeanContainer.java Source code

Java tutorial

Introduction

Here is the source code for BeanContainer.java

Source

    /*
    Swing, Second Edition
    by Matthew Robinson, Pavel Vorobiev
    
    */

    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.beans.*;
    import java.lang.reflect.*;
    import java.util.*;

    import javax.swing.*;
    import javax.swing.table.*;
    import javax.swing.event.*;

public class BeanContainer extends JFrame implements FocusListener{
  protected File m_currentDir = new File(".");
  protected Component m_activeBean;
  protected String m_className = "clock.Clock";
  protected JFileChooser m_chooser = new JFileChooser();
  protected Hashtable m_editors = new Hashtable();

  public BeanContainer() {
    super("Simple Bean Container");
    getContentPane().setLayout(new FlowLayout());
   
    setSize(300, 300);

    JPopupMenu.setDefaultLightWeightPopupEnabled(false);

    JMenuBar menuBar = createMenuBar();
    setJMenuBar(menuBar);

    WindowListener wndCloser = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    };
    addWindowListener(wndCloser);

    setVisible(true);
  }

  protected JMenuBar createMenuBar() {
    JMenuBar menuBar = new JMenuBar();
    
    JMenu mFile = new JMenu("File");

    JMenuItem mItem = new JMenuItem("New...");
    ActionListener lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {  
        Thread newthread = new Thread() {
          public void run() {
            String result = (String)JOptionPane.showInputDialog(
              BeanContainer.this, 
              "Please enter class name to create a new bean", 
              "Input", JOptionPane.INFORMATION_MESSAGE, null, 
              null, m_className);
            repaint();
            if (result==null)
              return;
            try {
              m_className = result;
              Class cls = Class.forName(result);
              Object obj = cls.newInstance();
              if (obj instanceof Component) {
                m_activeBean = (Component)obj;
                m_activeBean.addFocusListener(
                  BeanContainer.this);
                m_activeBean.requestFocus();
                getContentPane().add(m_activeBean);
              }
              validate();
            }
            catch (Exception ex) {
              ex.printStackTrace();
              JOptionPane.showMessageDialog(
                BeanContainer.this, "Error: "+ex.toString(),
                "Warning", JOptionPane.WARNING_MESSAGE);
            }
          }
        };
        newthread.start();
      }
    };
    mItem.addActionListener(lst);
    mFile.add(mItem);

    mItem = new JMenuItem("Load...");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {  
        Thread newthread = new Thread() {
          public void run() {
            m_chooser.setCurrentDirectory(m_currentDir);
            m_chooser.setDialogTitle(
              "Please select file with serialized bean");
            int result = m_chooser.showOpenDialog(
              BeanContainer.this);
            repaint();
            if (result != JFileChooser.APPROVE_OPTION)
              return;
            m_currentDir = m_chooser.getCurrentDirectory();
            File fChoosen = m_chooser.getSelectedFile();
            try {
              FileInputStream fStream = 
                new FileInputStream(fChoosen);
              ObjectInput  stream  =  
                new ObjectInputStream(fStream);
              Object obj = stream.readObject();
              if (obj instanceof Component) {
                m_activeBean = (Component)obj;
                m_activeBean.addFocusListener(
                  BeanContainer.this);
                m_activeBean.requestFocus();
                getContentPane().add(m_activeBean);
              }
              stream.close();
              fStream.close();
              validate();
            }
            catch (Exception ex) {
              ex.printStackTrace();
              JOptionPane.showMessageDialog(
                BeanContainer.this, "Error: "+ex.toString(),
                "Warning", JOptionPane.WARNING_MESSAGE);
            }
            repaint();
          }
        };
        newthread.start();
      }
    };
    mItem.addActionListener(lst);
    mFile.add(mItem);

    mItem = new JMenuItem("Save...");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        Thread newthread = new Thread() {
          public void run() {
            if (m_activeBean == null)
              return;
            m_chooser.setDialogTitle(
              "Please choose file to serialize bean");
            m_chooser.setCurrentDirectory(m_currentDir);
            int result = m_chooser.showSaveDialog(
              BeanContainer.this);
            repaint();
            if (result != JFileChooser.APPROVE_OPTION)
              return;
            m_currentDir = m_chooser.getCurrentDirectory();
            File fChoosen = m_chooser.getSelectedFile();
            try {
              FileOutputStream fStream = 
                new FileOutputStream(fChoosen);
              ObjectOutput stream  =  
                new ObjectOutputStream(fStream);
              stream.writeObject(m_activeBean);
              stream.close();
              fStream.close();
            }
            catch (Exception ex) {
              ex.printStackTrace();
            JOptionPane.showMessageDialog(
              BeanContainer.this, "Error: "+ex.toString(),
              "Warning", JOptionPane.WARNING_MESSAGE);
            }
          }
        };
        newthread.start();
      }
    };
    mItem.addActionListener(lst);
    mFile.add(mItem);

    mFile.addSeparator();

    mItem = new JMenuItem("Exit");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    };
    mItem.addActionListener(lst);
    mFile.add(mItem);
    menuBar.add(mFile);
    
    JMenu mEdit = new JMenu("Edit");

    mItem = new JMenuItem("Delete");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        if (m_activeBean == null)
          return;
        Object obj = m_editors.get(m_activeBean);
        if (obj != null) {
          BeanEditor editor = (BeanEditor)obj;
          editor.dispose();
          m_editors.remove(m_activeBean);
        }
        getContentPane().remove(m_activeBean);
        m_activeBean = null;
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    mEdit.add(mItem);

    mItem = new JMenuItem("Properties...");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        if (m_activeBean == null)
          return;
        Object obj = m_editors.get(m_activeBean);
        if (obj != null) {
          BeanEditor editor = (BeanEditor)obj;
          editor.setVisible(true);
          editor.toFront();
        }
        else {
          BeanEditor editor = new BeanEditor(m_activeBean);
          m_editors.put(m_activeBean, editor);
        }
      }
    };
    mItem.addActionListener(lst);
    mEdit.add(mItem);
    menuBar.add(mEdit);

    JMenu mLayout = new JMenu("Layout");
    ButtonGroup group = new ButtonGroup();

    mItem = new JRadioButtonMenuItem("FlowLayout");
    mItem.setSelected(true);
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e){
        getContentPane().setLayout(new FlowLayout());
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    group.add(mItem);
    mLayout.add(mItem);

    mItem = new JRadioButtonMenuItem("GridLayout");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e){
        int col = 3;
        int row = (int)Math.ceil(getContentPane().
          getComponentCount()/(double)col);
        getContentPane().setLayout(new GridLayout(row, col, 10, 10));
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    group.add(mItem);
    mLayout.add(mItem);
    
    mItem = new JRadioButtonMenuItem("BoxLayout - X");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        getContentPane().setLayout(new BoxLayout(
          getContentPane(), BoxLayout.X_AXIS));
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    group.add(mItem);
    mLayout.add(mItem);
    
    mItem = new JRadioButtonMenuItem("BoxLayout - Y");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        getContentPane().setLayout(new BoxLayout(
          getContentPane(), BoxLayout.Y_AXIS));
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    group.add(mItem);
    mLayout.add(mItem);
    
    mItem = new JRadioButtonMenuItem("DialogLayout");
    lst = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        getContentPane().setLayout(new DialogLayout());
        validate();
        repaint();
      }
    };
    mItem.addActionListener(lst);
    group.add(mItem);
    mLayout.add(mItem);

    menuBar.add(mLayout);

    return menuBar;
  }

  public void focusGained(FocusEvent e) {
    m_activeBean = e.getComponent();
    repaint();
  }

  public void focusLost(FocusEvent e) {}

  // This is a heavyweight component so we override paint
  // instead of paintComponent. super.paint(g) will
  // paint all child components first, and then we 
  // simply draw over top of them.
  public void paint(Graphics g) {
    super.paint(g);

    if (m_activeBean == null)
      return;

    Point pt = getLocationOnScreen();
    Point pt1 = m_activeBean.getLocationOnScreen();
    int x = pt1.x - pt.x - 2;
    int y = pt1.y - pt.y - 2;
    int w = m_activeBean.getWidth() + 2;
    int h = m_activeBean.getHeight() + 2;

    g.setColor(Color.black);
    g.drawRect(x, y, w, h);
  }

  public static void main(String argv[]) {
    new BeanContainer();
  }
}

    class BeanEditor extends JFrame implements PropertyChangeListener {
        protected Component m_bean;
        protected JTable m_table;
        protected PropertyTableData m_data;

        public BeanEditor(Component bean) {
            m_bean = bean;
            m_bean.addPropertyChangeListener(this);

            Point pt = m_bean.getLocationOnScreen();
            setBounds(pt.x + 50, pt.y + 10, 400, 300);
            getContentPane().setLayout(new BorderLayout());

            m_data = new PropertyTableData(m_bean);
            m_table = new JTable(m_data);

            JScrollPane ps = new JScrollPane();
            ps.getViewport().add(m_table);
            getContentPane().add(ps, BorderLayout.CENTER);

            setDefaultCloseOperation(HIDE_ON_CLOSE);
            setVisible(true);
        }

        public void propertyChange(PropertyChangeEvent evt) {
            m_data.setProperty(evt.getPropertyName(), evt.getNewValue());
        }

        class PropertyTableData extends AbstractTableModel {
            protected String[][] m_properties;
            protected int m_numProps = 0;
            protected Vector m_v;

            public PropertyTableData(Component bean) {
                try {
                    BeanInfo info = Introspector.getBeanInfo(m_bean.getClass());
                    BeanDescriptor descr = info.getBeanDescriptor();
                    setTitle("Editing " + descr.getName());
                    PropertyDescriptor[] props = info.getPropertyDescriptors();
                    m_numProps = props.length;

                    m_v = new Vector(m_numProps);
                    for (int k = 0; k < m_numProps; k++) {
                        String name = props[k].getDisplayName();
                        boolean added = false;
                        for (int i = 0; i < m_v.size(); i++) {
                            String str = ((PropertyDescriptor) m_v.elementAt(i)).getDisplayName();
                            if (name.compareToIgnoreCase(str) < 0) {
                                m_v.insertElementAt(props[k], i);
                                added = true;
                                break;
                            }
                        }
                        if (!added)
                            m_v.addElement(props[k]);
                    }

                    m_properties = new String[m_numProps][2];
                    for (int k = 0; k < m_numProps; k++) {
                        PropertyDescriptor prop = (PropertyDescriptor) m_v.elementAt(k);
                        m_properties[k][0] = prop.getDisplayName();
                        Method mRead = prop.getReadMethod();
                        if (mRead != null && mRead.getParameterTypes().length == 0) {
                            Object value = mRead.invoke(m_bean, null);
                            m_properties[k][1] = objToString(value);
                        } else
                            m_properties[k][1] = "error";
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(BeanEditor.this, "Error: " + ex.toString(), "Warning",
                            JOptionPane.WARNING_MESSAGE);
                }
            }

            public void setProperty(String name, Object value) {
                for (int k = 0; k < m_numProps; k++)
                    if (name.equals(m_properties[k][0])) {
                        m_properties[k][1] = objToString(value);
                        m_table.tableChanged(new TableModelEvent(this, k));
                        m_table.repaint();
                        break;
                    }
            }

            public int getRowCount() {
                return m_numProps;
            }

            public int getColumnCount() {
                return 2;
            }

            public String getColumnName(int nCol) {
                return nCol == 0 ? "Property" : "Value";
            }

            public boolean isCellEditable(int nRow, int nCol) {
                return (nCol == 1);
            }

            public Object getValueAt(int nRow, int nCol) {
                if (nRow < 0 || nRow >= getRowCount())
                    return "";
                switch (nCol) {
                case 0:
                    return m_properties[nRow][0];
                case 1:
                    return m_properties[nRow][1];
                }
                return "";
            }

            public void setValueAt(Object value, int nRow, int nCol) {
                if (nRow < 0 || nRow >= getRowCount())
                    return;
                String str = value.toString();
                PropertyDescriptor prop = (PropertyDescriptor) m_v.elementAt(nRow);
                Class cls = prop.getPropertyType();
                Object obj = stringToObj(str, cls);
                if (obj == null)
                    return; // can't process

                Method mWrite = prop.getWriteMethod();
                if (mWrite == null || mWrite.getParameterTypes().length != 1)
                    return;
                try {
                    mWrite.invoke(m_bean, new Object[] { obj });
                    m_bean.getParent().doLayout();
                    m_bean.getParent().repaint();
                    m_bean.repaint();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(BeanEditor.this, "Error: " + ex.toString(), "Warning",
                            JOptionPane.WARNING_MESSAGE);
                }
                m_properties[nRow][1] = str;
            }

            public String objToString(Object value) {
                if (value == null)
                    return "null";
                if (value instanceof Dimension) {
                    Dimension dim = (Dimension) value;
                    return "" + dim.width + "," + dim.height;
                } else if (value instanceof Insets) {
                    Insets ins = (Insets) value;
                    return "" + ins.left + "," + ins.top + "," + ins.right + "," + ins.bottom;
                } else if (value instanceof Rectangle) {
                    Rectangle rc = (Rectangle) value;
                    return "" + rc.x + "," + rc.y + "," + rc.width + "," + rc.height;
                } else if (value instanceof Color) {
                    Color col = (Color) value;
                    return "" + col.getRed() + "," + col.getGreen() + "," + col.getBlue();
                }
                return value.toString();
            }

            public Object stringToObj(String str, Class cls) {
                try {
                    if (str == null)
                        return null;
                    String name = cls.getName();
                    if (name.equals("java.lang.String"))
                        return str;
                    else if (name.equals("int"))
                        return new Integer(str);
                    else if (name.equals("long"))
                        return new Long(str);
                    else if (name.equals("float"))
                        return new Float(str);
                    else if (name.equals("double"))
                        return new Double(str);
                    else if (name.equals("boolean"))
                        return new Boolean(str);
                    else if (name.equals("java.awt.Dimension")) {
                        int[] i = strToInts(str);
                        return new Dimension(i[0], i[1]);
                    } else if (name.equals("java.awt.Insets")) {
                        int[] i = strToInts(str);
                        return new Insets(i[0], i[1], i[2], i[3]);
                    } else if (name.equals("java.awt.Rectangle")) {
                        int[] i = strToInts(str);
                        return new Rectangle(i[0], i[1], i[2], i[3]);
                    } else if (name.equals("java.awt.Color")) {
                        int[] i = strToInts(str);
                        return new Color(i[0], i[1], i[2]);
                    }
                    return null; // not supported
                } catch (Exception ex) {
                    return null;
                }
            }

            public int[] strToInts(String str) throws Exception {
                int[] i = new int[4];
                StringTokenizer tokenizer = new StringTokenizer(str, ",");
                for (int k = 0; k < i.length && tokenizer.hasMoreTokens(); k++)
                    i[k] = Integer.parseInt(tokenizer.nextToken());
                return i;
            }
        }
    }

    /**
       DialogLayout
    */
    class DialogLayout implements LayoutManager {
        protected int m_divider = -1;
        protected int m_hGap = 10;
        protected int m_vGap = 5;

        public DialogLayout() {
        }

        public DialogLayout(int hGap, int vGap) {
            m_hGap = hGap;
            m_vGap = vGap;
        }

        public void addLayoutComponent(String name, Component comp) {
        }

        public void removeLayoutComponent(Component comp) {
        }

        public Dimension preferredLayoutSize(Container parent) {
            int divider = getDivider(parent);

            int w = 0;
            int h = 0;
            for (int k = 1; k < parent.getComponentCount(); k += 2) {
                Component comp = parent.getComponent(k);
                Dimension d = comp.getPreferredSize();
                w = Math.max(w, d.width);
                h += d.height + m_vGap;
            }
            h -= m_vGap;

            Insets insets = parent.getInsets();
            return new Dimension(divider + w + insets.left + insets.right, h + insets.top + insets.bottom);
        }

        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        public void layoutContainer(Container parent) {
            int divider = getDivider(parent);

            Insets insets = parent.getInsets();
            int w = parent.getWidth() - insets.left - insets.right - divider;
            int x = insets.left;
            int y = insets.top;

            for (int k = 1; k < parent.getComponentCount(); k += 2) {
                Component comp1 = parent.getComponent(k - 1);
                Component comp2 = parent.getComponent(k);
                Dimension d = comp2.getPreferredSize();

                comp1.setBounds(x, y, divider - m_hGap, d.height);
                comp2.setBounds(x + divider, y, w, d.height);
                y += d.height + m_vGap;
            }
        }

        public int getHGap() {
            return m_hGap;
        }

        public int getVGap() {
            return m_vGap;
        }

        public void setDivider(int divider) {
            if (divider > 0)
                m_divider = divider;
        }

        public int getDivider() {
            return m_divider;
        }

        protected int getDivider(Container parent) {
            if (m_divider > 0)
                return m_divider;

            int divider = 0;
            for (int k = 0; k < parent.getComponentCount(); k += 2) {
                Component comp = parent.getComponent(k);
                Dimension d = comp.getPreferredSize();
                divider = Math.max(divider, d.width);
            }
            divider += m_hGap;
            return divider;
        }

        public String toString() {
            return getClass().getName() + "[hgap=" + m_hGap + ",vgap=" + m_vGap + ",divider=" + m_divider + "]";
        }
    }

    ///////////File: Clock.java

    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.beans.*;
    import java.io.*;
    import java.util.*;

    import javax.swing.*;
    import javax.swing.border.*;

    public class Clock extends JButton implements Customizer, Externalizable, Runnable {

        protected PropertyChangeSupport m_helper;
        protected boolean m_digital = false;
        protected Calendar m_calendar;
        protected Dimension m_preffSize;

        public Clock() {
            m_calendar = Calendar.getInstance();
            m_helper = new PropertyChangeSupport(this);

            Border br1 = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(128, 0, 0));
            Border br2 = new MatteBorder(4, 4, 4, 4, Color.red);
            setBorder(new CompoundBorder(br1, br2));

            setBackground(Color.white);
            setForeground(Color.black);

            (new Thread(this)).start();
        }

        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeBoolean(m_digital);
            out.writeObject(getBackground());
            out.writeObject(getForeground());
            out.writeObject(getPreferredSize());
        }

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            setDigital(in.readBoolean());
            setBackground((Color) in.readObject());
            setForeground((Color) in.readObject());
            setPreferredSize((Dimension) in.readObject());
        }

        public Dimension getPreferredSize() {
            if (m_preffSize != null)
                return m_preffSize;
            else
                return new Dimension(50, 50);
        }

        public void setPreferredSize(Dimension preffSize) {
            m_preffSize = preffSize;
        }

        public Dimension getMinimumSize() {
            return getPreferredSize();
        }

        public Dimension getMaximumSize() {
            return getPreferredSize();
        }

        public void setDigital(boolean digital) {
            m_helper.firePropertyChange("digital", new Boolean(m_digital), new Boolean(digital));
            m_digital = digital;
            repaint();
        }

        public boolean getDigital() {
            return m_digital;
        }

        public void addPropertyChangeListener(PropertyChangeListener lst) {
            if (m_helper != null)
                m_helper.addPropertyChangeListener(lst);
        }

        public void removePropertyChangeListener(PropertyChangeListener lst) {
            if (m_helper != null)
                m_helper.removePropertyChangeListener(lst);
        }

        public void setObject(Object bean) {
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Color colorRetainer = g.getColor();

            g.setColor(getBackground());
            g.fillRect(0, 0, getWidth(), getHeight());
            getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());

            m_calendar.setTime(new Date()); // get current time
            int hrs = m_calendar.get(Calendar.HOUR_OF_DAY);
            int min = m_calendar.get(Calendar.MINUTE);

            g.setColor(getForeground());
            if (m_digital) {
                String time = "" + hrs + ":" + min;
                g.setFont(getFont());
                FontMetrics fm = g.getFontMetrics();
                int y = (getHeight() + fm.getAscent()) / 2;
                int x = (getWidth() - fm.stringWidth(time)) / 2;
                g.drawString(time, x, y);
            } else {
                int x = getWidth() / 2;
                int y = getHeight() / 2;
                int rh = getHeight() / 4;
                int rm = getHeight() / 3;

                double ah = ((double) hrs + min / 60.0) / 6.0 * Math.PI;
                double am = min / 30.0 * Math.PI;

                g.drawLine(x, y, (int) (x + rh * Math.sin(ah)), (int) (y - rh * Math.cos(ah)));
                g.drawLine(x, y, (int) (x + rm * Math.sin(am)), (int) (y - rm * Math.cos(am)));
            }

            g.setColor(colorRetainer);
        }

        public void run() {
            while (true) {
                repaint();
                try {
                    Thread.sleep(30 * 1000);
                } catch (InterruptedException ex) {
                    break;
                }
            }
        }
    }