Copyright (C) 1999, 2000, 2001, Geert Vernaeve. All Rights Reserved.
package gve.calc.formula; import java.awt.*; import java.io.*; import java.util.Vector;
@author Geert Vernaeve A formula encapsulates a Part tree. You could use a Part directly to manage such a tree. However, if the formula changes, the root part can become non-root. The Formula keeps track of this and always has a reference to the current root part.
public class Formula { private Part rootPart; public Formula(Part p) { rootPart = p; p.parent = null; }
Formula filled with a string
public Formula(String str) { rootPart = new Identifier(str); } public Formula() { rootPart = new Identifier(); rootPart.parent = null; } public Object clone() { Formula newformula = new Formula(); newformula.rootPart = (Part)rootPart.clone(); return newformula; } public Part evaluate(Evaluator ev) { return rootPart.evaluate(ev); }
Debug method.
private void recurseprint(Part p,int indent) { // if (Part.debuglevel < 20) return; for (int i = 0; i < indent; i++) System.out.print(' '); System.out.println(p); for (int ch = 0; ; ch++) { Part child = p.getChild(ch); if (child == null) break; recurseprint(child,indent+2); if (child.parent != p) { for (int i = 0; i < indent; i++) System.out.print(' '); System.out.println("Child #"+ch+" "+child+" has bad parent "+child.parent); } } } public void printdebug() { // if (Part.debuglevel < 10) return; recurseprint(rootPart,0); } public Part getRootPart() { return rootPart; } /* Unlinks a part in the formula tree and replaces it with another * (by adjusting byThat.parent; me.parent is not modified). * Special care is taken if the unlinked part is the root part * of the formula. * If the part to unlink has the cursor in it, the cursor moves along * to the new part. * It also works on non-root part (a handy utility function * for all kinds of parts). * Note that byThat should not already be a child of me.parent * or strange things will occur when the View tries to adjust * (i.e. don't replace a child of a part by another child of the * same part). */ public void replace(Part me,Part byThat) { if (me.parent == null) { // replacement of top Part rootPart = byThat; byThat.parent = null; } else { // replacement inside a Part me.parent.replaceChild(me,byThat); } me.parent = null; // unlink [6-Dec-2000] MVC.changed(this,new ReplacedMessage(me,byThat)); } public Part commonParent(Vector table) { // in result, we accumulate everyone whose parent is in table. while (true) { int tabsiz = table.size(); if (tabsiz == 0) return null; if (tabsiz == 1) { // table.elementAt(0) is the parent of all return (Part)table.elementAt(0); } Part p = (Part)table.elementAt(0); if (p.parent == null) return p; // everything // Walk upwards from p. If we meet someone, take action. Part walk; for (walk = p.parent; walk!=null; walk = walk.parent) { // Is walk in here? int idx = table.indexOf(walk); if (idx < 0) continue; // A parent of p is inside table. Prune. for (Part scan = p; scan!=walk; scan = scan.parent) { table.removeElement(scan); } break; // stop the search } if (walk == null) { // We didn't meet parents from here. // So *maybe* p is the top part. In any case, we can // add somebody else's parent safely. Part one = (Part)table.elementAt(1); if (one.parent == null) return one; // everything // Add one.parent to the table, except if we already have it int index = table.indexOf(one.parent); if (index < 0) table.setElementAt(one.parent,1); // was not in table else table.removeElementAt(1); } } }
A part has been modified. This method notifies the parent tree of the change by calling modified() for all the parents.
public void modified(Part p) { Part child = p; for (p = p.parent; p!=null; p = p.parent) { p.modified(child); } }
Return true if the formula contains this part We check this by checking the part's parent, the part's parent parent ... until we arrive at a part without parent, which should be the root part of the formula. Note that this method will not terminate if things are mixed up so badly that following the parents results in a endless loop ...
public boolean contains(Part p) { while (true) { Part par = p.getParent(); if (par == null) return (p == rootPart); if (par == p) return false; /* protect against strange cases (theoretical, not observed yet ...) */ /* Is p a child of par? */ int count = 0; while (true) { Part child = par.getChild(count++); if (child == p) break; /* p is indeed a child of par */ if (child == null) return false; /* p is not a child of par so not in the formula */ } p = par; } } }