Search in sources :

Example 11 with FilteredTreeModel

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

the class NodeReference method applyEdit.

@Override
public void applyEdit(JTree tree) {
    String input = (String) getUserObject();
    if (input.isEmpty()) {
        boolean canceled = MainFrame.instance.undoManager.getPresentationName().equals("AddReference");
        delete(canceled);
        return;
    }
    String[] parts = input.split("=", 2);
    String name = parts[0].trim().replaceAll("[ \\n\\t]", "");
    String value;
    if (parts.length > 1)
        value = parts[1].trim();
    else
        value = "";
    NodeBase parent = (NodeBase) getParent();
    String oldName = source.key();
    String oldValue = source.get();
    if (!name.equals(oldName)) {
        // Check if name change is forbidden
        if (name.isEmpty()) {
            name = oldName;
        } else {
            MPart mparent = source.parent();
            MPart partAfter = (MPart) mparent.child(name);
            if (partAfter != null && partAfter.isFromTopDocument())
                name = oldName;
        }
    }
    if (name.equals(oldName) && value.equals(oldValue)) {
        setUserObject();
        FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
        // Our siblings should not change, because we did not really change. Just repaint in non-edit mode.
        model.nodeChanged(this);
        return;
    }
    MainFrame.instance.undoManager.apply(new ChangeReference(parent, oldName, oldValue, name, value));
}
Also used : MPart(gov.sandia.n2a.eqset.MPart) ChangeReference(gov.sandia.n2a.ui.eq.undo.ChangeReference) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel)

Example 12 with FilteredTreeModel

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

the class NodeVariable method makeAdd.

@Override
public Undoable makeAdd(String type, JTree tree, MNode data, Point location) {
    if (type.isEmpty()) {
        FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
        if (model.getChildCount(this) == 0 || tree.isCollapsed(new TreePath(getPath())))
            return ((NodeBase) parent).makeAdd("Variable", tree, data, location);
        type = "Equation";
    }
    if (isBinding && !type.equals("Annotation"))
        return ((NodeBase) parent).makeAdd(type, tree, data, location);
    if (type.equals("Equation")) {
        if (data != null) {
            // includes @
            String key = data.key();
            // Determine if pasting over empty variable (no equations of any type except a naked combiner)
            Variable.ParsedValue existing = new Variable.ParsedValue(source.get());
            boolean hasEquations = !existing.condition.isEmpty() || !existing.expression.isEmpty();
            if (!hasEquations) {
                // unfiltered
                Enumeration<?> children = children();
                while (children.hasMoreElements()) {
                    Object c = children.nextElement();
                    if (c instanceof NodeEquation) {
                        hasEquations = true;
                        break;
                    }
                }
            }
            if (// no equations, or possibly a naked combiner
            !hasEquations) {
                String value = existing.combiner + data.get() + key;
                if (value.endsWith("@"))
                    value = value.substring(0, value.length() - 1);
                return new ChangeVariable(this, source.key(), value);
            }
            // Determine if pasting over an existing equation
            NodeBase existingEquation = child(key);
            if (existingEquation != null) {
                // remove the @, since ChangeEquation expects strings from ParsedValue
                key = key.substring(1);
                String combiner = existing.combiner;
                String newValue = data.get();
                String existingValue = existingEquation.source.get();
                if (!newValue.equals(existingValue))
                    return new ChangeEquation(this, key, combiner, existingValue, key, combiner, newValue);
                // else the user intent is to duplicate the equation for convenience before editing it.
                // In this case, we need to create a new equation with alternate key.
                data = new MVolatile(existingValue, "@" + key + "&&");
            }
        }
        // Determine index for new equation
        int index = 0;
        NodeBase child = null;
        TreePath path = tree.getLeadSelectionPath();
        if (path != null)
            child = (NodeBase) path.getLastPathComponent();
        if (child != null && child.getParent() == this)
            index = getIndex(child);
        while (index > 0 && !(getChildAt(index) instanceof NodeEquation)) index--;
        if (index < getChildCount() && getChildAt(index) instanceof NodeEquation)
            index++;
        // Create an AddEquation action
        return new AddEquation(this, index, data);
    } else if (type.equals("Annotation")) {
        // Determine index at which to insert new annotation
        int index = 0;
        int count = getChildCount();
        while (index < count && !(children.get(index) instanceof NodeReference)) index++;
        return new AddAnnotation(this, index, data);
    } else if (type.equals("Annotations")) {
        // In this case, everything under this node will be rebuilt, so no need to worry about insertion index.
        return new ChangeAnnotations(this, data);
    } else if (type.equals("Reference")) {
        return new AddReference(this, getChildCount(), data);
    } else if (type.equals("References")) {
        return new ChangeReferences(this, data);
    }
    // refer all other requests up the tree
    return ((NodeBase) parent).makeAdd(type, tree, data, location);
}
Also used : ChangeReferences(gov.sandia.n2a.ui.eq.undo.ChangeReferences) DeleteVariable(gov.sandia.n2a.ui.eq.undo.DeleteVariable) Variable(gov.sandia.n2a.eqset.Variable) ChangeVariable(gov.sandia.n2a.ui.eq.undo.ChangeVariable) AddReference(gov.sandia.n2a.ui.eq.undo.AddReference) ChangeVariable(gov.sandia.n2a.ui.eq.undo.ChangeVariable) Point(java.awt.Point) MVolatile(gov.sandia.n2a.db.MVolatile) AddEquation(gov.sandia.n2a.ui.eq.undo.AddEquation) ChangeEquation(gov.sandia.n2a.ui.eq.undo.ChangeEquation) AddAnnotation(gov.sandia.n2a.ui.eq.undo.AddAnnotation) TreePath(javax.swing.tree.TreePath) ChangeAnnotations(gov.sandia.n2a.ui.eq.undo.ChangeAnnotations) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel)

