/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.das2.qds.util; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import org.das2.datum.Units; import org.das2.datum.UnitsUtil; import org.das2.util.DasMath; import org.das2.qds.DataSetUtil; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; /** * provides a TreeModel representation of the dataset's properties. * @author jbf */ public class PropertiesTreeModel extends DefaultTreeModel { QDataSet ds; String dsLabel; MutableTreeNode mroot= (MutableTreeNode)root; public PropertiesTreeModel( QDataSet ds ,int valuesSizeLimit) { this( null, ds ,valuesSizeLimit); } /** * TreeModel representing the dataset. This is really for human consumption and may change. * @param prefix String to prefix the root label. * @param ds the dataset source of the metadata. * @param valuesSizeLimit the number of values in a dataset to represent, e.g. 20, and ellipses (...) will represent the values not shown. */ public PropertiesTreeModel( String prefix, QDataSet ds ,int valuesSizeLimit) { super( new DefaultMutableTreeNode( ( prefix==null ? "" : prefix ) + DataSetUtil.toString(ds) ) ); this.ds = ds; Map<String,Object> properties= DataSetUtil.getProperties(ds); for ( Entry<String,Object> e: properties.entrySet() ) { String key= e.getKey(); Object value= e.getValue(); if ( key.equals(QDataSet.QUBE) && ( ds.rank()<2 || ds.property(QDataSet.BUNDLE_1)!=null ) ) { continue; } MutableTreeNode nextChild; if ( key.startsWith("BUNDLE_") && ( value instanceof QDataSet ) ) { QDataSet bdsd= (QDataSet)value; StringBuilder svalue= new StringBuilder(); svalue.append(key).append("="); if ( bdsd.length()>0 ) svalue.append( bdsd.property( QDataSet.NAME, 0 ) ); for ( int i=1; i<bdsd.length(); i++ ) { svalue.append( "," ).append( bdsd.property( QDataSet.NAME, i ) ); } BundleDescriptorTreeModel rm= new BundleDescriptorTreeModel(svalue.toString(),(QDataSet)value); nextChild= (MutableTreeNode) rm.getRoot(); } else if ( value instanceof QDataSet ) { PropertiesTreeModel model= new PropertiesTreeModel( key + "=", (QDataSet)value,valuesSizeLimit); nextChild= (MutableTreeNode) model.getRoot(); } else if ( value.getClass().isArray() ) { value.getClass().getComponentType(); List<Object> list= new ArrayList(); int nn= Math.min( Array.getLength(value), 5 ); for ( int i=0; i<nn; i++ ){ list.add( Array.get( value, i) ); } if ( Array.getLength(value)>5 ) { list.add("..."); } nextChild= new DefaultMutableTreeNode(""+key+"="+list); } else if ( Map.class.isAssignableFrom( value.getClass() ) ) { nextChild= (MutableTreeNode) new MapTreeModel( key + " (map)", (Map)value ).getRoot(); } else { String svalue= String.valueOf(value); if ( value instanceof Number && ( key.equals(QDataSet.VALID_MIN) || key.equals(QDataSet.VALID_MAX) || key.equals(QDataSet.TYPICAL_MIN ) || key.equals(QDataSet.TYPICAL_MAX ) ) ) { Units u= (Units) properties.get(QDataSet.UNITS); if ( u!=null && UnitsUtil.isTimeLocation(u) ) { if ( u.isValid( ((Number)value).doubleValue() ) ) { svalue= u.createDatum((Number)value).toString() + " (" + svalue + ")"; } else { svalue= "fill" + " (" + svalue + ")"; } } nextChild= new DefaultMutableTreeNode(""+key+"="+svalue); } else if ( key.equals(QDataSet.FILL_VALUE ) && value instanceof Number ) { // round N digits. if ( value instanceof Long ||value instanceof Integer || value instanceof Short ) { svalue= String.valueOf( value ); } else { svalue= String.valueOf( DasMath.roundNSignificantDigits( ((Number)value).doubleValue(), 6 ) ); } nextChild= new DefaultMutableTreeNode(""+key+"="+svalue); } else if ( key.equals(QDataSet.DESCRIPTION) ) { String rootNode= key + "=" + ( svalue.length()>60 ? svalue.substring(0,60)+"..." : svalue ); nextChild= (MutableTreeNode) new LongStringTreeModel( rootNode, svalue ).getRoot(); } else { nextChild= new DefaultMutableTreeNode(""+key+"="+svalue); } } mroot.insert( nextChild, mroot.getChildCount() ); } if ( ds.rank()>0 ) { if ( SemanticOps.isJoin(ds) ) { int lin=19; for ( int i=0; i<ds.length(); i++ ) { if ( i<lin || i>=ds.length()-3 ) { QDataSet ds1= ds.slice(i); MutableTreeNode values= (MutableTreeNode) new PropertiesTreeModel(String.format("slice(%d)= ",i), ds1,valuesSizeLimit).getRoot(); mroot.insert( values, mroot.getChildCount() ); } else if ( i==lin ) { mroot.insert( new DefaultMutableTreeNode("..."), mroot.getChildCount() ); } } } else { MutableTreeNode values= new DefaultMutableTreeNode("values"); ValuesTreeModel.valuesTreeNode( "value(", values, ds ,valuesSizeLimit); mroot.insert( values, mroot.getChildCount() ); } } } private static class BundleDescriptorTreeModel extends DefaultTreeModel { public BundleDescriptorTreeModel( String label, QDataSet root ) { super(new DefaultMutableTreeNode(root)); MutableTreeNode mrt= ((MutableTreeNode)getRoot()); ((DefaultMutableTreeNode)mrt).setUserObject(label); for ( int i=0; i<root.length(); i++ ) { PropertiesTreeModel m= new PropertiesTreeModel(root.slice(i),20); mrt.insert( (MutableTreeNode)m.getRoot(), mrt.getChildCount() ); } } } private static class ArrayTreeModel extends DefaultTreeModel { ArrayTreeModel( Object root, Object values ) { super( new DefaultMutableTreeNode(root) ); MutableTreeNode mrt= ((MutableTreeNode)getRoot()); for ( int i=0; i<Array.getLength(values); i++ ){ MutableTreeNode nextChild= (MutableTreeNode) new DefaultMutableTreeNode( "["+i + "]=" + Array.get( values, i ) ).getRoot(); mrt.insert( nextChild, mrt.getChildCount() ); } } } private static class MapTreeModel extends DefaultTreeModel { MapTreeModel( Object root, Map values ) { super( new DefaultMutableTreeNode(root) ); MutableTreeNode mrt= ((MutableTreeNode)getRoot()); for ( Object o : values.entrySet() ) { Entry val= (Entry)o; Object value= val.getValue(); if ( value!=null && value.getClass().isArray() ) { DefaultTreeModel nextChild= new ArrayTreeModel( val.getKey() + "["+ Array.getLength(value)+"]", value ); mrt.insert( (MutableTreeNode) nextChild.getRoot(), mrt.getChildCount() ); } else if ( value!=null && Map.class.isAssignableFrom( value.getClass() ) ) { MutableTreeNode nextChild= (MutableTreeNode) new MapTreeModel( val.getKey(), (Map)value ).getRoot(); mrt.insert( nextChild, mrt.getChildCount() ); } else if ( value instanceof String && ((String)value).length()>80 ) { String svalue= (String)value; String rootString= val.getKey() + "=" + ( svalue.length()>60 ? svalue.substring(0,60)+"..." : svalue ); MutableTreeNode nextChild= (MutableTreeNode) new LongStringTreeModel( rootString, (String)value ).getRoot(); mrt.insert( nextChild, mrt.getChildCount() ); } else { mrt.insert( new DefaultMutableTreeNode(""+val.getKey()+"="+val.getValue() ),mrt.getChildCount() ); } } } } /** * copied from Autoplot's DataSource package. */ private static class LongStringTreeModel extends DefaultTreeModel { private static final int LINE_LEN = 133; String name; String value; List<Integer> splits; boolean hasKids; LongStringTreeModel( Object root, String value) { super( new DefaultMutableTreeNode(root) ); MutableTreeNode mrt= ((MutableTreeNode)getRoot()); value= value.trim(); this.value = value; int lastBreak= -1; if ( value.length()>LINE_LEN || value.contains("\n") ) { 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() ) { String schild= lastBreak==-1 ? value.substring(0,ii) : value.substring( lastBreak, ii ); mrt.insert( new DefaultMutableTreeNode( schild ),mrt.getChildCount() ); lastBreak= ii; } } } else { mrt.insert( new DefaultMutableTreeNode( value ),mrt.getChildCount() ); } } } }