package gve.calc.formula;

import awt.*;
import java.awt.*;
import awt.Button;
import java.awt.event.*;
import java.util.Hashtable;

@author Geert Vernaeve
public abstract class InfixBinaryOp extends BinaryOp { //----------static stuff---------- private static Hashtable repository = new Hashtable(); public static void registerFactory(String name,InfixBinaryOpFactory factory) { repository.put(name,factory); } public static InfixBinaryOp getInstance(String name,Part l,Part r) { InfixBinaryOpFactory fact = (InfixBinaryOpFactory)repository.get(name); if (fact == null) throw new Error("No factory for "+name); return fact.createInfixBinaryOp(name,l,r); } public static boolean isOperatorName(String name) { return repository.containsKey(name); } static String operatorPrefix(String name,Hashtable tab) { String result = null; for (java.util.Enumeration keys = tab.keys(); keys.hasMoreElements(); ) { String opName = (String)keys.nextElement(); if (name.startsWith(opName)) { if (result == null) result = opName; else if (opName.length() > result.length()) result = opName; } } return result; }
Returns an operator whose name is a prefix of the given string. Basically, this function answers the question "does this string begins with an operator name?". If multiple operators match, return the operator with the longest name. E.g. if name is "->" then we don't return "-" but "->" (supposed those two are operator names)
public static String operatorPrefix(String name) { return operatorPrefix(name,repository); }
Given a prefix of an operator (e.g. ":") try to complete this prefix to find an operator with a name as long as possible (eg ":=")
public static String completePrefix(String name) { String result = null; for (java.util.Enumeration keys = repository.keys(); keys.hasMoreElements(); ) { String opName = (String)keys.nextElement(); if (opName.startsWith(name)) { if (result == null) result = opName; else if (opName.length() > result.length()) result = opName; } } return result; } //----------instance stuff---------- public InfixBinaryOp() {} public InfixBinaryOp(Part l,Part r) { left = l; right = r; l.parent = r.parent = this; } public InfixBinaryOp getInstance(Part l,Part r) { return getInstance(getName(),l,r); } public Object clone() { return getInstance((Part)left.clone(),(Part)right.clone()); } public boolean simpleRotate(Formula f) { return simpleRotate(f,null); } public boolean simpleRotate(Formula f,FormulaView view) { if (parent instanceof InfixBinaryOp) { InfixBinaryOp par = (InfixBinaryOp)parent; // Rotate myself upwards if (this==par.right && getPri()<par.getRightPri()) { Part cursorpart = null; if (view != null) cursorpart = view.getCursorPart(); Identifier dummy = new Identifier(); f.replace(par.right,dummy); f.replace(par,this); Part oldleft = left; int cpos = 0; HasCursorPos restoreCursorComp = null; if (cursorpart == oldleft) { Component ccomp = view.getCursorComp(); if (ccomp instanceof HasCursorPos) { restoreCursorComp = (HasCursorPos)ccomp; cpos = restoreCursorComp.getCursorPos(); } } f.replace(left,par); f.replace(dummy,oldleft); if (restoreCursorComp != null) { view.setCursorComp((Component)restoreCursorComp,cpos); } return true; } else if (this==par.left && getPri()<par.getLeftPri()) { Part cursorpart = null; if (view != null) cursorpart = view.getCursorPart(); // System.out.println(cursorpart); Identifier dummy = new Identifier(); f.replace(par.left,dummy); f.replace(par,this); Part oldright = right; int cpos = 0; HasCursorPos restoreCursorComp = null; if (cursorpart == oldright) { // replace() will tinker with the cursor // position (see FormulaView.replace()) // so we record the cursor position and restore it later // PENDING: Maybe a more elegant solution would be // that FormulaViews are able to pop and push their cursor position // to an internal stack, so we could ask the formula to let all its // views record and restore their cursor position ... Component ccomp = view.getCursorComp(); if (ccomp instanceof HasCursorPos) { restoreCursorComp = (HasCursorPos)ccomp; cpos = restoreCursorComp.getCursorPos(); } } f.replace(right,par); f.replace(dummy,oldright); if (restoreCursorComp != null) { view.setCursorComp((Component)restoreCursorComp,cpos); } return true; } } else if (parent instanceof PrefixUnaryOp) { PrefixUnaryOp par = (PrefixUnaryOp)parent; if (getPri() < par.getDownPri()) { Identifier dummy = new Identifier(); f.replace(this,dummy); f.replace(par,this); Part oldleft = left; f.replace(left,par); f.replace(dummy,oldleft); return true; } } return false; }
If this Part is badly positioned in the syntax tree, rotate. Else do nothing.
public void rotate(Formula f) { rotate(f,null); } public void rotate(Formula f,FormulaView view) { if (simpleRotate(f,view)) { // rotate upwards while (simpleRotate(f,view)) ; } else while (true) { // rotate downwards? if (left instanceof InfixBinaryOp) { InfixBinaryOp l = (InfixBinaryOp)left; if (l.simpleRotate(f,view)) continue; // keep rotating } else if (right instanceof InfixBinaryOp) { InfixBinaryOp r = (InfixBinaryOp)right; if (r.simpleRotate(f,view)) continue; // keep rotating } break; } if (Part.debuglevel>=95) { System.out.println("-----post rotate dump-----"); view.list(); f.getRootPart().dump(); System.out.println("----------"); } } public boolean same(Object obj) { if (!(obj instanceof InfixBinaryOp)) return false; InfixBinaryOp rot = (InfixBinaryOp)obj; return rot.left.same(left) && rot.right.same(right) && rot.getName().equals(getName()) && rot.getPri()==getPri(); } public void replaceChild(Part child,Part byThat) { if (child == left) { left = byThat; } else if (child == right) { right = byThat; } else { if (debuglevel >= 10) { System.out.println("InfixBinaryOp: "+this+".replace("+child+","+byThat+") error"); try { throw new Exception(); } catch (Exception exc) { exc.printStackTrace(); } } } byThat.parent = this; } Identifier dismantle(String str,Formula f) { Identifier result = new Identifier(str); f.replace(this,new OperatorSpace(left,new OperatorSpace(result,right))); return result; } public Component createView(FormulaView f) { return new InfixBinaryOpView(this,f); }
A default strategy, so a subclass only has to implement saveOperatorLatex()
public void saveLatex(java.io.BufferedWriter w) throws java.io.IOException { left.saveLatex(w); w.write(" "); saveOperatorLatex(w); w.write(" "); right.saveLatex(w); } public void saveOperatorLatex(java.io.BufferedWriter w) throws java.io.IOException { w.write(getName()); } }