package DisplayProject.swingdisplayer;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractCellEditor;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
@SuppressWarnings("serial")
public class TestWin extends JFrame {
private static class ArrayDisplayer implements TableCellRenderer {
private boolean isExpanded = true;
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (value == null) {
return null;
}
else if (value.getClass().isArray()) {
Class<?> type = value.getClass().getComponentType();
int length = Array.getLength(value);
String rootNodeText = type.getSimpleName() + "[" + length + "]";
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(rootNodeText);
for (int i = 0; i < length; i++) {
DefaultMutableTreeNode aNode = new DefaultMutableTreeNode("[" + i + "] " + Array.get(value, i));
rootNode.add(aNode);
}
JTree tree = new JTree(rootNode);
tree.setShowsRootHandles(false);
tree.setEditable(false);
tree.setRootVisible(true);
if (isExpanded) {
tree.expandRow(0);
}
else {
tree.collapseRow(0);
}
tree.setOpaque(false);
tree.setRowHeight(table.getRowHeight());
tree.setCellRenderer(new DefaultTreeCellRenderer() {
@Override
public Color getBackground() {
return null;
}
@Override
public Color getBackgroundNonSelectionColor() {
return null;
}
@Override
public Icon getOpenIcon() {
return null;
}
@Override
public Icon getLeafIcon() {
return null;
}
});
int minHeight = (1 + (isExpanded ? Math.min(length, 5): 0)) * tree.getRowHeight();
if (minHeight != table.getRowHeight(row)) {
table.setRowHeight(row, minHeight);
}
if (minHeight == table.getRowHeight()) {
return tree;
}
JScrollPane sp = new JScrollPane(tree);
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp.setOpaque(true);
sp.setBorder(null);
return sp;
}
// if (value instanceof Array) {}
// TODO Auto-generated method stub
return new JLabel(value.toString());
}
}
private static class NullableProperty {
private PropertyDescriptor property;
private PropertyDescriptor isSet;
public NullableProperty(PropertyDescriptor property) {
this.property = property;
this.isSet = null;
}
public void setIsSetProperty(PropertyDescriptor property) {
this.isSet = property;
}
public PropertyDescriptor getProperty() {
return this.property;
}
public boolean isNull(Component comp) {
if (isSet != null) {
try {
Boolean result = (Boolean)isSet.getReadMethod().invoke(comp);
return result.booleanValue() == false;
}
catch (Exception e) {}
}
return false;
}
/**
* This method sees if the passed property descriptor is in the correct format to be an isXXXSet()
* method (eg isForegroundSet(), isFontSet(), etc). To be in this format, it must be boolean, be
* readonly and have a name matching is<XXX>Set(). In this case, XXX, corrected to match the bean
* spec, will be returned. Otherwise, null will be returned.
* @param pd
* @return
*/
public static String getIsSetPropertyName(PropertyDescriptor pd) {
if (pd != null && pd.getWriteMethod() == null && pd.getPropertyType() != null && pd.getPropertyType().equals(Boolean.class)) {
Method m = pd.getReadMethod();
if (m != null && m.getName().startsWith("is") && m.getName().endsWith("Set") && m.getName().length() >= 6) {
String result = m.getName().substring(2, m.getName().length() - 3);
StringBuilder res = new StringBuilder(result);
if (result.length() == 1) {
res.setCharAt(0, Character.toLowerCase(res.charAt(0)));
}
else if (Character.isUpperCase(result.charAt(1))) {
res.setCharAt(0, Character.toUpperCase(res.charAt(0)));
}
else {
res.setCharAt(0, Character.toLowerCase(res.charAt(0)));
}
return res.toString();
}
}
return null;
}
}
private class PropertyModel extends AbstractTableModel {
@SuppressWarnings("unused")
private Component component;
private List<NullableProperty> properties = null;
public PropertyModel(Component component, PropertyDescriptor[] properties) {
super();
this.setProperties(properties);
this.component = component;
}
public PropertyModel() {
super();
}
public void setProperties(PropertyDescriptor[] properties) {
// Sort these properties, strip out any invalid ones, and merge in the setters.
this.properties = new ArrayList<NullableProperty>();
Map<String, NullableProperty> map = new HashMap<String, NullableProperty>(properties.length);
List<PropertyDescriptor> nulls = new ArrayList<PropertyDescriptor>();
for (PropertyDescriptor pd : properties) {
if (pd.getReadMethod() != null && pd.getPropertyType() != null) {
// Ok, it seems valid at this point, see if it's a null property
String propertyName = NullableProperty.getIsSetPropertyName(pd);
if (propertyName != null) {
// Yes, don't list it as a property in it's own right.
nulls.add(pd);
}
else {
// It's a property in it's own right.
NullableProperty np = new NullableProperty(pd);
this.properties.add(np);
map.put(pd.getName(), np);
}
}
}
// Iterate through the nulls and mark their properties as being nullable
for (PropertyDescriptor pd : nulls) {
String propertyName = NullableProperty.getIsSetPropertyName(pd);
NullableProperty np = map.get(propertyName);
if (np != null) {
np.setIsSetProperty(pd);
}
}
}
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Object.class;
case 1: return String.class;
case 2: return Object.class;
default: return null;
}
}
public int getColumnCount() {
return 3;
}
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0: return "";
case 1: return "Name";
case 2: return "Value";
default: return null;
}
}
public int getRowCount() {
return properties == null ? 0 : properties.size();
}
public Object getValueAt(int rowIndex, int columnIndex) {
if (rowIndex >= 0 && rowIndex < getRowCount()) {
switch (columnIndex) {
case 0: return null;
case 1: return properties.get(rowIndex).getProperty().getName();
case 2: return properties.get(rowIndex).getProperty();
default:
break;
}
}
return null;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (rowIndex >= 0 && rowIndex < properties.size() && columnIndex == 2) {
Method readMethod = properties.get(rowIndex).getProperty().getReadMethod();
if (readMethod != null) {
if (displayerMap.get(readMethod.getReturnType()) != null) {
return properties.get(rowIndex).getProperty().getWriteMethod() != null;
}
}
}
return false;
}
public void setValueAt(Object value, int rowIndex, int columnIndex) {
// TODO Auto-generated method stub
}
}
private Color alternatingRowColor = new Color(255, 255, 210);
private final Map<Class<?>, PropertyDisplayer> displayerMap = new HashMap<Class<?>, PropertyDisplayer>();
private void setup() {
this.displayerMap.put(Boolean.TYPE, new BooleanDisplayer());
this.displayerMap.put(Color.class, new ColorDisplayer());
this.displayerMap.put(Dimension.class, new DimensionDisplayer());
this.displayerMap.put(Integer.TYPE, new NumberDisplayer());
this.displayerMap.put(Short.TYPE, new NumberDisplayer());
this.displayerMap.put(Long.TYPE, new NumberDisplayer());
this.displayerMap.put(Byte.TYPE, new NumberDisplayer());
this.displayerMap.put(Float.TYPE, new NumberDisplayer());
this.displayerMap.put(Double.TYPE, new NumberDisplayer());
this.displayerMap.put(Font.class, new FontDisplayer());
}
private class PropertyCellRenderer implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component result;
if (value instanceof PropertyDescriptor) {
PropertyDescriptor pd = (PropertyDescriptor)value;
Method reader = pd.getReadMethod();
if (reader != null) {
try {
Class<?> returnType = reader.getReturnType();
if (returnType != null) {
Object val = reader.invoke(component);
PropertyDisplayer displayer = displayerMap.get(returnType);
if (displayer != null) {
displayer.preSelect(pd, component, table);
result = displayer.getTableCellRendererComponent(table, val, isSelected, hasFocus, pd.getWriteMethod() == null, component, row, column);
result.setForeground(displayer.getForegroundColor(table, isSelected, hasFocus, hasFocus));
}
else if (val != null && val.getClass().isArray()) {
result = new ArrayDisplayer().getTableCellRendererComponent(table, val, isSelected, hasFocus, row, column);
}
else {
result = new JLabel(val == null ? "" : val.toString());
((JLabel)result).setOpaque(true);
}
}
else {
result = new JLabel("<html><i>Null getter</i></html>");
}
}
catch (Exception e) {
result = new JLabel("<html><i>Not readable</i></html>");
}
}
else {
result = new JLabel("<html><i>Not readable</i></html>");
}
}
else {
result = new JLabel(value == null ? "" : value.toString());
((JLabel)result).setOpaque(true);
}
if (isSelected) {
result.setBackground(table.getSelectionBackground());
result.setForeground(table.getSelectionForeground());
}
else if (row % 2 == 1) {
result.setBackground(alternatingRowColor);
result.setForeground(Color.black);
}
else {
result.setBackground(Color.white);
result.setForeground(Color.black);
}
return result;
}
}
private class PropertyCellEditor extends AbstractCellEditor implements TableCellEditor {
private TableCellEditor editor = null;
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
editor = null;
Component result = null;
if (value instanceof PropertyDescriptor) {
PropertyDescriptor pd = (PropertyDescriptor)value;
Method reader = pd.getReadMethod();
if (reader != null) {
try {
Object val = reader.invoke(component);
PropertyDisplayer displayer = displayerMap.get(reader.getReturnType());
if (displayer != null) {
editor = displayer;
displayer.setEditingInformation(component, pd);
result = editor.getTableCellEditorComponent(table, val, isSelected, row, column);
}
}
catch (Exception e) {
System.out.println(e);
}
}
}
return result;
}
public void cancelCellEditing() {
if (editor != null) {
editor.cancelCellEditing();
editor = null;
super.cancelCellEditing();
}
}
public Object getCellEditorValue() {
if (editor != null) {
return editor.getCellEditorValue();
}
return null;
}
public boolean isCellEditable(EventObject anEvent) {
if (editor != null) {
return editor.isCellEditable(anEvent);
}
return true;
}
public boolean shouldSelectCell(EventObject anEvent) {
if (editor != null) {
return editor.shouldSelectCell(anEvent);
}
return true;
}
public boolean stopCellEditing() {
if (editor != null) {
boolean result = editor.stopCellEditing();
if (result) {
super.stopCellEditing();
editor = null;
}
return result;
}
return true;
}
}
private class PropertyColumnModel extends DefaultTableColumnModel {
public PropertyColumnModel() {
TableColumn col = new TableColumn();
col.setResizable(false);
col.setPreferredWidth(32);
col.setMinWidth(col.getPreferredWidth());
col.setMaxWidth(col.getPreferredWidth());
col.setModelIndex(0);
col.setHeaderValue(" ");
this.addColumn(col);
col = new TableColumn();
col.setResizable(true);
col.setPreferredWidth(100);
col.setModelIndex(1);
col.setHeaderValue("Name");
this.addColumn(col);
col = new TableColumn();
col.setResizable(true);
col.setPreferredWidth(100);
col.setModelIndex(2);
col.setHeaderValue("Value");
col.setCellRenderer(new PropertyCellRenderer());
col.setCellEditor(new PropertyCellEditor());
this.addColumn(col);
}
}
private JTable table;
private PropertyModel model;
private Component component;
public TestWin() {
this.setup();
table = new JTable() {
@Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int column) {
Component result = super.prepareRenderer(renderer, row, column);
// if (result instanceof JComponent) {
// ((JComponent)result).setOpaque(true);
// if (row % 2 == 1) {
// result.setBackground(alternatingRowColor);
// }
// else {
// result.setBackground(Color.white);
// }
// }
return result;
}
@Override
public void changeSelection(int rowIndex, int columnIndex,
boolean toggle, boolean extend) {
// TODO Auto-generated method stub
super.changeSelection(rowIndex, columnIndex, toggle, extend);
}
};
this.model = new PropertyModel();
table.setModel(model);
table.setColumnModel(new PropertyColumnModel());
this.getContentPane().add(new JScrollPane(table));
this.setSize(400, 400);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
public void display(Component component, PropertyDescriptor[] properties) {
this.component = component;
this.model.setProperties(properties);
this.setVisible(true);
}
}