/*
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 String name = props[k].getDisplayName();
boolean added = false;
for (int i=0; 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 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 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 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 {
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 {
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 {
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; }
}
}
}