/* * $Id: PropertyNode.java,v 1.2 2006/09/25 08:52:36 acaproni Exp $ * * $Date: 2006/09/25 08:52:36 $ * $Revision: 1.2 $ * $Author: acaproni $ * * Copyright CERN, All Rights Reserved. */ package cern.gp.nodes.impl; import java.awt.Component; import java.awt.Image; import java.awt.Toolkit; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyEditor; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ArrayList; import org.openide.nodes.AbstractNode; import org.openide.nodes.BeanNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.BeanNode.Descriptor; import org.openide.util.actions.SystemAction; import cern.gp.beans.BeanTagger; /** * <i><font size="-1" color="#FF0000">**For internal use only** </font></i> * A node that represents a property of a node. This node can be used to * expand a node that represent a bean with some properties to show those * properties. Each child represent one single property and has one * property called "value" that represent the value of the property itself. * * @version $Revision: 1.2 $ $Date: 2006/09/25 08:52:36 $ * @author Lionel Mestre */ public class PropertyNode extends AbstractNode { private static final String ICON_NAME = "cern/gp/nodes/resources/properties.gif"; private static final Image ICON_IMAGE = loadImage(ICON_NAME); public static final String VALUE = "value"; private Property property; private PropertySet[] propertySets; // // -- CONSTRUCTORS ----------------------------------------------- // public PropertyNode(Property property) { super(computeChildren(property)); this.property = property; this.propertySets = new PropertySet[] { new ValuePropertySet(property) }; setIconBase(ICON_NAME); } // // -- PUBLIC METHODS ----------------------------------------------- // public boolean canCopy() { return false; } public boolean canCut() { return false; } public boolean canRename() { return false; } public boolean canDestroy() { return false; } public String getDisplayName() { return property.getDisplayName(); } public String getName() { return property.getName(); } public String getShortDescription() { return property.getShortDescription(); } public Image getIcon(int type) { if (ICON_IMAGE == null) return super.getIcon(type); return ICON_IMAGE; } public Image getOpenedIcon(int type) { if (ICON_IMAGE == null) return super.getOpenedIcon(type); return ICON_IMAGE; } public Component getCustomizer() { PropertyEditor propertyEditor = property.getPropertyEditor(); if (propertyEditor == null) return null; return propertyEditor.getCustomEditor(); } public boolean hasCustomizer() { PropertyEditor propertyEditor = property.getPropertyEditor(); if (propertyEditor == null) return false; return propertyEditor.supportsCustomEditor(); } public PropertySet[] getPropertySets() { return propertySets; } public Object getValue(String attributeName) { if (VALUE.equals(attributeName)) { return property; } else { return super.getValue(attributeName); } } // // -- PROTECTED METHODS ----------------------------------------------- // /** * Returns the actions that shall be displayed in the pop-up menu for this node. * This method is called by Netbeans Explorer to build the pop-up menu for this node. */ protected SystemAction[] createActions() { return new SystemAction[] {}; } // // -- PRIVATE METHODS ----------------------------------------------- // private static Children computeChildren(Property property) { try { Object value = property.getValue(); if (value == null) return Children.LEAF; Class clazz = value.getClass(); Class arrayClass = clazz.getComponentType(); if (arrayClass != null) { // it is an array return new PropertyArrayChildren(property); } // not an array // test if the property declares itself as expandable if (BeanTagger.isExpandable(property)) { return new PropertyChildren(property); } // the property is not marked as hierarchical => look for editor if (property.getPropertyEditor() != null) { return Children.LEAF; } // here depending what we want we can decide that property without a PropertyEditor // are expandable or not return Children.LEAF; //return new PropertyChildren(property); } catch (Exception e) { return Children.LEAF; } } private static Image loadImage(String pathname) { URL url = PropertyNode.class.getClassLoader().getResource(pathname); if (url != null) return Toolkit.getDefaultToolkit().createImage(url); return null; } // // -- INNER CLASSES ----------------------------------------------- // /** * Children for a PropertyNode that represents a value that is * a bean with properties. The children are the nodes representing * those properties. */ private static class PropertyChildren extends Children.Array { private Property property; public PropertyChildren(Property property) { super(new ArrayList()); this.property = property; } protected void addNotify() { super.addNotify(); try { BeanInfo beanInfo = Introspector.getBeanInfo(property.getValueType()); Descriptor descriptor = BeanNode.computeProperties(property.getValue(), beanInfo); addPropertyNodes(descriptor.property); addPropertyNodes(descriptor.expert); } catch (Exception e) { e.printStackTrace(); } } protected void removeNotify() { nodes.clear(); super.removeNotify(); } private void addPropertyNodes(Property[] properties) { if (properties == null || properties.length == 0) return; Node[] nodesToAdd = new Node[properties.length]; for (int i=0; i<properties.length; i++) { nodesToAdd[i] = new PropertyNode(properties[i]); } add(nodesToAdd); } } // end inner class PropertyChildren /** * Children for a PropertyNode that represents an array of values */ private static class PropertyArrayChildren extends Children.Array { private Property property; private Object[] values; public PropertyArrayChildren(Property property) throws java.lang.IllegalAccessException, InvocationTargetException { super(new ArrayList(((Object[]) property.getValue()).length)); this.property = property; this.values = (Object[]) property.getValue(); } protected void addNotify() { super.addNotify(); Node[] nodesToAdd = new Node[values.length]; for (int i=0; i<values.length; i++) { nodesToAdd[i] = new PropertyNode(new ValuePropertyProxy(property, values[i], i)); } add(nodesToAdd); } protected void removeNotify() { nodes.clear(); super.removeNotify(); } } // end inner class PropertyArrayChildren /** * A simple PropertySet that contains only a single property * called value and whose value is the property represented * by the node. */ private static class ValuePropertySet extends PropertySet { private Property[] properties; public ValuePropertySet(Property property) { super("ValueSet", "ValueSet", "ValueSet"); properties = new Property[] { property }; } public Property[] getProperties() { return properties; } } /** * Proxy on a Node.Property that represents an array. The proxy acts as * if it was a property and represents one value of the array of values * the proxied property is equal to. */ private static class ValuePropertyProxy extends Property { private Property proxiedProperty; private Object value; private String indexString; public ValuePropertyProxy(Property proxiedProperty, Object value, int index) { super(proxiedProperty.getValueType()); this.proxiedProperty = proxiedProperty; this.value = value; this.indexString = "["+index+"]"; } public Object getValue() throws IllegalAccessException, InvocationTargetException { return value; } public void setValue(Object value) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { throw new IllegalAccessException(); } public boolean supportsDefaultValue() { return proxiedProperty.supportsDefaultValue(); } public void restoreDefaultValue() throws IllegalAccessException, InvocationTargetException { proxiedProperty.restoreDefaultValue(); } public PropertyEditor getPropertyEditor() { PropertyEditor editor = proxiedProperty.getPropertyEditor(); return editor; } public boolean canRead() { return true; } public boolean canWrite() { return false; } public String getDisplayName() { String s = proxiedProperty.getDisplayName(); if (s == null) return "null "+indexString; else return s+indexString; } public String getName() { String s = proxiedProperty.getName(); if (s == null) return "null "+indexString; else return s+indexString; } public String getShortDescription() { return proxiedProperty.getShortDescription(); } } }