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;
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, List<RocketComponent> stages) {
62 Vector root = new Vector();
63 Vector toAddTo = root;
66 if (stages.size() > 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()));
79 List<OpenRocketPrintable> unstaged = OpenRocketPrintable.getUnstaged();
80 for (int i = 0; i < unstaged.size(); i++) {
81 toAddTo.add(new CheckBoxNode(unstaged.get(i).getDescription(),
82 INITIAL_CHECKBOX_SELECTED));
85 RocketPrintTree tree = new RocketPrintTree(root);
87 tree.addTreeWillExpandListener
88 (new TreeWillExpandListener() {
90 public void treeWillExpand(TreeExpansionEvent e) {
94 public void treeWillCollapse(TreeExpansionEvent e)
95 throws ExpandVetoException {
96 throw new ExpandVetoException(e, "you can't collapse this JTree");
104 * Factory method to create a specialized JTree. This version is for a rocket with only one stage.
106 * @param rocketName the name of the rocket
108 * @return an instance of JTree
110 public static RocketPrintTree create(String rocketName) {
111 Vector root = new Vector();
112 root.add(new NamedVector(rocketName != null ? rocketName : "Rocket", createPrintTreeNode(false)));
114 RocketPrintTree tree = new RocketPrintTree(root);
116 tree.addTreeWillExpandListener
117 (new TreeWillExpandListener() {
119 public void treeWillExpand(TreeExpansionEvent e) {
123 public void treeWillCollapse(TreeExpansionEvent e)
124 throws ExpandVetoException {
125 throw new ExpandVetoException(e, "you can't collapse this JTree");
133 * This tree needs to have access both to the normal selection model (for the textual row) which is managed by the
134 * superclass, as well as the selection model for the check boxes. This mutator method allows an external class to
135 * set the model back onto this class. Because of some unfortunate circular dependencies this cannot be set at
138 * TODO: Ensure these circular references get cleaned up properly at dialog disposal so everything can be GC'd.
140 * @param checkBoxSelectionModel the selection model used to keep track of the check box state
142 public void setCheckBoxSelectionModel(TreeSelectionModel checkBoxSelectionModel) {
143 theCheckBoxSelectionModel = checkBoxSelectionModel;
147 * Add a selection path to the internal check box selection model. The normal JTree selection model is unaffected.
148 * This has the effect of "selecting" the check box, but not highlighting the row.
150 * @param path the path (row)
153 public void addSelectionPath(TreePath path) {
154 theCheckBoxSelectionModel.addSelectionPath(path);
158 * Helper to construct a named vector.
160 * @param name the name of the vector
161 * @param nodes the array of nodes to put into the vector
162 * @param stage the stage number
164 * @return a NamedVector suitable for adding to a JTree
166 private static Vector createNamedVector(String name, CheckBoxNode[] nodes, int stage) {
167 return new NamedVector(name, nodes, stage);
171 * Helper to construct the set of check box rows for each stage.
173 * @param onlyStageSpecific if true then only stage specific OpenRocketPrintable rows are represented (in this part
176 * @return an array of CheckBoxNode
178 private static CheckBoxNode[] createPrintTreeNode(boolean onlyStageSpecific) {
179 List<CheckBoxNode> nodes = new ArrayList<CheckBoxNode>();
180 OpenRocketPrintable[] printables = OpenRocketPrintable.values();
181 for (OpenRocketPrintable openRocketPrintable : printables) {
182 if (!onlyStageSpecific || openRocketPrintable.isStageSpecific()) {
183 nodes.add(new CheckBoxNode(openRocketPrintable.getDescription(),
184 INITIAL_CHECKBOX_SELECTED));
187 return nodes.toArray(new CheckBoxNode[nodes.size()]);
191 * Get the set of items to be printed, as selected by the user.
193 * @return the things to be printed, returned as an Iterator<PrintableContext>
195 public Iterator<PrintableContext> getToBePrinted() {
196 final DefaultMutableTreeNode mutableTreeNode = (DefaultMutableTreeNode) getModel().getRoot();
197 PrintableContext pc = new PrintableContext();
198 add(pc, mutableTreeNode);
199 return pc.iterator();
203 * Walk a tree, finding everything that has been selected and aggregating it into something that can be iterated upon
204 * This method is recursive.
206 * @param pc the printable context that aggregates the choices into an iterator
207 * @param theMutableTreeNode the root node
209 private void add(final PrintableContext pc, final DefaultMutableTreeNode theMutableTreeNode) {
210 int children = theMutableTreeNode.getChildCount();
211 for (int x = 0; x < children; x++) {
213 final DefaultMutableTreeNode at = (DefaultMutableTreeNode) theMutableTreeNode.getChildAt(x);
214 if (at.getUserObject() instanceof CheckBoxNode) {
215 CheckBoxNode cbn = (CheckBoxNode) at.getUserObject();
216 if (cbn.isSelected()) {
217 final OpenRocketPrintable printable = OpenRocketPrintable.findByDescription(cbn.getText());
219 printable.isStageSpecific() ? ((NamedVector) theMutableTreeNode.getUserObject())
231 * JTree's work off of Vector's (unfortunately). This class is tailored for use with check boxes in the JTree.
233 class NamedVector extends Vector<CheckBoxNode> {
238 public NamedVector(String theName) {
242 public NamedVector(String theName, CheckBoxNode elements[], int stage) {
243 this(theName, elements);
247 public NamedVector(String theName, CheckBoxNode elements[]) {
249 for (int i = 0, n = elements.length; i < n; i++) {
255 public String toString() {
259 public int getStage() {