4 package net.sf.openrocket.gui.print.components;
6 import net.sf.openrocket.gui.print.OpenRocketPrintable;
7 import net.sf.openrocket.gui.print.PrintableContext;
8 import net.sf.openrocket.rocketcomponent.RocketComponent;
9 import net.sf.openrocket.rocketcomponent.Stage;
11 import javax.swing.JTree;
12 import javax.swing.event.TreeExpansionEvent;
13 import javax.swing.event.TreeWillExpandListener;
14 import javax.swing.tree.DefaultMutableTreeNode;
15 import javax.swing.tree.ExpandVetoException;
16 import javax.swing.tree.TreePath;
17 import javax.swing.tree.TreeSelectionModel;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Vector;
24 * A specialized JTree for displaying various rocket items that can be printed.
26 public class RocketPrintTree extends JTree {
29 * All check boxes are initially set to true (selected).
31 public static final boolean INITIAL_CHECKBOX_SELECTED = true;
34 * The selection model that tracks the check box state.
36 private TreeSelectionModel theCheckBoxSelectionModel;
41 * @param root the vector of check box nodes (rows) to place into the tree
43 private RocketPrintTree (Vector root) {
46 //Remove the little down and sideways arrows. These are not needed because the tree expansion is fixed.
47 ((javax.swing.plaf.basic.BasicTreeUI) this.getUI()).
48 setExpandedIcon(null);
49 ((javax.swing.plaf.basic.BasicTreeUI) this.getUI()).
50 setCollapsedIcon(null);
54 * Factory method to create a specialized JTree. This version is for rocket's that have more than one stage.
56 * @param rocketName the name of the rocket
57 * @param stages the array of all stages
59 * @return an instance of JTree
61 public static RocketPrintTree create (String rocketName, RocketComponent[] stages) {
62 Vector root = new Vector();
63 Vector toAddTo = root;
66 if (stages.length > 1) {
67 final Vector parent = new NamedVector(rocketName != null ? rocketName : "Rocket");
72 for (RocketComponent stage : stages) {
73 if (stage instanceof Stage) {
74 toAddTo.add(createNamedVector(stage.getName(), createPrintTreeNode(true), stage.getStageNumber()));
78 toAddTo.add(new CheckBoxNode(OpenRocketPrintable.DESIGN_REPORT.getDescription(),
79 INITIAL_CHECKBOX_SELECTED));
81 RocketPrintTree tree = new RocketPrintTree(root);
83 tree.addTreeWillExpandListener
84 (new TreeWillExpandListener() {
85 public void treeWillExpand (TreeExpansionEvent e) {
88 public void treeWillCollapse (TreeExpansionEvent e)
89 throws ExpandVetoException {
90 throw new ExpandVetoException(e, "you can't collapse this JTree");
98 * Factory method to create a specialized JTree. This version is for a rocket with only one stage.
100 * @param rocketName the name of the rocket
102 * @return an instance of JTree
104 public static RocketPrintTree create (String rocketName) {
105 Vector root = new Vector();
106 root.add(new NamedVector(rocketName != null ? rocketName : "Rocket", createPrintTreeNode(false)));
108 RocketPrintTree tree = new RocketPrintTree(root);
110 tree.addTreeWillExpandListener
111 (new TreeWillExpandListener() {
112 public void treeWillExpand (TreeExpansionEvent e) {
115 public void treeWillCollapse (TreeExpansionEvent e)
116 throws ExpandVetoException {
117 throw new ExpandVetoException(e, "you can't collapse this JTree");
125 * This tree needs to have access both to the normal selection model (for the textual row) which is managed by the
126 * superclass, as well as the selection model for the check boxes. This mutator method allows an external class to
127 * set the model back onto this class. Because of some unfortunate circular dependencies this cannot be set at
130 * TODO: Ensure these circular references get cleaned up properly at dialog disposal so everything can be GC'd.
132 * @param checkBoxSelectionModel the selection model used to keep track of the check box state
134 public void setCheckBoxSelectionModel (TreeSelectionModel checkBoxSelectionModel) {
135 theCheckBoxSelectionModel = checkBoxSelectionModel;
139 * Add a selection path to the internal check box selection model. The normal JTree selection model is unaffected.
140 * This has the effect of "selecting" the check box, but not highlighting the row.
142 * @param path the path (row)
144 public void addSelectionPath (TreePath path) {
145 theCheckBoxSelectionModel.addSelectionPath(path);
149 * Helper to construct a named vector.
151 * @param name the name of the vector
152 * @param nodes the array of nodes to put into the vector
153 * @param stage the stage number
155 * @return a NamedVector suitable for adding to a JTree
157 private static Vector createNamedVector (String name, CheckBoxNode[] nodes, int stage) {
158 return new NamedVector(name, nodes, stage);
162 * Helper to construct the set of check box rows for each stage.
164 * @param onlyStageSpecific if true then only stage specific OpenRocketPrintable rows are represented (in this part
167 * @return an array of CheckBoxNode
169 private static CheckBoxNode[] createPrintTreeNode (boolean onlyStageSpecific) {
170 List<CheckBoxNode> nodes = new ArrayList<CheckBoxNode>();
171 OpenRocketPrintable[] printables = OpenRocketPrintable.values();
172 for (OpenRocketPrintable openRocketPrintable : printables) {
173 if (!onlyStageSpecific || openRocketPrintable.isStageSpecific() ) {
174 nodes.add(new CheckBoxNode(openRocketPrintable.getDescription(),
175 INITIAL_CHECKBOX_SELECTED));
178 return nodes.toArray(new CheckBoxNode[nodes.size()]);
182 * Get the set of items to be printed, as selected by the user.
184 * @return the things to be printed, returned as an Iterator<PrintableContext>
186 public Iterator<PrintableContext> getToBePrinted () {
187 final DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) getModel().getRoot();
188 PrintableContext pc = new PrintableContext();
189 add(pc, mutableTreeNode);
190 return pc.iterator();
194 * Walk a tree, finding everything that has been selected and aggregating it into something that can be iterated upon
195 * This method is recursive.
197 * @param pc the printable context that aggregates the choices into an iterator
198 * @param theMutableTreeNode the root node
200 private void add (final PrintableContext pc, final DefaultMutableTreeNode theMutableTreeNode) {
201 int children = theMutableTreeNode.getChildCount();
202 for (int x = 0; x < children; x++) {
204 final DefaultMutableTreeNode at = (DefaultMutableTreeNode) theMutableTreeNode.getChildAt(x);
205 if (at.getUserObject() instanceof CheckBoxNode) {
206 CheckBoxNode cbn = (CheckBoxNode) at.getUserObject();
207 if (cbn.isSelected()) {
208 final OpenRocketPrintable printable = OpenRocketPrintable.findByDescription(cbn.getText());
210 printable.isStageSpecific() ? ((NamedVector) theMutableTreeNode.getUserObject())
222 * JTree's work off of Vector's (unfortunately). This class is tailored for use with check boxes in the JTree.
224 class NamedVector extends Vector<CheckBoxNode> {
229 public NamedVector (String theName) {
233 public NamedVector (String theName, CheckBoxNode elements[], int stage) {
234 this(theName, elements);
238 public NamedVector (String theName, CheckBoxNode elements[]) {
240 for (int i = 0, n = elements.length; i < n; i++) {
245 public String toString () {
249 public int getStage () {