Search in sources :

Example 1 with AddInherit

use of gov.sandia.n2a.ui.eq.undo.AddInherit 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)

Example 2 with AddInherit

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

the class NodePart method makeAdd.

@Override
public Undoable makeAdd(String type, JTree tree, MNode data, Point location) {
    if (tree == null) {
        // The only thing we can add is a part in the current graph view.
        if (!type.equals("Part"))
            return null;
    } else {
        boolean collapsed = tree.isCollapsed(new TreePath(getPath()));
        boolean hasChildren = ((FilteredTreeModel) tree.getModel()).getChildCount(this) > 0;
        if (// The node is deliberately closed to indicate user intent.
        collapsed && hasChildren) {
            if (type.isEmpty())
                type = "Part";
            return ((NodePart) parent).makeAdd(type, tree, data, location);
        }
    // else this is an open node, so anything can be inserted under it.
    }
    int variableIndex = -1;
    int subpartIndex = -1;
    int metadataIndex = 0;
    // unfiltered, so we can insert at the correct place in the underlying collection
    int count = getChildCount();
    for (int i = 0; i < count; i++) {
        TreeNode t = getChildAt(i);
        if (t instanceof NodeInherit) {
            metadataIndex = i + 1;
        }
        if (t instanceof NodePart) {
            if (variableIndex < 0)
                variableIndex = i;
            subpartIndex = i + 1;
        }
    }
    if (variableIndex < 0)
        variableIndex = count;
    if (subpartIndex < 0)
        subpartIndex = count;
    if (tree != null) {
        TreePath path = tree.getLeadSelectionPath();
        if (path != null) {
            NodeBase selected = (NodeBase) path.getLastPathComponent();
            if (selected.getParent() == this) {
                // When we have a specific item selected, the user expects the new item to appear directly below it.
                // unfiltered
                int selectedIndex = getIndex(selected);
                variableIndex = selectedIndex + 1;
                subpartIndex = selectedIndex + 1;
            }
        }
    }
    if (type.equals("Annotation")) {
        // will automagically insert a $metadata block if needed
        return new AddAnnotation(this, metadataIndex, data);
    } else if (type.equals("Annotations")) {
        return new ChangeAnnotations(this, data);
    } else if (type.equals("Reference")) {
        return new AddReference(this, metadataIndex, data);
    } else if (type.equals("References")) {
        return new ChangeReferences(this, data);
    } else if (type.equals("Part")) {
        return new AddPart(this, subpartIndex, data, location);
    } else if (type.equals("Inherit")) {
        return new AddInherit(this, data.get());
    } else // treat all other requests as "Variable"
    {
        if (data != null && type.equals("Equation")) {
            // convert equation into nameless variable
            data = new MVolatile(data.get() + data.key(), "");
        }
        return new AddVariable(this, variableIndex, data);
    }
}
Also used : ChangeReferences(gov.sandia.n2a.ui.eq.undo.ChangeReferences) AddInherit(gov.sandia.n2a.ui.eq.undo.AddInherit) AddVariable(gov.sandia.n2a.ui.eq.undo.AddVariable) AddReference(gov.sandia.n2a.ui.eq.undo.AddReference) Point(java.awt.Point) MVolatile(gov.sandia.n2a.db.MVolatile) AddAnnotation(gov.sandia.n2a.ui.eq.undo.AddAnnotation) TreePath(javax.swing.tree.TreePath) AddPart(gov.sandia.n2a.ui.eq.undo.AddPart) TreeNode(javax.swing.tree.TreeNode) ChangeAnnotations(gov.sandia.n2a.ui.eq.undo.ChangeAnnotations)

Example 3 with AddInherit

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

the class NodePart method add.

