b250abef7244050a30bddefef6b5cea1f1113540
[debian/openrocket] / src / net / sf / openrocket / gui / print / components / RocketPrintTree.java
1 /*
2  * RocketPrintTree.java
3  */
4 package net.sf.openrocket.gui.print.components;
5
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;
10
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;
22
23 /**
24  * A specialized JTree for displaying various rocket items that can be printed.
25  */
26 public class RocketPrintTree extends JTree {
27
28     /**
29      * All check boxes are initially set to true (selected).
30      */
31     public static final boolean INITIAL_CHECKBOX_SELECTED = true;
32
33     /**
34      * The selection model that tracks the check box state.
35      */
36     private TreeSelectionModel theCheckBoxSelectionModel;
37
38     /**
39      * Constructor.
40      *
41      * @param root the vector of check box nodes (rows) to place into the tree
42      */
43     private RocketPrintTree (Vector root) {
44         super(root);
45
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);
51     }
52
53     /**
54      * Factory method to create a specialized JTree.  This version is for rocket's that have more than one stage.
55      *
56      * @param rocketName the name of the rocket
57      * @param stages     the array of all stages
58      *
59      * @return an instance of JTree
60      */
61     public static RocketPrintTree create (String rocketName, RocketComponent[] stages) {
62         Vector root = new Vector();
63         Vector toAddTo = root;
64
65         if (stages != null) {
66             if (stages.length > 1) {
67                 final Vector parent = new NamedVector(rocketName != null ? rocketName : "Rocket");
68
69                 root.add(parent);
70                 toAddTo = parent;
71             }
72             for (RocketComponent stage : stages) {
73                 if (stage instanceof Stage) {
74                     toAddTo.add(createNamedVector(stage.getName(), createPrintTreeNode(true), stage.getStageNumber()));
75                 }
76             }
77         }
78         toAddTo.add(new CheckBoxNode(OpenRocketPrintable.DESIGN_REPORT.getDescription(),
79                                      INITIAL_CHECKBOX_SELECTED));
80
81         RocketPrintTree tree = new RocketPrintTree(root);
82
83         tree.addTreeWillExpandListener
84                 (new TreeWillExpandListener() {
85                     public void treeWillExpand (TreeExpansionEvent e) {
86                     }
87
88                     public void treeWillCollapse (TreeExpansionEvent e)
89                             throws ExpandVetoException {
90                         throw new ExpandVetoException(e, "you can't collapse this JTree");
91                     }
92                 });
93
94         return tree;
95     }
96
97     /**
98      * Factory method to create a specialized JTree.  This version is for a rocket with only one stage.
99      *
100      * @param rocketName the name of the rocket
101      *
102      * @return an instance of JTree
103      */
104     public static RocketPrintTree create (String rocketName) {
105         Vector root = new Vector();
106         root.add(new NamedVector(rocketName != null ? rocketName : "Rocket", createPrintTreeNode(false)));
107
108         RocketPrintTree tree = new RocketPrintTree(root);
109
110         tree.addTreeWillExpandListener
111                 (new TreeWillExpandListener() {
112                     public void treeWillExpand (TreeExpansionEvent e) {
113                     }
114
115                     public void treeWillCollapse (TreeExpansionEvent e)
116                             throws ExpandVetoException {
117                         throw new ExpandVetoException(e, "you can't collapse this JTree");
118                     }
119                 });
120
121         return tree;
122     }
123
124     /**
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
128      * construction.
129      * <p/>
130      * TODO: Ensure these circular references get cleaned up properly at dialog disposal so everything can be GC'd.
131      *
132      * @param checkBoxSelectionModel the selection model used to keep track of the check box state
133      */
134     public void setCheckBoxSelectionModel (TreeSelectionModel checkBoxSelectionModel) {
135         theCheckBoxSelectionModel = checkBoxSelectionModel;
136     }
137
138     /**
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.
141      *
142      * @param path the path (row)
143      */
144     public void addSelectionPath (TreePath path) {
145         theCheckBoxSelectionModel.addSelectionPath(path);
146     }
147
148     /**
149      * Helper to construct a named vector.
150      *
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
154      *
155      * @return a NamedVector suitable for adding to a JTree
156      */
157     private static Vector createNamedVector (String name, CheckBoxNode[] nodes, int stage) {
158         return new NamedVector(name, nodes, stage);
159     }
160
161     /**
162      * Helper to construct the set of check box rows for each stage.
163      *
164      * @param onlyStageSpecific  if true then only stage specific OpenRocketPrintable rows are represented (in this part 
165      * of the tree).
166      * 
167      * @return an array of CheckBoxNode
168      */
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));
176             }
177         }
178         return nodes.toArray(new CheckBoxNode[nodes.size()]);
179     }
180
181     /**
182      * Get the set of items to be printed, as selected by the user.
183      * 
184      * @return the things to be printed, returned as an Iterator<PrintableContext>
185      */
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();
191     }
192
193     /**
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.
196      * 
197      * @param pc                  the printable context that aggregates the choices into an iterator
198      * @param theMutableTreeNode  the root node
199      */
200     private void add (final PrintableContext pc, final DefaultMutableTreeNode theMutableTreeNode) {
201         int children = theMutableTreeNode.getChildCount();
202         for (int x = 0; x < children; x++) {
203
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());
209                     pc.add(
210                             printable.isStageSpecific() ? ((NamedVector) theMutableTreeNode.getUserObject())
211                                     .getStage() : null,
212                             printable);
213                 }
214             }
215             add(pc, at);
216         }
217     }
218
219 }
220
221 /**
222  * JTree's work off of Vector's (unfortunately).  This class is tailored for use with check boxes in the JTree.
223  */
224 class NamedVector extends Vector<CheckBoxNode> {
225     String name;
226
227     int stageNumber;
228
229     public NamedVector (String theName) {
230         name = theName;
231     }
232
233     public NamedVector (String theName, CheckBoxNode elements[], int stage) {
234         this(theName, elements);
235         stageNumber = stage;
236     }
237
238     public NamedVector (String theName, CheckBoxNode elements[]) {
239         name = theName;
240         for (int i = 0, n = elements.length; i < n; i++) {
241             add(elements[i]);
242         }
243     }
244
245     public String toString () {
246         return name;
247     }
248
249     public int getStage () {
250         return stageNumber;
251     }
252 }