/* * NameValueTreeModel.java * * Created on July 31, 2007, 11:45 AM * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package org.autoplot.metatree; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import org.das2.qds.QDataSet; import org.das2.qds.util.PropertiesTreeModel; /** * * @author jbf */ public class NameValueTreeModel implements TreeModel { final Object root; List nodes; public interface TreeNode { int childCount(); Object getChild(int i); boolean isLeaf(); String toString(); } static class StringPropertyNode implements TreeNode { private static final int LINE_LEN = 133; String name; String value; List<Integer> splits; boolean hasKids; StringPropertyNode(String name, String value) { this.name = name; value= value.trim(); this.value = value; if ( value.length()>LINE_LEN || value.contains("\n") ) { splits= new ArrayList<>(); int ii=0; while ( ii<value.length() ) { int i= value.indexOf('\n',ii); if ( (i-ii)>LINE_LEN || i==-1 ) { if ( value.length()-ii < LINE_LEN ) { ii= value.length(); } else { i= value.lastIndexOf(' ',ii+LINE_LEN); if ( i==-1 ) { ii= ii+LINE_LEN; } else if ( i>ii ) { ii= i+1; } else { ii= value.length(); // couldn't find a break } } } else { ii= i+1; } if ( ii<value.length() ) splits.add(ii); } } this.hasKids = splits != null; } @Override public String toString() { if (!hasKids) { return "" + name + "=" + value; } else { return "" + name + "=" + value.substring(0, splits.get(0) ) + " ..."; } } public int childCount() { return hasKids ? splits.size() + 1 : 0; } public Object getChild(int i) { if ( i==0 ) { return value.substring( 0,splits.get(i) ); } else if ( i==splits.size() ) { return value.substring(splits.get(i-1)); } else { return value.substring( splits.get(i-1), splits.get(i) ); } } public boolean isLeaf() { return !hasKids; } } static class ArrayPropertyNode implements TreeNode { String name; Object value; boolean hasKids; ArrayPropertyNode(String name, Object value) { this.name = name; this.value = value; this.hasKids = true; } public String toString() { return "" + name + "=[" + Array.getLength(value) + "]"; } public int childCount() { return Array.getLength(value); } public Object getChild(int i) { return createNode("[" + i + "]", Array.get(value, i)); } public boolean isLeaf() { return !hasKids; } } static class MapPropertyNode implements TreeNode { String name; Map value; boolean hasKids; String[] keys; MapPropertyNode(String name, Map<String,Object> value) { this.name = name; this.value = value; this.keys= (String[]) this.value.keySet().toArray( new String[ value.size() ] ); this.hasKids = this.keys.length>0; } public String toString() { return "" + name ; } public int childCount() { return value.size(); } public Object getChild(int i) { String key= keys[i]; return createNode( key, value.get(key) ); } public boolean isLeaf() { return !hasKids; } } static class TreeNodeAdapter implements TreeNode { javax.swing.tree.TreeNode node; String name; TreeNodeAdapter( String name, javax.swing.tree.TreeNode node ) { this.node= node; this.name= name; } public int childCount() { return node.getChildCount(); } public Object getChild(int i) { return new TreeNodeAdapter( null, node.getChildAt(i) ); } public boolean isLeaf() { return node.isLeaf(); } public String toString() { if ( name!=null ) { return name + "=" + node.toString(); } else { return node.toString(); } } } static Object createNode(String name, Object value) { if ( value==null ) { return new StringPropertyNode(name, "null" ); } else if (value.getClass().isArray()) { return new ArrayPropertyNode(name, value); } else if (value instanceof String) { String svalue= (String) value; if ( svalue.length()>800 ) { svalue= svalue.substring(0,797) + "..."; } return new StringPropertyNode(name, svalue); } else if (value instanceof Map) { return new MapPropertyNode(name, (Map) value); } else if (value instanceof QDataSet ) { PropertiesTreeModel model= new PropertiesTreeModel((QDataSet)value,100); return new TreeNodeAdapter( name, (javax.swing.tree.TreeNode)model.getRoot() ); } else { return new StringPropertyNode(name, String.valueOf(value)); } } public Object getRoot() { return root; } public Object getChild(Object parent, int index) { if (parent == root) { return nodes.get(index); } else { TreeNode p = (TreeNode) parent; return p.getChild(index); } } public int getChildCount(Object parent) { if (parent == root) { return nodes.size(); } else { TreeNode p = (TreeNode) parent; return p.childCount(); } } public boolean isLeaf(Object parent) { if (parent == root) { return false; } else if (parent instanceof TreeNode) { TreeNode p = (TreeNode) parent; return p.isLeaf(); } else { return true; } } public void valueForPathChanged(TreePath path, Object newValue) { } public int getIndexOfChild(Object parent, Object child) { return 0; } public void addTreeModelListener(TreeModelListener l) { } public void removeTreeModelListener(TreeModelListener l) { } /** Creates a new instance of NameValueTreeModel */ private NameValueTreeModel(Object root, List nodes) { this.nodes = nodes; this.root = root; } public static NameValueTreeModel create(Object root, List names, List values) { ArrayList nodes = new ArrayList(names.size()); for (int i = 0; i < names.size(); i++) { nodes.add(createNode((String) names.get(i), values.get(i))); } return new NameValueTreeModel(root, nodes); } /** * creates a new tree from a hash map. * @param root a node to use as the root. Often this will just be a string identifying the properties set like "metadata(cdf)" * @param map Map that are translated to nodes. Most value types result in <name>=<value>, while values that are * Maps may be handled recursively. * @return */ public static NameValueTreeModel create(Object root, Map map) { List nodes; if ( map!=null ) { nodes = new ArrayList(map.size()); for ( Iterator i = map.entrySet().iterator(); i.hasNext();) { Entry e= (Entry)i.next(); nodes.add( createNode( String.valueOf(e.getKey()), e.getValue() ) ); } } else { nodes= Collections.EMPTY_LIST; } return new NameValueTreeModel( root, nodes ); } public String toString() { return String.valueOf(this.root) + "(" + nodes.size() + "key/value pairs)"; } }