public NodeBase add(String type, JTree tree, MNode data) {
    FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
    if (// The node is deliberately closed to indicate user intent.
    tree.isCollapsed(new TreePath(getPath())) && model.getChildCount(this) > 0 && !isRoot()) {
        // The only thing that can contain a NodePart is another NodePart. (If that ever changes, the following code will break.)
        if (type.isEmpty())
            return ((NodePart) getParent()).add("Part", tree, data);
        return ((NodePart) getParent()).add(type, tree, data);
    }
    int variableIndex = -1;
    int subpartIndex = -1;
    int metadataIndex = 0;
    // unfiltered, so we can insert at the correct place in the underlying collection
    int count = getChildCount();
    for (int i = 0; i < count; i++) {
        TreeNode t = getChildAt(i);
        if (t instanceof NodeInherit) {
            metadataIndex = i + 1;
        }
        if (t instanceof NodePart) {
            if (variableIndex < 0)
                variableIndex = i;
            subpartIndex = i + 1;
        }
    }
    if (variableIndex < 0)
        variableIndex = count;
    if (subpartIndex < 0)
        subpartIndex = count;
    TreePath path = tree.getSelectionPath();
    if (path != null) {
        NodeBase selected = (NodeBase) path.getLastPathComponent();
        if (selected.getParent() == this) {
            // When we have a specific item selected, the user expects the new item to appear directly below it.
            // unfiltered
            int selectedIndex = getIndex(selected);
            variableIndex = selectedIndex + 1;
            subpartIndex = selectedIndex + 1;
        }
    }
    if (type.equals("Annotation")) {
        AddAnnotation aa = new AddAnnotation(this, metadataIndex, data);
        // aa will automagically insert a $metadata block if needed
        PanelModel.instance.undoManager.add(aa);
        return aa.createdNode;
    } else if (type.equals("Annotations")) {
        // TODO: figure out how to handle this case
        return null;
    } else if (type.equals("Reference")) {
        AddReference ar = new AddReference(this, metadataIndex, data);
        PanelModel.instance.undoManager.add(ar);
        return ar.createdNode;
    } else if (type.equals("References")) {
        // TODO: figure out how to handle this case
        return null;
    } else if (type.equals("Part")) {
        AddPart ap = new AddPart(this, subpartIndex, data);
        PanelModel.instance.undoManager.add(ap);
        return ap.createdNode;
    } else if (type.equals("Inherit")) {
        Undoable un = null;
        NodeInherit inherit = (NodeInherit) child("$inherit");
        String value = "";
        if (data != null)
            value = data.get();
        if (inherit == null) {
            un = new AddInherit(this, value);
        } else if (!value.isEmpty()) {
            un = new ChangeInherit(inherit, value);
        }
        if (un != null)
            PanelModel.instance.undoManager.add(un);
        return child("$inherit");
    } else // treat all other requests as "Variable"
    {
        if (data != null && type.equals("Equation")) {
            // convert equation into nameless variable
            data = new MVolatile("", data.get() + data.key());
        }
        AddVariable av = new AddVariable(this, variableIndex, data);
        PanelModel.instance.undoManager.add(av);
        return av.createdNode;
    }
}
Also used : Undoable(gov.sandia.n2a.ui.Undoable) AddInherit(gov.sandia.n2a.ui.eq.undo.AddInherit) AddVariable(gov.sandia.n2a.ui.eq.undo.AddVariable) AddReference(gov.sandia.n2a.ui.eq.undo.AddReference) MVolatile(gov.sandia.n2a.db.MVolatile) AddAnnotation(gov.sandia.n2a.ui.eq.undo.AddAnnotation) TreePath(javax.swing.tree.TreePath) AddPart(gov.sandia.n2a.ui.eq.undo.AddPart) TreeNode(javax.swing.tree.TreeNode) ChangeInherit(gov.sandia.n2a.ui.eq.undo.ChangeInherit) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel)

Aggregations

AddInherit (gov.sandia.n2a.ui.eq.undo.AddInherit)3 MVolatile (gov.sandia.n2a.db.MVolatile)2 FilteredTreeModel (gov.sandia.n2a.ui.eq.FilteredTreeModel)2 AddAnnotation (gov.sandia.n2a.ui.eq.undo.AddAnnotation)2 AddPart (gov.sandia.n2a.ui.eq.undo.AddPart)2 AddReference (gov.sandia.n2a.ui.eq.undo.AddReference)2 AddVariable (gov.sandia.n2a.ui.eq.undo.AddVariable)2 Point (java.awt.Point)2 TreeNode (javax.swing.tree.TreeNode)2 TreePath (javax.swing.tree.TreePath)2 Variable (gov.sandia.n2a.eqset.Variable)1 CompoundEdit (gov.sandia.n2a.ui.CompoundEdit)1 UndoManager (gov.sandia.n2a.ui.UndoManager)1 Undoable (gov.sandia.n2a.ui.Undoable)1 AddEquation (gov.sandia.n2a.ui.eq.undo.AddEquation)1 ChangeAnnotations (gov.sandia.n2a.ui.eq.undo.ChangeAnnotations)1 ChangeEquation (gov.sandia.n2a.ui.eq.undo.ChangeEquation)1 ChangeInherit (gov.sandia.n2a.ui.eq.undo.ChangeInherit)1 ChangeReferences (gov.sandia.n2a.ui.eq.undo.ChangeReferences)1 ChangeVariable (gov.sandia.n2a.ui.eq.undo.ChangeVariable)1