Search in sources :

Example 1 with ChangeVariableToInherit

use of gov.sandia.n2a.ui.eq.undo.ChangeVariableToInherit in project n2a by frothga.

the class NodeVariable method applyEdit.

/**
 *        Enforces all the different use cases associated with editing of variables.
 *        This is the most complex node class, and does the most work. Some of the use cases include:
 * Create a new variable.
 * Move an existing variable tree, perhaps overriding an inherited one, perhaps also with a change of value.
 * Insert an equation under ourselves.
 * Insert an equation under another variable.
 */
@Override
public void applyEdit(JTree tree) {
    String input = toString();
    UndoManager um = MainFrame.instance.undoManager;
    boolean canceled = um.getPresentationName().equals("AddVariable");
    if (input.isEmpty()) {
        delete(canceled);
        return;
    }
    String[] parts = input.split("=", 2);
    String nameAfter = parts[0].trim().replaceAll("[ \\n\\t]", "");
    String valueAfter;
    if (// Explicit assignment
    parts.length > 1) {
        valueAfter = parts[1].trim();
        if (valueAfter.startsWith("$kill"))
            valueAfter = valueAfter.substring(5).trim();
    } else {
        // Input was a variable name with no assignment.
        valueAfter = "";
    }
    // What follows is a series of analyses, most having to do with enforcing constraints
    // on name change (which implies moving the variable tree or otherwise modifying another variable).
    // Handle a naked expression.
    String nameBefore = source.key();
    String valueBefore = getValue();
    if (// Not a proper variable name. The user actually passed a naked expression, so resurrect the old (probably auto-assigned) variable name.
    !isValidIdentifier(nameAfter)) {
        nameAfter = nameBefore;
        valueAfter = input;
    }
    // Handle creation of $inherit node.
    FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
    boolean canInject = getChildCount() == 0 && source.isFromTopDocument();
    // Only a heuristic. Could also be an existing variable with no equation.
    boolean newlyCreated = canInject && valueBefore.isEmpty();
    NodeBase parent = (NodeBase) getParent();
    if (nameAfter.equals("$inherit")) {
        if (parent.child(nameAfter) == null) {
            if (newlyCreated) {
                parent.source.clear(nameBefore);
                // No need to update GUI, because AddInherit rebuilds parent.
                um.apply(new AddInherit((NodePart) parent, valueAfter));
            } else {
                um.apply(new ChangeVariableToInherit(this, valueAfter));
            }
            return;
        }
        // Reject name change, because $inherit already exists. User should edit it directly.
        nameAfter = nameBefore;
    }
    // Prevent illegal name change. (Don't override another top-level node. Don't overwrite a non-variable node.)
    NodeBase nodeAfter = parent.child(nameAfter);
    if (nodeAfter != null) {
        boolean isVariable = nodeAfter instanceof NodeVariable;
        boolean different = nodeAfter != this;
        boolean topdoc = nodeAfter.source.isFromTopDocument();
        boolean revoked = nodeAfter.source.get().equals("$kill");
        if (!isVariable || (different && topdoc && !revoked && !canInject)) {
            nameAfter = nameBefore;
            nodeAfter = this;
        }
    }
    // If there's nothing to do, then repaint the node and quit.
    if (nameBefore.equals(nameAfter) && valueBefore.equals(valueAfter)) {
        setUserObject();
        model.nodeChanged(this);
        return;
    }
    // Detect and handle special cases
    if (// There exists a variable in the target location, so we may end up injecting an equation into a multiconditional expression.
    nodeAfter != null) {
        // In this section, "dest" refers to state of target node before it is overwritten, while "after" refers to newly input values from user.
        Variable.ParsedValue piecesDest = new Variable.ParsedValue(((NodeVariable) nodeAfter).getValue());
        Variable.ParsedValue piecesAfter = new Variable.ParsedValue(valueAfter);
        boolean expressionAfter = !piecesAfter.expression.isEmpty() || !piecesAfter.condition.isEmpty();
        // If the user doesn't specify a combiner, absorb it from our destination.
        if (piecesAfter.combiner.isEmpty())
            piecesAfter.combiner = piecesDest.combiner;
        int equationCount = 0;
        NodeEquation equationMatch = null;
        Enumeration<?> childrenAfter = nodeAfter.children();
        while (childrenAfter.hasMoreElements()) {
            Object c = childrenAfter.nextElement();
            if (c instanceof NodeEquation) {
                equationCount++;
                NodeEquation e = (NodeEquation) c;
                if (e.source.key().substring(1).equals(piecesAfter.condition))
                    equationMatch = e;
            }
        }
        if (nodeAfter == this) {
            if (// Inject an equation into ourselves.
            equationCount > 0 && expressionAfter) {
                if (// New equation
                equationMatch == null) {
                    // It is possible to add an equation revocation here without there being an existing equation to revoke.
                    um.apply(new AddEquation(this, piecesAfter.condition, piecesAfter.combiner, piecesAfter.expression));
                } else // Overwrite an existing equation
                {
                    Variable.ParsedValue piecesMatch = new Variable.ParsedValue(piecesDest.combiner + equationMatch.source.get() + equationMatch.source.key());
                    um.apply(new ChangeEquation(this, piecesMatch.condition, piecesMatch.combiner, piecesMatch.expression, piecesAfter.condition, piecesAfter.combiner, piecesAfter.expression));
                }
                return;
            }
        } else // Node has been renamed.
        {
            if (// Inject into/over an existing variable.
            canInject) {
                // Remove this variable, regardless of what we do to nodeAfter.
                um.addEdit(new CompoundEdit());
                um.apply(new DeleteVariable(this, canceled));
                // Decide what change (if any) to apply to nodeAfter.
                if (expressionAfter) {
                    NodeVariable nva = (NodeVariable) nodeAfter;
                    if (equationCount == 0) {
                        if (// Directly overwrite the target, since they share the say name and condition.
                        piecesAfter.condition.equals(piecesDest.condition)) {
                            um.apply(new ChangeVariable(nva, nameAfter, valueAfter, getKeyPath()));
                        } else // Inject new equation and change target into a multiconditional variable.
                        {
                            // Possible to revoke non-existent equation
                            um.apply(new AddEquation(nva, piecesAfter.condition, piecesAfter.combiner, piecesAfter.expression, getKeyPath()));
                        }
                    } else {
                        if (// Add new equation to an existing multiconditional.
                        equationMatch == null) {
                            // Possible to revoke non-existent equation
                            um.apply(new AddEquation(nva, piecesAfter.condition, piecesAfter.combiner, piecesAfter.expression, getKeyPath()));
                        } else // Overwrite an existing equation in a multiconditional
                        {
                            Variable.ParsedValue piecesMatch = new Variable.ParsedValue(piecesDest.combiner + equationMatch.source.get() + equationMatch.source.key());
                            um.apply(new ChangeEquation(nva, piecesMatch.condition, piecesMatch.combiner, piecesMatch.expression, piecesAfter.condition, piecesAfter.combiner, piecesAfter.expression, getKeyPath()));
                        }
                    }
                }
                um.endCompoundEdit();
                return;
            }
        }
    }
    // The @ will be hidden most of the time, but it will distinguish a variable from a part.
    if (valueAfter.isEmpty() && !hasEquations())
        valueAfter = "@";
    um.apply(new ChangeVariable(this, nameAfter, valueAfter));
}
Also used : AddInherit(gov.sandia.n2a.ui.eq.undo.AddInherit) DeleteVariable(gov.sandia.n2a.ui.eq.undo.DeleteVariable) Variable(gov.sandia.n2a.eqset.Variable) ChangeVariable(gov.sandia.n2a.ui.eq.undo.ChangeVariable) CompoundEdit(gov.sandia.n2a.ui.CompoundEdit) DeleteVariable(gov.sandia.n2a.ui.eq.undo.DeleteVariable) ChangeVariable(gov.sandia.n2a.ui.eq.undo.ChangeVariable) Point(java.awt.Point) AddEquation(gov.sandia.n2a.ui.eq.undo.AddEquation) ChangeVariableToInherit(gov.sandia.n2a.ui.eq.undo.ChangeVariableToInherit) ChangeEquation(gov.sandia.n2a.ui.eq.undo.ChangeEquation) UndoManager(gov.sandia.n2a.ui.UndoManager) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel)

Aggregations

Variable (gov.sandia.n2a.eqset.Variable)1 CompoundEdit (gov.sandia.n2a.ui.CompoundEdit)1 UndoManager (gov.sandia.n2a.ui.UndoManager)1 FilteredTreeModel (gov.sandia.n2a.ui.eq.FilteredTreeModel)1 AddEquation (gov.sandia.n2a.ui.eq.undo.AddEquation)1 AddInherit (gov.sandia.n2a.ui.eq.undo.AddInherit)1 ChangeEquation (gov.sandia.n2a.ui.eq.undo.ChangeEquation)1 ChangeVariable (gov.sandia.n2a.ui.eq.undo.ChangeVariable)1 ChangeVariableToInherit (gov.sandia.n2a.ui.eq.undo.ChangeVariableToInherit)1 DeleteVariable (gov.sandia.n2a.ui.eq.undo.DeleteVariable)1 Point (java.awt.Point)1