FileDocCategorySizeDatePackage
PropertyTable.javaAPI DocExample6153Sat Jan 24 10:44:34 GMT 2004je3.gui

PropertyTable.java

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
package je3.gui;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;   // TableModel and other JTable-related classes
import java.beans.*;          // For JavaBean introspection
import java.util.*;           // For array sorting 

/**
 * This class is a JTable subclass that displays a table of the JavaBeans
 * properties of any specified class.
 **/
public class PropertyTable extends JTable {
    /** This main method allows the class to be demonstrated  standalone */
    public static void main(String[] args) {
	// Specify the name of the class as a command-line argument
	Class beanClass = null;
 	try {
	    // Use reflection to get the Class from the classname
	    beanClass = Class.forName(args[0]);
	}
	catch (Exception e) {  // Report errors
	    System.out.println("Can't find specified class: "+e.getMessage());
	    System.out.println("Usage: java PropertyTable <bean class name>");
	    System.exit(0);
	}
	
	// Create a table to display the properties of the specified class
	JTable table = new PropertyTable(beanClass);
	
	// Then put the table in a scrolling window, put the scrolling 
	// window into a frame, and pop it all up on to the screen
	JScrollPane scrollpane = new JScrollPane(table);
	JFrame frame = new JFrame("Properties of JavaBean: " + args[0]);
	frame.getContentPane().add(scrollpane);
	frame.setSize(500, 400);
	frame.setVisible(true);
    }

    /**
     * This constructor method specifies what data the table will display
     * (the table model) and uses the TableColumnModel to customize the
     * way that the table displays it.  The hard work is done by the
     * TableModel implementation below.
     **/
    public PropertyTable(Class beanClass) {
	// Set the data model for this table
	try {
	    setModel(new JavaBeanPropertyTableModel(beanClass));
	}
	catch (IntrospectionException e) {
	    System.err.println("WARNING: can't introspect: " + beanClass);
	}
	
	// Tweak the appearance of the table by manipulating its column model
	TableColumnModel colmodel = getColumnModel();
	
	// Set column widths
	colmodel.getColumn(0).setPreferredWidth(125);
	colmodel.getColumn(1).setPreferredWidth(200);
	colmodel.getColumn(2).setPreferredWidth(75);
	colmodel.getColumn(3).setPreferredWidth(50);
	
	// Right justify the text in the first column
	TableColumn namecol = colmodel.getColumn(0);
	DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
	renderer.setHorizontalAlignment(SwingConstants.RIGHT);
	namecol.setCellRenderer(renderer);
    }

    /**
     * This class implements TableModel and represents JavaBeans property data
     * in a way that the JTable component can display.  If you've got some
     * type of tabular data to display, implement a TableModel class to
     * describe that data, and the JTable component will be able to display it.
     **/
    static class JavaBeanPropertyTableModel extends AbstractTableModel {
	PropertyDescriptor[] properties;  // The properties to display

	/**
	 * The constructor: use the JavaBeans introspector mechanism to get 
	 * information about all the properties of a bean.  Once we've got
	 * this information, the other methods will interpret it for JTable.
	 **/
	public JavaBeanPropertyTableModel(Class beanClass)
	    throws java.beans.IntrospectionException
	{
	    // Use the introspector class to get "bean info" about the class.
	    BeanInfo beaninfo = Introspector.getBeanInfo(beanClass);
	    // Get the property descriptors from that BeanInfo class
	    properties = beaninfo.getPropertyDescriptors();
	    // Now do a case-insensitive sort by property name
	    // The anonymous Comparator implementation specifies how to 
	    // sort PropertyDescriptor objects by name
	    Arrays.sort(properties, new Comparator() {
		    public int compare(Object p, Object q) {
			PropertyDescriptor a = (PropertyDescriptor) p;
			PropertyDescriptor b = (PropertyDescriptor) q;
			return a.getName().compareToIgnoreCase(b.getName());
		    }
		    public boolean equals(Object o) { return o == this; }
		});
	}

	// These are the names of the columns represented by this TableModel
	static final String[] columnNames = new String[] {
	    "Name", "Type", "Access", "Bound"
	};

	// These are the types of the columns represented by this TableModel
	static final Class[] columnTypes = new Class[] {
	    String.class, Class.class, String.class, Boolean.class
	};

	// These simple methods return basic information about the table
	public int getColumnCount() { return columnNames.length; }
	public int getRowCount() { return properties.length; }
	public String getColumnName(int column) { return columnNames[column]; }
	public Class getColumnClass(int column) { return columnTypes[column]; }

	/**
	 * This method returns the value that appears at the specified row and
	 * column of the table
	 **/
	public Object getValueAt(int row, int column) {
	    PropertyDescriptor prop = properties[row];
	    switch(column) {
	    case 0: return prop.getName();
	    case 1: return prop.getPropertyType();
	    case 2: return getAccessType(prop);
	    case 3: return new Boolean(prop.isBound());
	    default: return null;
	    }
	}

	// A helper method called from getValueAt() above
	String getAccessType(PropertyDescriptor prop) {
	    java.lang.reflect.Method reader = prop.getReadMethod();
	    java.lang.reflect.Method writer = prop.getWriteMethod();
	    if ((reader != null) && (writer != null)) return "Read/Write";
	    else if (reader != null) return "Read-Only";
	    else if (writer != null) return "Write-Only";
	    else return "No Access";  // should never happen
	}
    }
}