View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.tree.model;
20  
21  import org.apache.myfaces.custom.tree.DefaultMutableTreeNode;
22  import org.apache.myfaces.custom.tree.MutableTreeNode;
23  import org.apache.myfaces.custom.tree.TreeNode;
24  
25  import java.io.Serializable;
26  import java.util.Iterator;
27  import java.util.Collection;
28  import java.util.LinkedList;
29  
30  
31  /**
32   * @author <a href="mailto:oliver@rossmueller.com">Oliver Rossmueller</a>
33   * @version $Revision: 472638 $ $Date: 2006-11-08 15:54:13 -0500 (Wed, 08 Nov 2006) $
34   */
35  public class DefaultTreeModel
36          implements TreeModel, Serializable
37  {
38  
39      private TreeNode root;
40      private LinkedList listeners = new LinkedList();
41  
42  
43      public DefaultTreeModel()
44      {
45          this(new DefaultMutableTreeNode("Root"));
46      }
47  
48  
49      public DefaultTreeModel(TreeNode root)
50      {
51          this.root = root;
52      }
53  
54  
55      public Object getRoot()
56      {
57          return root;
58      }
59  
60  
61      public Object getChild(Object parent, int index)
62      {
63          return ((TreeNode)parent).getChildAt(index);
64      }
65  
66  
67      public int getChildCount(Object parent)
68      {
69          return ((TreeNode)parent).getChildCount();
70      }
71  
72  
73      public boolean isLeaf(Object node)
74      {
75          return ((TreeNode)node).isLeaf();
76      }
77  
78  
79      public void valueForPathChanged(TreePath path, Object newValue)
80      {
81          MutableTreeNode node = (MutableTreeNode)path.getLastPathComponent();
82  
83          node.setUserObject(newValue);
84      }
85  
86  
87      public int getIndexOfChild(Object parent, Object child)
88      {
89          return ((TreeNode)parent).getIndex((TreeNode)child);
90      }
91  
92  
93      public Collection getTreeModelListeners()
94      {
95          return listeners;
96      }
97  
98  
99      /**
100      * Invoke this method after you've changed how node is to be
101      * represented in the tree.
102      */
103     public void nodeChanged(TreeNode node)
104     {
105         if (listeners.isEmpty())
106         {
107             // nobody cares
108             return;
109         }
110 
111         if (node != null)
112         {
113             TreeNode parent = node.getParent();
114 
115             if (parent != null)
116             {
117                 int index = parent.getIndex(node);
118                 if (index != -1)
119                 {
120                     int[] childIndices = new int[1];
121 
122                     childIndices[0] = index;
123                     nodesChanged(parent, childIndices);
124                 }
125             }
126             else if (node == getRoot())
127             {
128                 nodesChanged(node, null);
129             }
130         }
131     }
132 
133 
134     /**
135      * Invoke this method after you've changed how the children identified by
136      * childIndicies are to be represented in the tree.
137      */
138     public void nodesChanged(TreeNode node, int[] childIndices)
139     {
140         if (listeners.isEmpty())
141         {
142             // nobody cares
143             return;
144         }
145 
146         if (node != null)
147         {
148             if (childIndices != null)
149             {
150                 int count = childIndices.length;
151 
152                 if (count > 0)
153                 {
154                     Object[] children = new Object[count];
155 
156                     for (int i = 0; i < count; i++)
157                     {
158                         children[i] = node.getChildAt(childIndices[i]);
159                     }
160                     fireTreeNodesChanged(this, getPathToRoot(node), childIndices, children);
161                 }
162             }
163             else if (node == root)
164             {
165                 fireTreeNodesChanged(this, getPathToRoot(node), null, null);
166             }
167         }
168     }
169 
170 
171     /**
172      * Invoke this method if you've totally changed the children of
173      * node and its childrens children...  This will post a
174      * treeStructureChanged event.
175      */
176     public void nodeStructureChanged(TreeNode node)
177     {
178         if (listeners.isEmpty())
179         {
180             // nobody cares
181             return;
182         }
183 
184         if (node != null)
185         {
186             fireTreeStructureChanged(this, getPathToRoot(node), null, null);
187         }
188     }
189 
190 
191     /**
192      * Invoke this method after you've inserted some TreeNodes into
193      * node.  childIndices should be the index of the new elements and
194      * must be sorted in ascending order.
195      */
196     public void nodesWereInserted(TreeNode node, int[] childIndices)
197     {
198         if (listeners.isEmpty())
199         {
200             // nobody cares
201             return;
202         }
203         if (node != null && childIndices != null && childIndices.length > 0)
204         {
205             int cCount = childIndices.length;
206             Object[] newChildren = new Object[cCount];
207 
208             for (int counter = 0; counter < cCount; counter++)
209             {
210                 newChildren[counter] = node.getChildAt(childIndices[counter]);
211             }
212             fireTreeNodesInserted(this, getPathToRoot(node), childIndices,
213                                   newChildren);
214         }
215     }
216 
217 
218     /**
219      * Invoke this method after you've removed some TreeNodes from
220      * node.  childIndices should be the index of the removed elements and
221      * must be sorted in ascending order. And removedChildren should be
222      * the array of the children objects that were removed.
223      */
224     public void nodesWereRemoved(TreeNode node, int[] childIndices, Object[] removedChildren)
225     {
226         if (listeners.isEmpty())
227         {
228             // nobody cares
229             return;
230         }
231         if (node != null && childIndices != null)
232         {
233             fireTreeNodesRemoved(this, getPathToRoot(node), childIndices, removedChildren);
234         }
235     }
236 
237 
238     /**
239      * Collect all parent nodes up to the root node.
240      *
241      * @param node the TreeNode to get the path for
242      */
243     public TreeNode[] getPathToRoot(TreeNode node)
244     {
245         return getPathToRoot(node, 0);
246     }
247 
248 
249     /**
250      * Recursivly collect parent nodes up the the root node.
251      *
252      * @param node  the TreeNode to get the path for
253      * @param depth number of steps already taken towards the root (on recursive calls)
254      * @return an array giving the path from the root to the specified node
255      */
256     protected TreeNode[] getPathToRoot(TreeNode node, int depth)
257     {
258         TreeNode[] answer;
259 
260         if (node == null)
261         {
262             if (depth == 0)
263             {
264                 // nothing to do
265                 return null;
266             }
267             else
268             {
269                 // end recursion
270                 answer = new TreeNode[depth];
271             }
272         }
273         else
274         {
275             // recurse
276             depth++;
277 
278             if (node == root)
279             {
280                 // we found the root node
281                 answer = new TreeNode[depth];
282             }
283             else
284             {
285                 answer = getPathToRoot(node.getParent(), depth);
286             }
287             answer[answer.length - depth] = node;
288         }
289         return answer;
290     }
291 
292 
293     /**
294      * Notify all listeners of a node change.
295      *
296      * @param source       the node being changed
297      * @param path         the path to the root node
298      * @param childIndices the indices of the changed elements
299      * @param children     the changed elements
300      */
301     protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children)
302     {
303         TreeModelEvent event = null;
304         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
305         {
306             TreeModelListener listener = (TreeModelListener)iterator.next();
307             if (event == null)
308             {
309                 event = new TreeModelEvent(source, path, childIndices, children);
310             }
311             listener.treeNodesChanged(event);
312         }
313     }
314 
315 
316     /**
317      * Notify all listeners of structure change.
318      *
319      * @param source       the node where new elements are being inserted
320      * @param path         the path to the root node
321      * @param childIndices the indices of the new elements
322      * @param children     the new elements
323      */
324     protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children)
325     {
326         TreeModelEvent event = null;
327         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
328         {
329             TreeModelListener listener = (TreeModelListener)iterator.next();
330             if (event == null)
331             {
332                 event = new TreeModelEvent(source, path, childIndices, children);
333             }
334             listener.treeNodesInserted(event);
335         }
336     }
337 
338 
339     /**
340      * Notify all listeners of structure change.
341      *
342      * @param source       the node where elements are being removed
343      * @param path         the path to the root node
344      * @param childIndices the indices of the removed elements
345      * @param children     the removed elements
346      */
347     protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children)
348     {
349         TreeModelEvent event = null;
350         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
351         {
352             TreeModelListener listener = (TreeModelListener)iterator.next();
353             if (event == null)
354             {
355                 event = new TreeModelEvent(source, path, childIndices, children);
356             }
357             listener.treeNodesRemoved(event);
358         }
359     }
360 
361 
362     /**
363      * Notify all listeners of structure change.
364      *
365      * @param source       the node where the tree model has changed
366      * @param path         the path to the root node
367      * @param childIndices the indices of the affected elements
368      * @param children     the affected elements
369      */
370     protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children)
371     {
372         TreeModelEvent event = null;
373         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
374         {
375             TreeModelListener listener = (TreeModelListener)iterator.next();
376             if (event == null)
377             {
378                 event = new TreeModelEvent(source, path, childIndices, children);
379             }
380             listener.treeStructureChanged(event);
381         }
382     }
383 
384 
385     /**
386      * Notify all listeners of structure change.
387      *
388      * @param source the node where the tree model has changed
389      * @param path   the path to the root node
390      */
391     protected void fireTreeStructureChanged(Object source, TreePath path)
392     {
393         TreeModelEvent event = null;
394         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
395         {
396             TreeModelListener listener = (TreeModelListener)iterator.next();
397             if (event == null)
398             {
399                 event = new TreeModelEvent(source, path);
400             }
401             listener.treeStructureChanged(event);
402         }
403     }
404 
405 }