View Javadoc

1   // Copyright 2004-2005, FreeHEP.
2   package hep.wired.heprep.tree;
3   
4   import java.awt.*;
5   import java.awt.event.*;
6   import java.beans.*;
7   import java.util.*;
8   import java.util.List;
9   import javax.swing.*;
10  import javax.swing.event.*;
11  import javax.swing.tree.*;
12  
13  import org.freehep.swing.layout.TableLayout;
14  import org.freehep.swing.popup.HasPopupItems;
15  
16  import hep.graphics.heprep.HepRep;
17  import hep.graphics.heprep.HepRepType;
18  import hep.graphics.heprep.HepRepTypeTree;
19  
20  import hep.wired.image.WiredBaseImage;
21  import hep.wired.plot.WiredPlot;
22  import hep.wired.services.GraphicsPanel;
23  import hep.wired.util.JTristateTree;
24  import hep.wired.util.TristateTreeCellEditor;
25  import hep.wired.util.TristateTreeNode;
26  
27  import hep.wired.heprep.graphicspanel.HepRepPanel;
28  import hep.wired.heprep.graphicspanel.ControlPanel;
29  import hep.wired.heprep.util.WiredHepRepUtil;
30  
31  /***
32   * TreePanel.
33   *
34   * @author Mark Donszelmann
35   * @version $Id: TreePanel.java 2115 2005-07-25 05:33:47Z duns $
36   */
37  public class TreePanel extends ControlPanel {
38  
39      private TreePanelModel panelModel;
40  
41      private TypeTristateTreeModel typeModel;
42      private TypeTreeCellRenderer typeTreeCellRenderer, typeTreeCellEditor;
43      private JTree typeTree;
44      
45      private JCheckBox applyImmediately;
46      private JButton apply;
47      
48      private JCheckBox hide;
49      private JSpinner hideLevel;
50  
51      private ButtonModel dummyApplyImmediatelyModel, dummyApplyModel, dummyHideModel;
52      private SpinnerModel dummyHideLevelModel;
53      private TreeCellRenderer dummyCellRenderer;
54      private TreeCellEditor dummyCellEditor;
55   
56      interface PathListener {
57          public void doAction(JTree tree, TreePath path);
58      }        
59          
60      class JTypeTree extends JTristateTree implements HasPopupItems {
61          public JTypeTree(TypeTristateTreeModel model) {
62              super(model);
63          }            
64          
65                  
66          private void doForPath(JTree tree, TreePath path, PathListener listener) {
67              // Traverse children
68              TreeNode node = (TreeNode)path.getLastPathComponent();
69              if (node.getChildCount() >= 0) {
70                  for (Enumeration e=node.children(); e.hasMoreElements(); ) {
71                      TreeNode n = (TreeNode)e.nextElement();
72                      TreePath childPath = path.pathByAddingChild(n);
73                      doForPath(tree, childPath, listener);
74                  }
75              }
76          
77              // action must be done bottom-up
78              listener.doAction(tree, path);
79          }
80          
81          public JPopupMenu modifyPopupMenu(JPopupMenu menu, Component source, Point p) {
82              final TreePath path = getClosestPathForLocation(p.x, p.y);
83              if (getPathBounds(path) == null) return menu;
84              
85              if (getPathBounds(path).contains(p)) {
86                  
87                  //This is to reproduce the Windows behaviour: if right click is on a selected node
88                  //the selection does not change, otherwise the selected path is the only one being
89                  //selected.
90                  if ( ! isPathSelected(path) ) {
91                      removeSelectionPaths( getSelectionPaths() );
92                      addSelectionPath(path);
93                  }
94  
95                  menu.add(new JMenuItem("Expand all")).addActionListener(new ActionListener() {
96                      public void actionPerformed(ActionEvent e) {
97                          doForPath(typeTree, path, new PathListener() {
98                              public void doAction(JTree tree, TreePath path) {
99                                  tree.expandPath(path);
100                             }                        
101                         });    
102                     }
103                 });          
104 
105                 menu.add(new JMenuItem("Collapse all")).addActionListener(new ActionListener() {
106                     public void actionPerformed(ActionEvent e) {
107                         doForPath(typeTree, path, new PathListener() {
108                             public void doAction(JTree tree, TreePath path) {
109                                 tree.collapsePath(path);
110                             }                        
111                         });    
112                     }
113                 });          
114 
115                 menu.addSeparator();
116                 
117                 menu.add(new JMenuItem("Show all")).addActionListener(new ActionListener() {
118                     public void actionPerformed(ActionEvent e) {
119                         doForPath(typeTree, path, new PathListener() {
120                             public void doAction(JTree tree, TreePath path) {
121                                 Object object = path.getLastPathComponent();
122                                 if (object instanceof TristateTreeNode) {
123                                     TristateTreeNode node = (TristateTreeNode)object;
124                                     node.include(true);                                    
125                                     node.select(true);                                    
126                                 }
127                             }                        
128                         });
129                         typeModel.treeNodesChanged(new TreeModelEvent(typeModel, path.getParentPath()));    
130                         panelModel.fireChangeEvent(false);
131                     }
132                 });          
133 
134                 menu.add(new JMenuItem("Hide all")).addActionListener(new ActionListener() {
135                     public void actionPerformed(ActionEvent e) {
136                         doForPath(typeTree, path, new PathListener() {
137                             public void doAction(JTree tree, TreePath path) {
138                                 Object object = path.getLastPathComponent();
139                                 if (object instanceof TristateTreeNode) {
140                                     TristateTreeNode node = (TristateTreeNode)object;
141                                     node.include(false);                                    
142                                     node.select(false);                                    
143                                 }
144                             }                        
145                         });
146                         typeModel.treeNodesChanged(new TreeModelEvent(typeModel, path.getParentPath()));    
147                         panelModel.fireChangeEvent(false);
148                     }
149                 });          
150 
151                 menu.addSeparator();
152 
153                 menu.add(new JMenuItem("Invert all")).addActionListener(new ActionListener() {
154                     public void actionPerformed(ActionEvent e) {
155                         doForPath(typeTree, path, new PathListener() {
156                             public void doAction(JTree tree, TreePath path) {
157                                 Object object = path.getLastPathComponent();
158                                 if (object instanceof TristateTreeNode) {
159                                     TristateTreeNode node = (TristateTreeNode)object;
160                                     node.include(!node.isIncluded());                                    
161                                     node.select(!node.isSelected());                                    
162                                 }
163                             }                        
164                         });
165                         typeModel.treeNodesChanged(new TreeModelEvent(typeModel, path.getParentPath()));    
166                         panelModel.fireChangeEvent(false);
167                     }
168                 });          
169 
170             }
171             return menu;
172         }        
173     }
174     
175     public TreePanel() {
176         super("Visibility Tree", "Set or Clear Visibility of Objects", WiredBaseImage.getIcon("Tree%w", 16), null);
177         setLayout(new TableLayout());
178 
179         typeModel = null;
180 
181         typeTree = new JTypeTree(typeModel);
182         
183         // Note, both TypeTreeCellRenderers need to be different instances.
184         typeTreeCellRenderer = new TypeTreeCellRenderer();
185         typeTree.setCellRenderer(typeTreeCellRenderer);
186         typeTreeCellEditor = new TypeTreeCellRenderer();
187         typeTree.setCellEditor(new TristateTreeCellEditor(typeTree, typeTreeCellEditor));
188 
189         dummyCellRenderer = typeTree.getCellRenderer();
190         dummyCellEditor = typeTree.getCellEditor();
191         
192         String insets = " [3 3 3 3] ";
193 
194         JScrollPane treeScrollPane = new JScrollPane(typeTree, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
195                                                                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
196         add(treeScrollPane, "0 1 2 1"+insets+"wh");
197         
198         applyImmediately = new JCheckBox("Apply immediately");
199         add(applyImmediately, "0 2"+insets+"w");
200         applyImmediately.addPropertyChangeListener("enabled", new PropertyChangeListener() {
201             public void propertyChange(PropertyChangeEvent event) {
202                 apply.setEnabled(applyImmediately.isEnabled() && !applyImmediately.isSelected());
203             }
204         });
205         applyImmediately.addActionListener(new ActionListener() {
206             public void actionPerformed(ActionEvent event) {
207                 apply.setEnabled(!applyImmediately.isSelected());
208             }
209         });
210         dummyApplyImmediatelyModel = applyImmediately.getModel();
211 
212         apply = new JButton("Apply");
213         add(apply, "1 2"+insets+"wr");
214         dummyApplyModel = apply.getModel();
215                 
216         hide = new JCheckBox("Hide below level: ");
217         add(hide, "0 3"+insets+"w");
218         hide.addActionListener(new ActionListener() {
219             public void actionPerformed(ActionEvent event) {
220                 hideLevel.setEnabled(hide.isSelected());
221                 if (panelModel != null) {
222                     int maxDepth = panelModel.getMaxDepth();
223                     typeTreeCellRenderer.setMaxDepth(maxDepth);
224                     typeTreeCellEditor.setMaxDepth(maxDepth);
225                 }
226             }
227         });
228         hide.addPropertyChangeListener("enabled", new PropertyChangeListener() {
229             public void propertyChange(PropertyChangeEvent event) {
230                 hideLevel.setEnabled(hide.isEnabled() && hide.isSelected());
231             }
232         });
233         dummyHideModel = hide.getModel();
234         
235         hideLevel = new JSpinner();
236         hideLevel.addChangeListener(new ChangeListener() {
237             public void stateChanged(ChangeEvent event) {
238                 if (panelModel != null) {
239                     int maxDepth = panelModel.getMaxDepth();
240                     typeTreeCellRenderer.setMaxDepth(maxDepth);
241                     typeTreeCellEditor.setMaxDepth(maxDepth);
242                 }
243             }
244         });
245         
246         add(hideLevel, "1 3"+insets+"wr");
247         hideLevel.setEnabled(false);
248         dummyHideLevelModel = hideLevel.getModel();        
249     }
250         
251     public void setTreeToPlot(WiredPlot plot) {
252         if (plot != null) {
253             GraphicsPanel panel = plot.getGraphicsPanel();
254             
255             if (!(panel instanceof HepRepPanel)) return;
256             
257             HepRepPanel heprepPanel = (HepRepPanel)panel;
258 
259             // normally not necessary...
260             if (panelModel != null) {
261                 panelModel.setExpandedTypeNames(WiredHepRepUtil.getExpandedState(typeModel, typeTree));
262             }
263             
264             panelModel = heprepPanel.getTreePanelModel();
265             
266             typeModel = panelModel.getTypeTreeModel();
267             typeTree.setModel(typeModel);
268             
269             applyImmediately.setModel(panelModel.getApplyImmediatelyModel());
270             apply.setModel(panelModel.getApplyModel());            
271             
272             hide.setModel(panelModel.getHideModel());            
273             hideLevel.setModel(panelModel.getHideLevelModel());
274 
275             int maxDepth = panelModel.getMaxDepth();
276             typeTreeCellRenderer.setMaxDepth(maxDepth);
277             typeTreeCellEditor.setMaxDepth(maxDepth);
278             
279             WiredHepRepUtil.setExpandedState(panelModel.getExpandedTypeNames(), typeModel, typeTree);
280 
281             setEnabled(true);            
282         } else {
283             if (panelModel != null) {
284                 panelModel.setExpandedTypeNames(WiredHepRepUtil.getExpandedState(typeModel, typeTree));
285             }
286  
287             panelModel = null;
288             typeModel = null;
289             typeTree.setModel(typeModel);
290             
291             // NOTE: set all fake models to loose pointers.
292             applyImmediately.setModel(dummyApplyImmediatelyModel);
293             apply.setModel(dummyApplyModel);
294             
295             hide.setModel(dummyHideModel);
296             hideLevel.setModel(dummyHideLevelModel);
297                         
298             setEnabled(false);
299         }
300     }
301     
302     public void setEnabled(boolean state) {
303         applyImmediately.setEnabled(state);
304         hide.setEnabled(state);          
305     }       
306 }