Initial commit
[debian/openrocket] / src / net / sf / openrocket / gui / main / BareComponentTreeModel.java
1 package net.sf.openrocket.gui.main;
2
3 import java.util.ArrayList;
4 import java.util.Enumeration;
5 import java.util.Iterator;
6
7 import javax.swing.JTree;
8 import javax.swing.event.TreeModelEvent;
9 import javax.swing.event.TreeModelListener;
10 import javax.swing.tree.TreeModel;
11 import javax.swing.tree.TreePath;
12
13 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
14 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
15 import net.sf.openrocket.rocketcomponent.RocketComponent;
16
17
18 /**
19  * A TreeModel that implements viewing of the rocket tree structure.
20  * This class shows the internal structure of the tree, as opposed to the regular
21  * user-side view.
22  * 
23  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
24  */
25
26 public class BareComponentTreeModel implements TreeModel, ComponentChangeListener {
27         ArrayList<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
28
29         private final RocketComponent root;
30         private final JTree tree;
31
32         public BareComponentTreeModel(RocketComponent root, JTree tree) {
33                 this.root = root;
34                 this.tree = tree;
35                 root.addComponentChangeListener(this);
36         }
37         
38         
39         public Object getChild(Object parent, int index) {
40                 RocketComponent component = (RocketComponent)parent;
41                 try {
42                         return component.getChild(index);
43                 } catch (IndexOutOfBoundsException e) {
44                         return null;
45                 }
46         }
47
48         public int getChildCount(Object parent) {
49                 return ((RocketComponent)parent).getChildCount();
50         }
51
52         public int getIndexOfChild(Object parent, Object child) {
53                 RocketComponent p = (RocketComponent)parent;
54                 RocketComponent c = (RocketComponent)child;
55                 return p.getChildPosition(c);
56         }
57
58         public Object getRoot() {
59                 return root;
60         }
61
62         public boolean isLeaf(Object node) {
63                 RocketComponent c = (RocketComponent)node;
64                 return (c.getChildCount()==0);
65         }
66
67         public void addTreeModelListener(TreeModelListener l) {
68                 listeners.add(l);
69         }
70
71         public void removeTreeModelListener(TreeModelListener l) {
72                 listeners.remove(l);
73         }
74         
75         private void fireTreeNodesChanged() {
76                 Object[] path = { root };
77                 TreeModelEvent e = new TreeModelEvent(this,path);
78                 Object[] l = listeners.toArray();
79                 for (int i=0; i<l.length; i++)
80                         ((TreeModelListener)l[i]).treeNodesChanged(e);
81         }
82         
83         
84         private void printStructure(TreePath p, int level) {
85                 String indent="";
86                 for (int i=0; i<level; i++)
87                         indent += "  ";
88                 System.out.println(indent+p+
89                                 ": isVisible:"+tree.isVisible(p)+
90                                 " isCollapsed:"+tree.isCollapsed(p)+
91                                 " isExpanded:"+tree.isExpanded(p));
92                 Object parent = p.getLastPathComponent();
93                 for (int i=0; i<getChildCount(parent); i++) {
94                         Object child = getChild(parent,i);
95                         TreePath path = makeTreePath((RocketComponent)child);
96                         printStructure(path,level+1);
97                 }
98         }
99         
100         
101         private void fireTreeStructureChanged(RocketComponent source) {
102                 Object[] path = { root };
103                 
104                 
105                 // Get currently expanded path IDs
106                 Enumeration<TreePath> enumer = tree.getExpandedDescendants(new TreePath(path));
107                 ArrayList<String> expanded = new ArrayList<String>();
108                 if (enumer != null) {
109                         while (enumer.hasMoreElements()) {
110                                 TreePath p = enumer.nextElement();
111                                 expanded.add(((RocketComponent)p.getLastPathComponent()).getID());
112                         }
113                 }
114                 
115                 // Send structure change event
116                 TreeModelEvent e = new TreeModelEvent(this,path);
117                 Object[] l = listeners.toArray();
118                 for (int i=0; i<l.length; i++)
119                         ((TreeModelListener)l[i]).treeStructureChanged(e);
120                 
121                 // Re-expand the paths
122                 Iterator<String> iter = expanded.iterator();
123                 while (iter.hasNext()) {
124                         RocketComponent c = root.findComponent(iter.next());
125                         if (c==null)
126                                 continue;
127                         tree.expandPath(makeTreePath(c));
128                 }
129                 if (source != null) {
130                         TreePath p = makeTreePath(source);
131                         tree.makeVisible(p);
132                         tree.expandPath(p);
133                 }
134         }
135         
136         public void valueForPathChanged(TreePath path, Object newValue) {
137                 System.err.println("ERROR: valueForPathChanged called?!");
138         }
139
140
141         public void componentChanged(ComponentChangeEvent e) {
142                 if (e.isTreeChange() || e.isUndoChange()) {
143                         // Tree must be fully updated also in case of an undo change 
144                         fireTreeStructureChanged((RocketComponent)e.getSource());
145                         if (e.isTreeChange() && e.isUndoChange()) {
146                                 // If the undo has changed the tree structure, some elements may be hidden unnecessarily
147                                 // TODO: LOW: Could this be performed better?
148                                 expandAll();
149                         }
150                 } else if (e.isOtherChange()) {
151                         fireTreeNodesChanged();
152                 }
153         }
154
155         public void expandAll() {
156                 Iterator<RocketComponent> iterator = root.deepIterator();
157                 while (iterator.hasNext()) {
158                         tree.makeVisible(makeTreePath(iterator.next()));
159                 }
160         }
161         
162         public static TreePath makeTreePath(RocketComponent component) {
163                 int count = 0;
164                 RocketComponent c = component;
165                 
166                 while (c != null) {
167                         count++;
168                         c = c.getParent();
169                 }
170                 
171                 Object[] list = new Object[count];
172                 
173                 count--;
174                 c=component;
175                 while (c!=null) {
176                         list[count] = c;
177                         count--;
178                         c = c.getParent();
179                 }
180                 
181                 return new TreePath(list);
182         }
183         
184 }