/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.gui.main;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import javax.swing.tree.TreeNode;
import com.cburch.logisim.circuit.CircuitAttributes;
import com.cburch.logisim.circuit.CircuitEvent;
import com.cburch.logisim.circuit.CircuitListener;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.circuit.SubcircuitFactory;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.data.AttributeEvent;
import com.cburch.logisim.data.AttributeListener;
import com.cburch.logisim.instance.StdAttr;
class SimulationTreeCircuitNode extends SimulationTreeNode implements
CircuitListener, AttributeListener, Comparator<Component> {
private static class CompareByName implements Comparator<Object> {
public int compare(Object a, Object b) {
return a.toString().compareToIgnoreCase(b.toString());
}
}
private SimulationTreeModel model;
private SimulationTreeCircuitNode parent;
private CircuitState circuitState;
private Component subcircComp;
private ArrayList<TreeNode> children;
public SimulationTreeCircuitNode(SimulationTreeModel model,
SimulationTreeCircuitNode parent, CircuitState circuitState,
Component subcircComp) {
this.model = model;
this.parent = parent;
this.circuitState = circuitState;
this.subcircComp = subcircComp;
this.children = new ArrayList<TreeNode>();
circuitState.getCircuit().addCircuitListener(this);
if (subcircComp != null) {
subcircComp.getAttributeSet().addAttributeListener(this);
} else {
circuitState.getCircuit().getStaticAttributes()
.addAttributeListener(this);
}
computeChildren();
}
//
// AttributeListener methods
public void attributeListChanged(AttributeEvent e) {
}
public void attributeValueChanged(AttributeEvent e) {
Object attr = e.getAttribute();
if (attr == CircuitAttributes.CIRCUIT_LABEL_ATTR
|| attr == StdAttr.LABEL) {
model.fireNodeChanged(this);
}
}
@Override
public Enumeration<TreeNode> children() {
return Collections.enumeration(children);
}
public void circuitChanged(CircuitEvent event) {
int action = event.getAction();
if (action == CircuitEvent.ACTION_SET_NAME) {
model.fireNodeChanged(this);
} else {
if (computeChildren()) {
model.fireStructureChanged(this);
}
}
}
public int compare(Component a, Component b) {
if (a != b) {
String aName = a.getFactory().getDisplayName();
String bName = b.getFactory().getDisplayName();
int ret = aName.compareToIgnoreCase(bName);
if (ret != 0)
return ret;
}
return a.getLocation().toString().compareTo(b.getLocation().toString());
}
// returns true if changed
private boolean computeChildren() {
ArrayList<TreeNode> newChildren = new ArrayList<TreeNode>();
ArrayList<Component> subcircs = new ArrayList<Component>();
for (Component comp : circuitState.getCircuit().getNonWires()) {
if (comp.getFactory() instanceof SubcircuitFactory) {
subcircs.add(comp);
} else {
TreeNode toAdd = model.mapComponentToNode(comp);
if (toAdd != null) {
newChildren.add(toAdd);
}
}
}
Collections.sort(newChildren, new CompareByName());
Collections.sort(subcircs, this);
for (Component comp : subcircs) {
SubcircuitFactory factory = (SubcircuitFactory) comp.getFactory();
CircuitState state = factory.getSubstate(circuitState, comp);
SimulationTreeCircuitNode toAdd = null;
for (TreeNode o : children) {
if (o instanceof SimulationTreeCircuitNode) {
SimulationTreeCircuitNode n = (SimulationTreeCircuitNode) o;
if (n.circuitState == state) {
toAdd = n;
break;
}
}
}
if (toAdd == null) {
toAdd = new SimulationTreeCircuitNode(model, this, state, comp);
}
newChildren.add(toAdd);
}
if (!children.equals(newChildren)) {
children = newChildren;
return true;
} else {
return false;
}
}
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public TreeNode getChildAt(int index) {
return children.get(index);
}
@Override
public int getChildCount() {
return children.size();
}
public CircuitState getCircuitState() {
return circuitState;
}
@Override
public ComponentFactory getComponentFactory() {
return circuitState.getCircuit().getSubcircuitFactory();
}
@Override
public int getIndex(TreeNode node) {
return children.indexOf(node);
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public boolean isCurrentView(SimulationTreeModel model) {
return model.getCurrentView() == circuitState;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public String toString() {
if (subcircComp != null) {
String label = subcircComp.getAttributeSet()
.getValue(StdAttr.LABEL);
if (label != null && !label.equals("")) {
return label;
}
}
String ret = circuitState.getCircuit().getName();
if (subcircComp != null) {
ret += subcircComp.getLocation();
}
return ret;
}
}