use of gov.sandia.n2a.ui.eq.FilteredTreeModel in project n2a by frothga.
the class ChangePart method apply.
public void apply(String nameBefore, String nameAfter) {
NodePart parent = (NodePart) NodeBase.locateNode(path);
if (parent == null)
throw new CannotRedoException();
NodeBase temp = parent.child(nameBefore);
if (!(temp instanceof NodePart))
throw new CannotRedoException();
NodePart nodeBefore = (NodePart) temp;
// Update the database
// Move the subtree
MPart mparent = parent.source;
mparent.clear(nameBefore);
mparent.set(savedTree, nameAfter);
MPart oldPart = (MPart) mparent.child(nameBefore);
MPart newPart = (MPart) mparent.child(nameAfter);
// Change connection bindings to this part.
// See ChangeVariable.apply() for a similar procedure. More detailed comments appear there.
// We make use of static functions in that class to do the heavy work of emitting code with name changes.
// TODO: This approach will probably fail on parts that contain references to themselves.
PanelEquations pe = PanelModel.instance.panelEquations;
List<List<String>> references = new ArrayList<List<String>>();
try {
MPart doc = pe.root.source;
EquationSet compiled = new EquationSet(doc);
List<String> keypath = new ArrayList<String>(path.subList(1, path.size()));
EquationSet eold;
EquationSet enew;
if (oldPart == null) {
EquationSet p = (EquationSet) compiled.getObject(keypath);
eold = new EquationSet(p, nameBefore);
p.parts.add(eold);
keypath.add(nameAfter);
} else {
keypath.add(nameBefore);
eold = (EquationSet) compiled.getObject(keypath);
keypath.set(keypath.size() - 1, nameAfter);
}
enew = (EquationSet) compiled.getObject(keypath);
try {
compiled.resolveConnectionBindings();
} catch (Exception e) {
}
try {
compiled.resolveLHS();
compiled.resolveRHS();
} catch (Exception e) {
}
ChangeVariable.prepareConnections(compiled);
// Collect variables that might have changed.
List<Variable> users = collectVariables(compiled, eold);
if (eold.dependentConnections != null) {
// The variable associated with such a connection binding could explicitly mention the part name.
for (ConnectionBinding cb : eold.dependentConnections) users.add(cb.variable);
}
eold.name = enew.name;
for (Variable v : users) {
List<String> ref = v.getKeyPath();
MNode n = doc.child(ref.toArray());
String oldKey = n.key();
String newKey = ChangeVariable.changeReferences(eold, n, v);
if (// Handle a change in variable name.
!newKey.equals(oldKey)) {
NodeBase nb = pe.root.locateNodeFromHere(ref);
n.parent().move(oldKey, newKey);
ref.set(ref.size() - 1, newKey);
nb.source = (MPart) doc.child(ref.toArray());
}
// Queue GUI updates for nodes other than the primary ones.
if (v.container != enew && v.container != eold)
references.add(ref);
}
} catch (Exception e) {
}
// Change pin links to this part.
// Scan peer parts (which is the only place a pin link can be declared) and check for "bind" keys that reference nameBefore.
// for updating GUI later
Map<NodePart, List<String>> rebind = new HashMap<NodePart, List<String>>();
Enumeration<?> siblings = parent.children();
while (siblings.hasMoreElements()) {
Object o = siblings.nextElement();
if (!(o instanceof NodePart))
continue;
NodePart sibling = (NodePart) o;
MNode pins;
if (// because the old source is no longer attached to document
sibling == nodeBefore)
// because the old source is no longer attached to document
pins = parent.source.child(nameAfter, "$metadata", "gui", "pin", "in");
else
pins = sibling.source.child("$metadata", "gui", "pin", "in");
if (pins == null)
continue;
List<String> bound = null;
for (MNode pin : pins) {
if (pin.get("bind").equals(nameBefore)) {
pin.set(nameAfter, "bind");
// Also set the new name in collated pin data.
sibling.pinIn.set(nameAfter, pin.key(), "bind");
if (bound == null)
bound = new ArrayList<String>();
bound.add(pin.key());
}
}
if (bound != null)
rebind.put(sibling, bound);
}
// Check parent for pin exports.
MNode pins = parent.source.child("$metadata", "gui", "pin", "out");
if (pins != null) {
List<String> bound = null;
for (MNode pin : pins) {
if (pin.get("bind").equals(nameBefore)) {
pin.set(nameAfter, "bind");
if (bound == null)
bound = new ArrayList<String>();
bound.add(pin.key());
}
}
if (bound != null)
rebind.put(parent, bound);
}
// Update GUI
boolean graphParent = parent == pe.part;
PanelEquationTree pet = graphParent ? null : parent.getTree();
FilteredTreeModel model = null;
if (pet != null)
model = (FilteredTreeModel) pet.tree.getModel();
// Only used if graphParent is true.
PanelEquationGraph peg = pe.panelEquationGraph;
// It's either a NodePart or it's null. Any other case should be blocked by GUI constraints.
NodePart nodeAfter = (NodePart) parent.child(nameAfter);
boolean addGraphNode = false;
if (// Only one node will remain when we are done.
oldPart == null) {
pe.renameFocus(nodeBefore.getKeyPath(), nameAfter);
if (// This is a simple rename, with no restructuring. Keep nodeBefore.
nodeAfter == null) {
nodeAfter = nodeBefore;
nodeAfter.source = newPart;
if (graphParent)
peg.updatePart(nodeAfter);
} else // Use existing nodeAfter, so get rid of nodeBefore.
{
if (model == null)
FilteredTreeModel.removeNodeFromParentStatic(nodeBefore);
else
model.removeNodeFromParent(nodeBefore);
if (graphParent)
peg.removePart(nodeBefore, true);
}
} else // Need two nodes
{
if (// Need a node to hold the new part.
nodeAfter == null) {
int index = parent.getIndex(nodeBefore);
nodeAfter = new NodePart(newPart);
nodeAfter.hide = graphParent;
if (model == null)
FilteredTreeModel.insertNodeIntoUnfilteredStatic(nodeAfter, parent, index);
else
model.insertNodeIntoUnfiltered(nodeAfter, parent, index);
addGraphNode = true;
}
nodeBefore.build();
nodeBefore.findConnections();
nodeBefore.rebuildPins();
nodeBefore.filter();
if (nodeBefore.visible()) {
if (// Need to update entire model under fake root.
graphParent) {
PanelEquationTree subpet = nodeBefore.getTree();
if (subpet != null) {
FilteredTreeModel submodel = (FilteredTreeModel) subpet.tree.getModel();
submodel.nodeStructureChanged(nodeBefore);
subpet.animate();
}
} else if (model != null) {
model.nodeStructureChanged(nodeBefore);
}
} else {
parent.hide(nodeBefore, model);
}
}
nodeAfter.build();
if (graphParent)
parent.findConnections();
else
nodeAfter.findConnections();
nodeAfter.rebuildPins();
nodeAfter.filter();
pe.resetBreadcrumbs();
TreeNode[] nodePath = nodeAfter.getPath();
Set<PanelEquationTree> needAnimate = new HashSet<PanelEquationTree>();
if (pet == null) {
PanelEquationTree.updateOrder(null, nodePath);
PanelEquationTree.updateVisibility(null, nodePath, -2, false);
} else {
pet.updateOrder(nodePath);
// Will include nodeStructureChanged(), if necessary.
pet.updateVisibility(nodePath);
needAnimate.add(pet);
}
for (List<String> ref : references) {
NodeVariable n = (NodeVariable) pe.root.locateNodeFromHere(ref);
if (n == null)
continue;
// Rebuild n, because equations and/or their conditions may have changed.
n.build();
n.findConnections();
n.filter();
if (// n's visibility won't change
n.visible()) {
PanelEquationTree subpet = n.getTree();
if (subpet == null)
continue;
JTree subtree = subpet.tree;
FilteredTreeModel submodel = (FilteredTreeModel) subtree.getModel();
NodeBase subparent = (NodeBase) n.getParent();
// Node will collapse if it was open. Don't worry about this.
submodel.nodeStructureChanged(n);
subparent.invalidateColumns(submodel);
needAnimate.add(subpet);
}
}
for (NodePart peer : rebind.keySet()) {
PanelEquationTree subpet = peer.getTree();
// also works for parent
NodeBase metadata = peer.child("$metadata");
for (String pinKey : rebind.get(peer)) {
// Retrieve GUI metadata node so it can be updated to match DB.
NodeBase nodeBind;
if (peer == parent)
nodeBind = (NodeAnnotation) AddAnnotation.findExact(metadata, false, "gui", "pin", "out", pinKey, "bind");
else
nodeBind = (NodeAnnotation) AddAnnotation.findExact(metadata, false, "gui", "pin", "in", pinKey, "bind");
nodeBind.setUserObject();
// Update display tree.
if (subpet != null) {
// For simplicity, look up subtree, submodel and subparent each time,
// even though they could be done just once per peer part.
JTree subtree = subpet.tree;
FilteredTreeModel submodel = (FilteredTreeModel) subtree.getModel();
NodeBase subparent = (NodeBase) nodeBind.getParent();
submodel.nodeChanged(nodeBind);
subparent.invalidateColumns(submodel);
needAnimate.add(subpet);
}
}
}
for (PanelEquationTree ap : needAnimate) ap.animate();
if (graphParent) {
if (addGraphNode) {
// builds tree
peg.addPart(nodeAfter);
} else {
PanelEquationTree subpet = nodeAfter.getTree();
if (subpet != null) {
FilteredTreeModel submodel = (FilteredTreeModel) subpet.tree.getModel();
submodel.nodeStructureChanged(nodeAfter);
FocusCacheEntry fce = pe.createFocus(nodeAfter);
if (fce.sp != null)
fce.sp.restore(subpet.tree, false);
subpet.animate();
}
}
nodeAfter.hide = false;
nodeAfter.graph.takeFocusOnTitle();
peg.updatePins();
peg.reconnect();
peg.repaint();
}
}
use of gov.sandia.n2a.ui.eq.FilteredTreeModel in project n2a by frothga.
the class ChangeReferences method apply.
public void apply(MNode add, MNode remove) {
NodeBase parent = NodeBase.locateNode(path);
if (parent == null)
throw new CannotUndoException();
PanelEquationTree pet = parent.getTree();
FilteredTreeModel model = null;
StoredPath sp = null;
if (pet != null) {
model = (FilteredTreeModel) pet.tree.getModel();
sp = new StoredPath(pet.tree);
}
// The immediate container of reference items in the tree.
NodeContainer referenceNode;
// The $reference node under which all changes are made.
MNode referenceSource = null;
if (parent instanceof NodeVariable) {
referenceNode = (NodeContainer) parent;
referenceSource = referenceNode.source.child("$reference");
} else // NodePart is the default case
{
referenceNode = (NodeContainer) parent.child("$reference");
if (referenceNode != null)
referenceSource = referenceNode.source;
}
boolean needBuild = true;
if (// This is an undo, and $reference did not exist before, so remove it.
add == null) {
// We can safely assume that referenceSource is non-null, since we only get here during an undo.
referenceSource.parent().clear("$reference");
if (parent instanceof NodePart) {
if (model == null)
FilteredTreeModel.removeNodeFromParentStatic(referenceNode);
else
model.removeNodeFromParent(referenceNode);
needBuild = false;
}
} else // Update $reference node. Create if it doesn't exist.
{
if (referenceSource == null)
referenceSource = parent.source.childOrCreate("$reference");
if (// only happens when parent is NodePart
referenceNode == null) {
referenceNode = new NodeReferences((MPart) referenceSource);
if (model == null)
FilteredTreeModel.insertNodeIntoUnfilteredStatic(referenceNode, parent, index);
else
model.insertNodeIntoUnfiltered(referenceNode, parent, index);
}
if (remove != null)
referenceSource.uniqueNodes(remove);
referenceSource.merge(add);
}
if (needBuild) {
referenceNode.build();
referenceNode.filter();
if (model != null && referenceNode.visible()) {
model.nodeStructureChanged(referenceNode);
}
}
PanelEquationTree.updateVisibility(pet, referenceNode.getPath(), -1, false);
// This forces focus back to original location.
if (!multi && sp != null)
sp.restore(pet.tree, true);
if (pet != null)
pet.animate();
}
use of gov.sandia.n2a.ui.eq.FilteredTreeModel in project n2a by frothga.
the class ChangeVariableToInherit method undo.
public void undo() {
super.undo();
NodePart parent = (NodePart) NodeBase.locateNode(path);
if (parent == null)
throw new CannotUndoException();
NodePart grandparent = (NodePart) parent.getTrueParent();
// Update the database
MPart mparent = parent.source;
mparent.clear("$inherit");
String nameBefore = treeBefore.key();
mparent.set(treeBefore, nameBefore);
// Update the GUI
PanelEquations pe = PanelModel.instance.panelEquations;
PanelEquationTree pet = parent.getTree();
FilteredTreeModel model = (FilteredTreeModel) pet.tree.getModel();
PanelEquationGraph peg = pe.panelEquationGraph;
parent.build();
if (grandparent == null)
parent.findConnections();
else
grandparent.findConnections();
parent.rebuildPins();
parent.filter();
if (parent == pe.part) {
peg.reloadPart();
parent.filter();
}
model.nodeStructureChanged(parent);
TreeNode[] nodePath = parent.child(nameBefore).getPath();
pet.updateOrder(nodePath);
pet.updateVisibility(nodePath);
pet.animate();
if (parent != pe.part) {
peg.updatePins();
peg.reconnect();
peg.repaint();
}
if (// root node, so update categories in search list
parent.getTrueParent() == null) {
PanelModel.instance.panelSearch.search();
}
}
use of gov.sandia.n2a.ui.eq.FilteredTreeModel in project n2a by frothga.
the class Outsource method apply.
public void apply(MNode subtree) {
// Retrieve created node
NodePart node = (NodePart) NodeBase.locateNode(path);
if (node == null)
throw new CannotRedoException();
PanelEquationTree pet = node.getTree();
FilteredTreeModel model = (FilteredTreeModel) pet.tree.getModel();
// Update database
// remove all children
node.source.clear();
node.source.merge(subtree);
// Update GUI
node.build();
node.findConnections();
node.rebuildPins();
node.filter();
// The caller of this Undoable promises to only use it on top-level nodes.
// Thus, node retains exactly the same visibility as before, so no need for full update.
// There are some obscure cases in which this doesn't hold (node was inherited, and the
// new value of $inherit matches the inherited value of node.$inherit, so node ceases to be top-level),
// but we won't worry about that.
model.nodeStructureChanged(node);
if (node.graph == null) {
TreePath nodePath = new TreePath(node.getPath());
pet.tree.setSelectionPath(nodePath);
if (wasExpanded)
pet.tree.expandPath(nodePath);
} else {
PanelEquations pe = PanelModel.instance.panelEquations;
if (pe.view == PanelEquations.NODE)
node.graph.setOpen(wasExpanded);
node.graph.takeFocusOnTitle();
// Because changes to inherit can change how a part's title is displayed.
node.graph.updateTitle();
}
pet.animate();
// Not necessary to update the graph, since exactly the same connections exist.
// findConnections() would merely re-establish them.
}
use of gov.sandia.n2a.ui.eq.FilteredTreeModel in project n2a by frothga.
the class AddPart method destroy.
public static void destroy(List<String> path, boolean canceled, String name, boolean setSelected, boolean multiShared, boolean touchesPin) {
// Retrieve created node
NodePart parent = (NodePart) NodeBase.locateNode(path);
if (parent == null)
throw new CannotUndoException();
NodePart createdNode = (NodePart) parent.child(name);
PanelEquations pe = PanelModel.instance.panelEquations;
boolean graphParent = parent == pe.part;
// Only use tree if it is not the graph parent, since graph parent hides its sub-parts.
PanelEquationTree pet = graphParent ? null : parent.getTree();
FilteredTreeModel model = null;
if (pet != null)
model = (FilteredTreeModel) pet.tree.getModel();
// only used if graphParent is true
PanelEquationGraph peg = pe.panelEquationGraph;
TreeNode[] createdPath = createdNode.getPath();
// returns -1 if createdNode is filtered out of parent
int index = parent.getIndexFiltered(createdNode);
if (canceled)
index--;
MPart mparent = parent.source;
mparent.clear(name);
if (// Node is fully deleted
mparent.child(name) == null) {
pe.deleteFocus(createdNode);
if (model == null)
FilteredTreeModel.removeNodeFromParentStatic(createdNode);
else
model.removeNodeFromParent(createdNode);
if (graphParent)
peg.removePart(createdNode, setSelected && !multiShared);
parent.findConnections();
parent.updatePins();
} else // Just exposed an overridden node
{
// Does not change the fake-root status of this node.
createdNode.build();
parent.findConnections();
createdNode.rebuildPins();
createdNode.filter();
if (// Need to update entire model under fake root.
graphParent) {
PanelEquationTree subpet = createdNode.getTree();
if (subpet != null) {
FilteredTreeModel submodel = (FilteredTreeModel) subpet.tree.getModel();
submodel.nodeStructureChanged(createdNode);
subpet.animate();
}
// Implicitly, the title of the node was focused when the part was deleted, so ensure it gets the focus back.
if (setSelected && !multiShared)
createdNode.graph.takeFocusOnTitle();
}
}
pe.resetBreadcrumbs();
if (pet == null) {
PanelEquationTree.updateOrder(null, createdPath);
PanelEquationTree.updateVisibility(null, createdPath, index, false);
} else {
pet.updateOrder(createdPath);
// includes nodeStructureChanged(), if necessary
pet.updateVisibility(createdPath, index, setSelected);
pet.animate();
}
if (graphParent || touchesPin) {
peg.updatePins();
peg.reconnect();
peg.repaint();
}
if (graphParent) {
if (pe.view == PanelEquations.NODE && peg.isEmpty())
pe.panelParent.setOpen(true);
if (setSelected && multiShared)
pe.switchFocus(false, false);
}
}
Aggregations