Example 13 with FilteredTreeModel

use of gov.sandia.n2a.ui.eq.FilteredTreeModel 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 14 with FilteredTreeModel

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

the class AddEquation method destroy.

public static void destroy(List<String> path, int equationCount, boolean canceled, String name, String combinerBefore, boolean setSelection) {
    // Retrieve created node
    NodeBase parent = NodeBase.locateNode(path);
    if (parent == null)
        throw new CannotUndoException();
    NodeBase createdNode = parent.child(name);
    PanelEquationTree pet = parent.getTree();
    FilteredTreeModel model = (FilteredTreeModel) pet.tree.getModel();
    TreeNode[] createdPath = createdNode.getPath();
    int index = parent.getIndexFiltered(createdNode);
    if (canceled)
        index--;
    // Update database
    MPart mparent = parent.source;
    mparent.clear(name);
    boolean parentChanged = false;
    if (!mparent.get().equals(combinerBefore)) {
        // This value may be replaced below if we switch back to single-line.
        mparent.set(combinerBefore);
        parentChanged = true;
    }
    if (// There is no overridden value, so this node goes away completely.
    mparent.child(name) == null) {
        model.removeNodeFromParent(createdNode);
        if (// The node used to be single-line, so fold the last equation back into it.
        equationCount == 0) {
            // The one remaining equation.
            NodeEquation lastEquation = null;
            // unfiltered
            Enumeration<?> i = parent.children();
            while (i.hasMoreElements()) {
                Object o = i.nextElement();
                if (o instanceof NodeEquation) {
                    lastEquation = (NodeEquation) o;
                    break;
                }
            }
            String lastCondition = lastEquation.source.key();
            String lastExpression = lastEquation.source.get();
            mparent.clear(lastCondition);
            if (lastCondition.equals("@"))
                mparent.set(combinerBefore + lastExpression);
            else
                mparent.set(combinerBefore + lastExpression + lastCondition);
            parentChanged = true;
            model.removeNodeFromParent(lastEquation);
        }
    } else // Just exposed an overridden value, so update.
    {
        createdNode.setUserObject();
    }
    if (// Update tabs among this variable's siblings
    parentChanged) {
        parent.setUserObject();
        NodeBase grandparent = (NodeBase) parent.getParent();
        grandparent.invalidateColumns(model);
    }
    parent.invalidateColumns(null);
    pet.updateOrder(createdPath);
    pet.updateVisibility(createdPath, index, setSelection);
    parent.allNodesChanged(model);
    pet.animate();
}
Also used : MPart(gov.sandia.n2a.eqset.MPart) NodeBase(gov.sandia.n2a.ui.eq.tree.NodeBase) NodeEquation(gov.sandia.n2a.ui.eq.tree.NodeEquation) TreeNode(javax.swing.tree.TreeNode) CannotUndoException(javax.swing.undo.CannotUndoException) PanelEquationTree(gov.sandia.n2a.ui.eq.PanelEquationTree) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel)

