package net.sf.openrocket.gui.dialogs.optimization; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.util.Enumeration; import java.util.List; import java.util.Map; import javax.swing.JTree; import javax.swing.ToolTipManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import net.sf.openrocket.gui.components.BasicTree; import net.sf.openrocket.gui.main.ComponentIcons; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.TextUtil; /** * A tree that displays the simulation modifiers in a tree structure. * <p> * All nodes in the model are instances of DefaultMutableTreeNode. The user objects * within are either of type RocketComponent, String or SimulationModifier. * * @author Sampo Niskanen <sampo.niskanen@iki.fi> */ public class SimulationModifierTree extends BasicTree { private final List<SimulationModifier> selectedModifiers; private static final Translator trans = Application.getTranslator(); /** * Sole constructor. * * @param rocket the rocket. * @param simulationModifiers the simulation modifiers, ordered and mapped by components * @param selectedModifiers a list of the currently selected modifiers (may be modified). */ public SimulationModifierTree(Rocket rocket, Map<Object, List<SimulationModifier>> simulationModifiers, List<SimulationModifier> selectedModifiers) { this.selectedModifiers = selectedModifiers; populateTree(rocket, simulationModifiers); this.setCellRenderer(new ComponentModifierTreeRenderer()); // Enable tooltips for this component ToolTipManager.sharedInstance().registerComponent(this); expandComponents(); } /** * Populate the simulation modifier tree from the provided information. This can be used to update * the tree. */ public void populateTree(Rocket rocket, Map<Object, List<SimulationModifier>> simulationModifiers) { DefaultMutableTreeNode baseNode = new DefaultMutableTreeNode(rocket); populateTree(baseNode, rocket, simulationModifiers); this.setModel(new DefaultTreeModel(baseNode)); } private static void populateTree(DefaultMutableTreeNode node, RocketComponent component, Map<Object, List<SimulationModifier>> simulationModifiers) { // Add modifiers (if any) List<SimulationModifier> modifiers = simulationModifiers.get(component); if (modifiers != null) { DefaultMutableTreeNode modifierNode; if (component.getChildCount() > 0) { modifierNode = new DefaultMutableTreeNode(trans.get("SimulationModifierTree.OptimizationParameters")); node.add(modifierNode); } else { modifierNode = node; } for (SimulationModifier m : modifiers) { modifierNode.add(new DefaultMutableTreeNode(m)); } } // Add child components for (RocketComponent c : component.getChildren()) { DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(c); node.add(newNode); populateTree(newNode, c, simulationModifiers); } } /** * Expand the rocket components, but not the modifiers. */ @SuppressWarnings("rawtypes") public void expandComponents() { DefaultMutableTreeNode baseNode = (DefaultMutableTreeNode) this.getModel().getRoot(); Enumeration enumeration = baseNode.breadthFirstEnumeration(); while (enumeration.hasMoreElements()) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement(); Object object = node.getUserObject(); if (object instanceof RocketComponent) { this.makeVisible(new TreePath(node.getPath())); } } } public class ComponentModifierTreeRenderer extends DefaultTreeCellRenderer { private Font componentFont; private Font stringFont; private Font modifierFont; @Override public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus2) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus2); if (componentFont == null) { makeFonts(); } // Customize based on line type Object object = ((DefaultMutableTreeNode) value).getUserObject(); // Set icon (for rocket components, null for others) setIcon(ComponentIcons.getSmallIcon(object.getClass())); // Set text color/style if (object instanceof RocketComponent) { setForeground(Color.GRAY); setFont(componentFont); // Set tooltip RocketComponent c = (RocketComponent) object; String comment = c.getComment().trim(); if (comment.length() > 0) { comment = TextUtil.escapeXML(comment); comment = "<html>" + comment.replace("\n", "<br>"); this.setToolTipText(comment); } else { this.setToolTipText(null); } } else if (object instanceof String) { setForeground(Color.GRAY); setFont(stringFont); } else if (object instanceof SimulationModifier) { if (selectedModifiers.contains(object)) { setForeground(Color.GRAY); } else { setForeground(Color.BLACK); } setFont(modifierFont); setText(((SimulationModifier) object).getName()); setToolTipText(((SimulationModifier) object).getDescription()); } return this; } private void makeFonts() { Font font = getFont(); componentFont = font.deriveFont(Font.ITALIC); stringFont = font; modifierFont = font.deriveFont(Font.BOLD); } } }