View Javadoc

1   /*
2    * $Id: OverviewTreeModel.java,v 1.12 2007/09/28 08:44:28 edankert Exp $
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  
23  package org.xmlhammer.gui.overview;
24  
25  import java.awt.Dimension;
26  import java.util.ArrayList;
27  
28  import javax.swing.Icon;
29  import javax.swing.event.EventListenerList;
30  import javax.swing.event.TreeModelEvent;
31  import javax.swing.event.TreeModelListener;
32  import javax.swing.tree.TreeModel;
33  import javax.swing.tree.TreePath;
34  
35  import org.bounce.DummyIcon;
36  
37  
38  public class OverviewTreeModel implements TreeModel, OverviewNode {
39      private static final Icon DUMMY_ICON = new DummyIcon(new Dimension(16, 16));
40  
41      /*** Listeners. */
42      protected EventListenerList listenerList = new EventListenerList();
43  
44      private ArrayList<OverviewNode> children = null;
45  	
46  	public OverviewTreeModel() { 
47  		this( new ArrayList<OverviewNode>());
48  	}
49  
50  	public OverviewTreeModel( ArrayList<OverviewNode> children) { 
51          setChildren( children);
52  	}
53  	
54  	public void setChildren( ArrayList<OverviewNode> children) {
55  		this.children = children;
56  	    
57  		fireTreeNodesInserted( this, new Object[] { getRoot()}, new int[] { 0, 1, 2}, children.toArray());
58  	}
59  	
60      public void addChild( OverviewNode child) {
61          this.children.add( child);
62          
63          nodeInserted( child);
64      }
65  
66      public OverviewNode getRoot() {
67  		return this;
68  	}
69  
70  	/* (non-Javadoc)
71  	 * @see javax.swing.tree.TreeModel#getChild(java.lang.Object, int)
72  	 */
73  	public Object getChild( Object parent, int index) {
74  	    if ( parent instanceof OverviewNode){
75  			return ((OverviewNode)parent).getChildNodes().get( index);
76  		}
77  
78  		return null;
79  	}
80  
81  	/* (non-Javadoc)
82  	 * @see javax.swing.tree.TreeModel#getChildCount(java.lang.Object)
83  	 */
84  	public int getChildCount( Object parent) {
85  	    if ( parent instanceof OverviewNode){
86  			return ((OverviewNode)parent).getChildNodes().size();
87  		}
88  		
89  		return 0;
90  	}
91  
92  	/* (non-Javadoc)
93  	 * @see javax.swing.tree.TreeModel#isLeaf(java.lang.Object)
94  	 */
95  	public boolean isLeaf( Object node) {
96  		return getChildCount( node) == 0;
97  	}
98  
99  	/* (non-Javadoc)
100 	 * @see javax.swing.tree.TreeModel#valueForPathChanged(javax.swing.tree.TreePath, java.lang.Object)
101 	 */
102 	public void valueForPathChanged( TreePath path, Object newValue) {
103 	}
104 
105     public String getError() {
106         return null;
107     }
108 
109     public void nodeChanged(OverviewNode node) {
110         if(node != null) {
111             OverviewNode parent = node.getParentNode();
112 
113             if (parent != null) {
114                 int i = parent.getChildNodes().indexOf(node);
115             
116                 if (i != -1) {
117                     int ai[] = new int[1];
118                     ai[0] = i;
119                     nodesChanged(parent, ai);
120                 }
121             } else {
122                 nodesChanged(node, null);
123             }
124         }
125     }
126 
127     public void nodePathChanged(OverviewNode node) {
128         if(node != null) {
129             OverviewNode parent = node.getParentNode();
130             
131             while (parent != null) {
132                 int i = parent.getChildNodes().indexOf(node);
133 
134                 if(i != -1) {
135                     int ai[] = new int[1];
136                     ai[0] = i;
137                     nodesChanged(parent, ai);
138                 }
139                 
140                 node = node.getParentNode();
141                 parent = node.getParentNode();
142             }
143 
144             nodesChanged(node, null);
145         }
146     }
147 
148     public void nodesChanged(OverviewNode node, int ai[]) {
149         if(node != null)
150             
151             if( ai != null) {
152                 int i = ai.length;
153                 
154                 if( i > 0) {
155                     Object aobj[] = new Object[i];
156                     
157                     for(int j = 0; j < i; j++) {
158                         aobj[j] = node.getChildNodes().get(ai[j]);
159                     }
160 
161                     fireTreeNodesChanged(this, getPathToRoot( node, 0), ai, aobj);
162                 }
163             } else {
164                 fireTreeNodesChanged(this, getPathToRoot( node, 0), null, null);
165             }
166     }
167     
168     public void nodeRemoved(OverviewNode node) {
169         if(node != null) {
170             fireTreeNodesRemoved(node.getParentNode(), getPathToRoot( node.getParentNode(), 0), new int[] { node.getParentNode().getChildNodes().indexOf(node) }, new OverviewNode[] { node });
171         }
172     }
173 
174     public void nodeInserted(OverviewNode node) {
175         if(node != null) {
176             fireTreeNodesInserted(node.getParentNode(), getPathToRoot( node.getParentNode(), 0), new int[] { node.getParentNode().getChildNodes().indexOf(node) }, new OverviewNode[] { node });
177         }
178     }
179 
180     public void structureChanged(OverviewNode node) {
181         if(node != null) {
182             fireTreeStructureChanged(this, getPathToRoot( node, 0), null, null);
183         }
184     }
185 
186     public OverviewNode[] getPathToRoot(OverviewNode node, int i) {
187         OverviewNode path[] = null;
188 
189         if(node == null) {
190             if(i == 0) {
191                 return null;
192             }
193 
194             path = new OverviewNode[i];
195         } else {
196             i++;
197         
198             if(node == getRoot()) {
199                 path = new OverviewNode[i];
200             } else {
201                 path = getPathToRoot(node.getParentNode(), i);
202             }
203             path[path.length - i] = node;
204         }
205 
206         return path;
207     }
208 
209     /* (non-Javadoc)
210 	 * @see javax.swing.tree.TreeModel#getIndexOfChild(java.lang.Object, java.lang.Object)
211 	 */
212 	public int getIndexOfChild( Object parent, Object child) {
213 	    if ( parent instanceof OverviewNode){
214 			return ((OverviewNode)parent).getChildNodes().indexOf( child);
215 		}
216 		
217 		return 0;
218 	}
219 
220 	   /***
221      * Adds a listener for the TreeModelEvent posted after the tree changes.
222      *
223      * @see     #removeTreeModelListener
224      * @param   l       the listener to add
225      */
226     public void addTreeModelListener(TreeModelListener l) {
227         listenerList.add(TreeModelListener.class, l);
228     }
229 
230     /***
231      * Removes a listener previously added with <B>addTreeModelListener()</B>.
232      *
233      * @see     #addTreeModelListener
234      * @param   l       the listener to remove
235      */  
236     public void removeTreeModelListener(TreeModelListener l) {
237         listenerList.remove(TreeModelListener.class, l);
238     }
239 
240     /***
241      * Returns an array of all the tree model listeners
242      * registered on this model.
243      *
244      * @return all of this model's <code>TreeModelListener</code>s
245      *         or an empty
246      *         array if no tree model listeners are currently registered
247      *
248      * @see #addTreeModelListener
249      * @see #removeTreeModelListener
250      *
251      * @since 1.4
252      */
253     public TreeModelListener[] getTreeModelListeners() {
254         return listenerList.getListeners(TreeModelListener.class);
255     }
256 
257     /***
258      * Notifies all listeners that have registered interest for
259      * notification on this event type.  The event instance 
260      * is lazily created using the parameters passed into 
261      * the fire method.
262      *
263      * @param source the node being changed
264      * @param path the path to the root node
265      * @param childIndices the indices of the changed elements
266      * @param children the changed elements
267      * @see EventListenerList
268      */
269     protected void fireTreeNodesChanged(Object source, Object[] path, 
270                                         int[] childIndices, 
271                                         Object[] children) {
272         // Guaranteed to return a non-null array
273         Object[] listeners = listenerList.getListenerList();
274         TreeModelEvent e = null;
275         // Process the listeners last to first, notifying
276         // those that are interested in this event
277         for (int i = listeners.length-2; i>=0; i-=2) {
278             if (listeners[i]==TreeModelListener.class) {
279                 // Lazily create the event:
280                 if (e == null)
281                     e = new TreeModelEvent(source, path, 
282                                            childIndices, children);
283                 ((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
284             }          
285         }
286     }
287 
288     /***
289      * Notifies all listeners that have registered interest for
290      * notification on this event type.  The event instance 
291      * is lazily created using the parameters passed into 
292      * the fire method.
293      *
294      * @param source the node where new elements are being inserted
295      * @param path the path to the root node
296      * @param childIndices the indices of the new elements
297      * @param children the new elements
298      * @see EventListenerList
299      */
300     protected void fireTreeNodesInserted(Object source, Object[] path, 
301                                         int[] childIndices, 
302                                         Object[] children) {
303         // Guaranteed to return a non-null array
304         Object[] listeners = listenerList.getListenerList();
305         TreeModelEvent e = null;
306         // Process the listeners last to first, notifying
307         // those that are interested in this event
308         for (int i = listeners.length-2; i>=0; i-=2) {
309             if (listeners[i]==TreeModelListener.class) {
310                 // Lazily create the event:
311                 if (e == null)
312                     e = new TreeModelEvent(source, path, 
313                                            childIndices, children);
314                 ((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
315             }          
316         }
317     }
318 
319     /***
320      * Notifies all listeners that have registered interest for
321      * notification on this event type.  The event instance 
322      * is lazily created using the parameters passed into 
323      * the fire method.
324      *
325      * @param source the node where elements are being removed
326      * @param path the path to the root node
327      * @param childIndices the indices of the removed elements
328      * @param children the removed elements
329      * @see EventListenerList
330      */
331     protected void fireTreeNodesRemoved(Object source, Object[] path, 
332                                         int[] childIndices, 
333                                         Object[] children) {
334         // Guaranteed to return a non-null array
335         Object[] listeners = listenerList.getListenerList();
336         TreeModelEvent e = null;
337         // Process the listeners last to first, notifying
338         // those that are interested in this event
339         for (int i = listeners.length-2; i>=0; i-=2) {
340             if (listeners[i]==TreeModelListener.class) {
341                 // Lazily create the event:
342                 if (e == null)
343                     e = new TreeModelEvent(source, path, 
344                                            childIndices, children);
345                 ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
346             }          
347         }
348     }
349 
350     /***
351      * Notifies all listeners that have registered interest for
352      * notification on this event type.  The event instance 
353      * is lazily created using the parameters passed into 
354      * the fire method.
355      *
356      * @param source the node where the tree model has changed
357      * @param path the path to the root node
358      * @param childIndices the indices of the affected elements
359      * @param children the affected elements
360      * @see EventListenerList
361      */
362     protected void fireTreeStructureChanged(Object source, Object[] path, 
363                                         int[] childIndices, 
364                                         Object[] children) {
365         // Guaranteed to return a non-null array
366         Object[] listeners = listenerList.getListenerList();
367         TreeModelEvent e = null;
368         // Process the listeners last to first, notifying
369         // those that are interested in this event
370         for (int i = listeners.length-2; i>=0; i-=2) {
371             if (listeners[i]==TreeModelListener.class) {
372                 // Lazily create the event:
373                 if (e == null)
374                     e = new TreeModelEvent(source, path, 
375                                            childIndices, children);
376                 ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
377             }          
378         }
379     }
380 
381     /*
382      * Notifies all listeners that have registered interest for
383      * notification on this event type.  The event instance 
384      * is lazily created using the parameters passed into 
385      * the fire method.
386      *
387      * @param source the node where the tree model has changed
388      * @param path the path to the root node
389      * @see EventListenerList
390      */
391 //    private void fireTreeStructureChanged(Object source, TreePath path) {
392 //        // Guaranteed to return a non-null array
393 //        Object[] listeners = listenerList.getListenerList();
394 //        TreeModelEvent e = null;
395 //        // Process the listeners last to first, notifying
396 //        // those that are interested in this event
397 //        for (int i = listeners.length-2; i>=0; i-=2) {
398 //            if (listeners[i]==TreeModelListener.class) {
399 //                // Lazily create the event:
400 //                if (e == null)
401 //                    e = new TreeModelEvent(source, path);
402 //                ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
403 //            }
404 //        }
405 //    }
406     
407 	public String getNodeName() {
408 	    return "ROOT";
409 	}
410 	
411 	public ArrayList<OverviewNode> getChildNodes() {
412 	    return this.children;
413 	}
414 	
415 	public OverviewNode getParentNode() {
416 	    return null;
417 	}
418 	
419 	public Icon getNodeIcon() {
420 	    return DUMMY_ICON;
421 	}
422 }