Example 15 with FilteredTreeModel

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

the class NodePart method applyEdit.

@Override
public void applyEdit(JTree tree) {
    FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
    String input = (String) getUserObject();
    String[] pieces = input.split("=", 2);
    String name = pieces[0].trim();
    String oldKey = source.key();
    if (name.equals(oldKey)) {
        revert(model);
        return;
    }
    UndoManager um = MainFrame.instance.undoManager;
    if (// Edits to root cause a rename of the document on disk
    isTrueRoot()) {
        if (name.isEmpty()) {
            revert(model);
            return;
        }
        name = MDir.validFilenameFrom(name);
        // In addition to filename constraints, we also forbid comma, because these names are used in list expressions.
        name = name.replace(",", "-");
        String stem = name;
        int suffix = 0;
        MNode models = AppData.models;
        MNode existingDocument = models.child(name);
        while (existingDocument != null) {
            suffix++;
            name = stem + " " + suffix;
            existingDocument = models.child(name);
        }
        um.apply(new ChangeDoc(oldKey, name));
        // MDir promises to maintain object identity during the move, so "source" is still valid.
        return;
    }
    if (input.isEmpty()) {
        // A part may appear in the form of a graph node, rather than an entry in an equation tree.
        // In that case, delete during the current event can mess up focus control (due to sequence of other code).
        // Therefore, put the delete action onto the event queue. This is OK to do, even for tree editing.
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                boolean canceled = um.getPresentationName().equals("AddPart");
                delete(canceled);
            }
        });
        return;
    }
    name = validIdentifierFrom(name);
    NodeBase parent = getTrueParent();
    NodeBase sibling = parent.child(name);
    if (// the name already exists in top document, so reject rename
    sibling != null && (sibling.source.isFromTopDocument() || !(sibling instanceof NodePart))) {
        revert(model);
        return;
    }
    um.apply(new ChangePart(this, oldKey, name));
}
Also used : UndoManager(gov.sandia.n2a.ui.UndoManager) ChangeDoc(gov.sandia.n2a.ui.eq.undo.ChangeDoc) FilteredTreeModel(gov.sandia.n2a.ui.eq.FilteredTreeModel) MNode(gov.sandia.n2a.db.MNode) Point(java.awt.Point) ChangePart(gov.sandia.n2a.ui.eq.undo.ChangePart)

Aggregations

FilteredTreeModel (gov.sandia.n2a.ui.eq.FilteredTreeModel)46 MPart (gov.sandia.n2a.eqset.MPart)34 TreeNode (javax.swing.tree.TreeNode)31 PanelEquationTree (gov.sandia.n2a.ui.eq.PanelEquationTree)29 NodeBase (gov.sandia.n2a.ui.eq.tree.NodeBase)28 CannotRedoException (javax.swing.undo.CannotRedoException)21 NodePart (gov.sandia.n2a.ui.eq.tree.NodePart)18 TreePath (javax.swing.tree.TreePath)18 CannotUndoException (javax.swing.undo.CannotUndoException)15 NodeVariable (gov.sandia.n2a.ui.eq.tree.NodeVariable)14 PanelEquations (gov.sandia.n2a.ui.eq.PanelEquations)11 JTree (javax.swing.JTree)10 PanelEquationGraph (gov.sandia.n2a.ui.eq.PanelEquationGraph)9 NodeContainer (gov.sandia.n2a.ui.eq.tree.NodeContainer)9 Variable (gov.sandia.n2a.eqset.Variable)8 MNode (gov.sandia.n2a.db.MNode)7 PanelModel (gov.sandia.n2a.ui.eq.PanelModel)6 NodeAnnotations (gov.sandia.n2a.ui.eq.tree.NodeAnnotations)6 FontMetrics (java.awt.FontMetrics)6 Point (java.awt.Point)6