use of gov.sandia.n2a.ui.eq.undo.ChangeEquation in project n2a by frothga.
the class NodeEquation method delete.
@Override
public void delete(JTree tree, boolean canceled) {
if (source.isFromTopDocument()) {
PanelModel.instance.undoManager.add(new DeleteEquation(this, canceled));
} else {
NodeVariable parent = (NodeVariable) getParent();
String combiner = parent.source.get();
// strip @ from name, as required by ChangeEquation
String name = source.key().substring(1);
String value = source.get();
// revoke the equation
PanelModel.instance.undoManager.add(new ChangeEquation(parent, name, combiner, value, name, combiner, ""));
}
}
use of gov.sandia.n2a.ui.eq.undo.ChangeEquation in project n2a by frothga.
the class NodeVariable method add.
@Override
public NodeBase add(String type, JTree tree, MNode data) {
FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
if (type.isEmpty()) {
if (model.getChildCount(this) == 0 || tree.isCollapsed(new TreePath(getPath())))
return ((NodeBase) getParent()).add("Variable", tree, data);
type = "Equation";
}
if (isBinding)
return ((NodeBase) getParent()).add(type, tree, data);
if (type.equals("Equation")) {
// Determine if pasting over an existing equation
if (data != null) {
// includes @
String key = data.key();
NodeBase existingEquation = child(key);
if (existingEquation != null) {
// remove the @, since ChangeEquation expects strings from ParsedValue
key = key.substring(1);
String combiner = new Variable.ParsedValue(source.get()).combiner;
PanelModel.instance.undoManager.add(new ChangeEquation(this, key, combiner, existingEquation.source.get(), key, combiner, data.get()));
// Somewhat of a cheat, since we didn't really add it. OTOH, a paste operation should not be followed by edit mode.
return existingEquation;
}
}
// Determine index for new equation
int index = 0;
NodeBase child = (NodeBase) tree.getLastSelectedPathComponent();
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
AddEquation ae = new AddEquation(this, index, data);
PanelModel.instance.undoManager.add(ae);
return ae.createdNode;
} 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++;
AddAnnotation aa = new AddAnnotation(this, index, data);
PanelModel.instance.undoManager.add(aa);
return aa.createdNode;
} else if (type.equals("Reference")) {
AddReference ar = new AddReference(this, getChildCount(), data);
PanelModel.instance.undoManager.add(ar);
return ar.createdNode;
}
// refer all other requests up the tree
return ((NodeBase) getParent()).add(type, tree, data);
}
use of gov.sandia.n2a.ui.eq.undo.ChangeEquation 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);
}
use of gov.sandia.n2a.ui.eq.undo.ChangeEquation 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));
}
use of gov.sandia.n2a.ui.eq.undo.ChangeEquation in project n2a by frothga.
the class NodeEquation method makeDelete.
@Override
public Undoable makeDelete(boolean canceled) {
if (source.isFromTopDocument())
return new DeleteEquation(this, canceled);
NodeVariable parent = (NodeVariable) getParent();
String combiner = parent.source.get();
// strip @ from name, as required by ChangeEquation
String name = source.key().substring(1);
String value = source.get();
// revoke the equation
return new ChangeEquation(parent, name, combiner, value, name, combiner, "$kill");
}
Aggregations