FileDocCategorySizeDatePackage
OpNode.javaAPI DocExample3888Mon Nov 09 12:45:50 GMT 1998None

OpNode.java

// OpNode.java
// A node structure containing an operator in our calculation tree. This node
// will hold two children.
// 
import javax.swing.tree.*;

public class OpNode {
  public static final String MULTIPLY = "*";
  public static final String DIVIDE   = "/";
  public static final String ADD      = "+";
  public static final String SUBTRACT = "-";

  String operator;
  Object[] children = new Object[2];
  boolean expanded = false;
  
  public OpNode() { this(ADD); }
  public OpNode(String op) { operator = op; }

  public void setExpanded(boolean b) { expanded = b; }
  
  // Add in a child (which can be either another OpNode or an Integer. If the
  // index isn't 0 or 1, throw an exception
  public void setChild(int index, Object child) {
    if (index == 0) { children[0] = buildChild(child); }
    else if (index == 1) { children[1] = buildChild(child); } 
    else {
      throw new IllegalArgumentException("child index " + index 
                                         + " must be 0 or 1");
    }
  }
  
  // return the child for the given index, may return null
  public Object getChild(int index) {
    if (index == 0) { return children[0]; }
    else if (index == 1) { return children[1]; }
    throw new IllegalArgumentException("child index must be 0 or 1");
  }
  
  // return the index of the given child
  public int getIndexOfChild(Object child) {
    if (child.equals(children[0])) { return 0;  }
    else if (child.equals(children[1])) { return 1; }
    return -1;
  }
  
  public int getChildCount() {
    int count = 0;
    if (children[0] != null) { count++; }
    if (children[1] != null) { count++; }
    return count;
  }
  
  // Get and set the current operator. We'll need to support the set method when
  // we start to make the tree editable
  public String getOperator() { return operator; }
  public void setOperator(Object op) {
    if (op instanceof String) { operator = (String)op; }
    else {
      throw new IllegalArgumentException("operators must be strings");
    }
  }

  // Here's the workhorse for OpNode. This method parses an Object and returns
  // either a valid OpNode or an Integer. If the object can't be parsed, an error
  // is printed and an Integer(0) is returned. (This keeps the tree from crashing
  // out . . . )
  protected Object buildChild(Object o) {
    if ((o instanceof Integer) || (o instanceof OpNode)) {
      return o;
    }
    String op = null;
    if (o instanceof String) {
      op = ((String)o).trim();
      if (op.equals(ADD)) { return new OpNode(ADD); }
      else if (op.equals(SUBTRACT)) { return new OpNode(SUBTRACT); }
      else if (op.equals(MULTIPLY)) { return new OpNode(MULTIPLY); }
      else if (op.equals(DIVIDE)) { return new OpNode(DIVIDE); }
      else {
        try { return Integer.valueOf(op); }
        catch (NumberFormatException nfe) { return new Integer(0); }
      }
    }
    System.err.println("Fell through new child: " + op);
    return new Integer(0);
  }

  // Return a string representing this node. If the tree is collapsed, build up
  // the expression below this node and return that as the string.
  public String toString() {
    if (expanded) { return operator; }
    else {
      StringBuffer buf = new StringBuffer(40);
      buildCollapsedString(buf, this);
      return buf.toString();
    }
  }

  // put together an expression of (leftside op rightside), but do it recursively
  // so we get the entire subtree
  protected void buildCollapsedString(StringBuffer buf, Object node) {
    if (node == null) { return; }
    if (node instanceof OpNode) {
      buf.append("(");
      buildCollapsedString(buf, ((OpNode)node).getChild(0));
      buf.append(" ");
      buf.append(((OpNode)node).getOperator());
      buf.append(" ");
      buildCollapsedString(buf, ((OpNode)node).getChild(1));
      buf.append(")");
    }
    else { buf.append(node); }
  }
}