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));
}
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);
}
}
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;
}
}
Aggregations