package ui.bigstep; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.Rectangle; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import common.ProofRule; import common.ProofStep; import common.interpreters.InterpreterProofModel; import expressions.Expression; import expressions.Location; import bigstep.BigStepProofNode; import ui.AbstractNode; import ui.beans.MenuButton; import ui.beans.MenuButtonListener; import ui.beans.StringComponent; import ui.renderer.CompoundExpression; public class BigStepNode extends AbstractNode { private enum ActionType { TranslateToCoresyntax, Guess, } private class RuleMenuItem extends JMenuItem { private ProofRule rule; public RuleMenuItem (ProofRule rule) { super (rule.getName()); this.rule = rule; } public ProofRule getRule () { return rule; } }; private static class ActionMenuItem extends JMenuItem { private ActionType type; public ActionMenuItem (ActionType type) { super (ActionMenuItem.getString(type)); this.type = type; } private static String getString(ActionType type) { switch (type) { case TranslateToCoresyntax: return "Translate to coresyntax"; case Guess: return "Guess"; } return "narf"; } public ActionType getActionType () { return type; } } private ActionMenuItem translateToCoreSyntax = null; private ActionMenuItem actionGuess = null; private StringComponent locationIdComponent = null; private StringComponent downArrowComponent = null; private CompoundExpression expression = null; private CompoundExpression resultExpression = null; private MenuButton menuButton = null; private StringComponent ruleString = null; private GridBagLayout layout = null; private BigStepProofNode proofNode; private int locationId; public BigStepNode (BigStepProofNode proofNode) { super (); this.proofNode = proofNode; this.locationIdComponent = new StringComponent("(x)"); this.downArrowComponent = new StringComponent("\u21d3"); this.expression = new CompoundExpression<Location, Expression>(proofNode.getExpression()); this.resultExpression = new CompoundExpression<Location, Expression>(); this.menuButton = new MenuButton(); this.ruleString = new StringComponent("Rule"); setLayout (null); this.expression.setUseColoring(true); this.resultExpression.setUseColoring(false); add (this.locationIdComponent); add (this.downArrowComponent); add (this.expression); add (this.resultExpression); add (this.menuButton); add (this.ruleString); this.menuButton.addMenuButtonListener(new MenuButtonListener() { public void menuItemActivated (MenuButton source, JMenuItem item) { if (item instanceof RuleMenuItem) { evaluateRule(((RuleMenuItem)item).getRule()); } else if (item instanceof ActionMenuItem) { ActionMenuItem ami = (ActionMenuItem)item; switch (ami.getActionType()) { case TranslateToCoresyntax: translateToCoreSyntax(); break; case Guess: guessNode (); } } } public void menuClosed (MenuButton source) { } }); } public void buildMenu () { JPopupMenu menu = new JPopupMenu(); ProofRule rules[] = this.model.getRules(); for (ProofRule r : rules) { menu.add(new RuleMenuItem (r)); } menu.addSeparator(); this.translateToCoreSyntax = new ActionMenuItem (ActionType.TranslateToCoresyntax); menu.add(this.translateToCoreSyntax); if (!this.proofNode.containsSyntacticSugar()) { this.translateToCoreSyntax.setEnabled(false); } this.actionGuess = new ActionMenuItem (ActionType.Guess); menu.add(this.actionGuess); this.menuButton.setMenu(menu); } public void updateNode () { if (this.proofNode != null) { if (this.proofNode.getResult () != null) { this.resultExpression.setExpression(this.proofNode.getResult().getValue()); } this.expression.setExpression(this.proofNode.getExpression()); } if (((InterpreterProofModel)model).isMemoryEnabled()) { if (this.proofNode.getResult() != null) { this.resultExpression.setEnvironment( ((BigStepProofNode)this.proofNode).getResult().getStore()); } this.expression.setEnvironment( ((BigStepProofNode)this.proofNode).getStore()); } } public Dimension layout (int width) { int margin = 4; int spacing = 4; int completeNeededWidth = this.expression.getMaxExpressionDimension().width + this.resultExpression.getMaxExpressionDimension().width; // remainginWidth is the origin width minus the id // the down arrow and the margins and spacings int remainingWidth = width - this.locationIdComponent.getPreferredSize().width - this.downArrowComponent.getPreferredSize().width; float expFactor = (float)this.expression.getMaxExpressionDimension().width / (float)completeNeededWidth; float resFactor = 1.0f - expFactor; Dimension size = null; Dimension expDim = this.expression.getDimensions((int)(expFactor * (float)remainingWidth)); Dimension resDim = this.resultExpression.getDimensions((int)(resFactor * (float)remainingWidth)); int maxHeight = expDim.height > resDim.height ? expDim.height : resDim.height; JComponent ruleComp; if (this.proofNode.getSteps ().length == 0) { ruleComp = this.menuButton; this.menuButton.setVisible(true); this.ruleString.setVisible(false); } else { ruleComp = this.ruleString; this.menuButton.setVisible(false); this.ruleString.setVisible(true); } size = new Dimension ( margin * 2 + this.locationIdComponent.getPreferredSize().width + expDim.width + this.downArrowComponent.getPreferredSize().width + resDim.width, maxHeight + 2*margin + spacing + ruleComp.getPreferredSize().height); setSize (size); setPreferredSize (size); setMinimumSize (size); setMaximumSize (size); int posX = margin; this.locationIdComponent.setBounds(posX, margin, this.locationIdComponent.getPreferredSize().width, maxHeight); posX += this.locationIdComponent.getPreferredSize().width; this.expression.setBounds(posX, margin, expDim.width, maxHeight); posX += expDim.width; this.downArrowComponent.setBounds(posX, margin, this.downArrowComponent.getPreferredSize().width, maxHeight); posX += this.downArrowComponent.getPreferredSize().width; this.resultExpression.setBounds(posX, margin, resDim.width, maxHeight); ruleComp.setBounds(this.locationIdComponent.getX() + this.locationIdComponent.getWidth(), margin + maxHeight + spacing, ruleComp.getPreferredSize().width, ruleComp.getPreferredSize().height); return size; } public void setLocationId (int id) { this.locationId = id; this.locationIdComponent.setString("(" + id + ")"); } public void evaluateRule (ProofRule rule) { try { // prepare the view that something is about to change next this.fireBigStepNodeAboutToProve(); this.model.prove(rule, this.proofNode); ProofStep[] steps = this.proofNode.getSteps(); if (steps.length != 0) { this.ruleString.setString("(" + steps [0].getRule().getName() + ")"); } } catch (Exception e) { this.menuButton.setTextColor(Color.RED); } } public void translateToCoreSyntax() { // prepare the view that something is about to change next this.fireBigStepNodeAboutToProve(); this.model.translateToCoreSyntax(this.proofNode); } public void guessNode () { try { // prepare the view that something is about to change next this.fireBigStepNodeAboutToProve(); this.model.guess(this.proofNode); ProofStep[] steps = this.proofNode.getSteps(); if (steps.length != 0) { this.ruleString.setString("(" + steps [0].getRule().getName() + ")"); } } catch (Exception e) { } } public Point getArrowPoint() { Rectangle rect = this.locationIdComponent.getBounds(); return new Point (rect.x + rect.width / 2, rect.y + rect.height); } public Point getJointPoint() { Rectangle rect = this.locationIdComponent.getBounds(); return new Point (rect.x, rect.y + rect.height / 2); } public void addBigStepNodeListener (BigStepNodeListener listener) { this.listenerList.add(BigStepNodeListener.class, listener); } public void fireBigStepNodeAboutToProve () { Object[] listeners = this.listenerList.getListenerList(); for (int i=0;i<listeners.length; i+=2) { if (listeners[i+0] == BigStepNodeListener.class) { BigStepNodeListener listener = (BigStepNodeListener)listeners[i+1]; if (listener == null) continue; listener.aboutToProve(this.proofNode); } } } }