KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > myfaces > custom > tree > HtmlTreeNode


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.myfaces.custom.tree;
17
18 import org.apache.myfaces.custom.tree.model.TreeModel;
19 import org.apache.myfaces.custom.tree.model.TreePath;
20
21 import javax.faces.component.html.HtmlCommandLink;
22 import javax.faces.context.FacesContext;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25
26
27 /**
28  * Represents a single node of a three. A custom html link component representing the expand/collapse icon
29  * is held as a facet named <code>expandCollapse</code>.
30  *
31  * @author <a HREF="mailto:oliver@rossmueller.com">Oliver Rossmueller</a>
32  * @version $Revision: 1.12 $ $Date: 2004/11/26 12:46:38 $
33  *
34  * $Log: HtmlTreeNode.java,v $
35  * Revision 1.12 2004/11/26 12:46:38 oros
36  * cleanup: removed unused iconChild attribute
37  *
38  * Revision 1.11 2004/11/26 12:14:10 oros
39  * MYFACES-8: applied tree table patch by David Le Strat
40  *
41  */

42 public class HtmlTreeNode
43     extends HtmlCommandLink
44 {
45
46     private static final String JavaDoc DEFAULT_RENDERER_TYPE = "org.apache.myfaces.HtmlTreeNode";
47
48     public static final String JavaDoc COMPONENT_TYPE = "org.apache.myfaces.HtmlTreeNode";
49     public static final String JavaDoc EXPAND_COLLAPSE_FACET = "expandCollapse";
50
51     public static final int OPEN = 0;
52     public static final int OPEN_FIRST = 1;
53     public static final int OPEN_LAST = 2;
54     public static final int OPEN_SINGLE = 3;
55     public static final int CLOSED = 10;
56     public static final int CLOSED_FIRST = 11;
57     public static final int CLOSED_LAST = 12;
58     public static final int CLOSED_SINGLE = 13;
59     public static final int CHILD = 20;
60     public static final int CHILD_FIRST = 21;
61     public static final int CHILD_LAST = 22;
62     public static final int LINE = 30;
63     public static final int EMPTY = 40;
64     private static final int OFFSET = 10;
65     private static final int MOD_FIRST = 1;
66     private static final int MOD_LAST = 2;
67
68     private transient TreePath path;
69     private int[] translatedPath;
70     private transient Object JavaDoc userObject;
71     private boolean expanded = false;
72     private boolean selected = false;
73     private int[] layout;
74
75
76     public HtmlTreeNode()
77     {
78         setRendererType(DEFAULT_RENDERER_TYPE);
79     }
80
81
82     public int getLevel()
83     {
84         return layout.length - 1;
85     }
86
87
88     public int getMaxChildLevel()
89     {
90         if (getChildCount() == 0)
91         {
92             return getLevel();
93         }
94
95         int max = getLevel();
96         for (Iterator JavaDoc iterator = getChildren().iterator(); iterator.hasNext();)
97         {
98             HtmlTreeNode child = (HtmlTreeNode) iterator.next();
99             max = Math.max(max, child.getMaxChildLevel());
100         }
101         return max;
102     }
103
104
105     public TreePath getPath()
106     {
107         if (path == null)
108         {
109             if (translatedPath == null)
110             {
111                 throw new IllegalStateException JavaDoc("No path and no translated path available");
112             }
113             path = translatePath(translatedPath, getTreeModel(FacesContext.getCurrentInstance()));
114         }
115         return path;
116     }
117
118
119     public void setPath(TreePath path)
120     {
121         this.path = path;
122     }
123
124
125     int[] getTranslatedPath()
126     {
127         if (translatedPath != null)
128         {
129             return translatedPath;
130         }
131         ;
132         return translatePath(getPath(), getTreeModel(FacesContext.getCurrentInstance()));
133     }
134
135
136     public Object JavaDoc getUserObject()
137     {
138         if (userObject == null)
139         {
140             userObject = getPath().getLastPathComponent();
141         }
142         return userObject;
143     }
144
145
146     public void setUserObject(Object JavaDoc userObject)
147     {
148         this.userObject = userObject;
149         setValue(userObject.toString());
150     }
151
152
153     public boolean isExpanded()
154     {
155         return expanded;
156     }
157
158
159     void childrenAdded(int[] children, FacesContext context)
160     {
161         if (getChildCount() == 0 && children.length > 0)
162         {
163             // change to CLOSED_*
164
layout[layout.length - 1] -= OFFSET;
165         }
166
167         if (!expanded)
168         {
169             // nothing to do
170
return;
171         }
172
173         TreeModel model = getTreeModel(context);
174         int childCount = model.getChildCount(getUserObject());
175         int pathUpdateIndex = getTranslatedPath().length;
176
177         for (int i = 0; i < children.length; i++)
178         {
179             int index = children[i];
180             translateChildrenPath(pathUpdateIndex, index, 1);
181             Object JavaDoc userObject = model.getChild(getUserObject(), index);
182             addNode(model, userObject, index, childCount, context);
183         }
184     }
185
186
187     void childrenChanged(int[] children, FacesContext context)
188     {
189         if (!expanded)
190         {
191             // nothing to do
192
return;
193         }
194
195         TreeModel model = getTreeModel(context);
196
197         for (int i = 0; i < children.length; i++)
198         {
199             int index = children[i];
200             Object JavaDoc userObject = model.getChild(getUserObject(), index);
201             HtmlTreeNode node = (HtmlTreeNode) getChildren().get(index);
202             node.setUserObject(userObject);
203             // todo: modify path????
204
}
205     }
206
207
208     private void addNode(TreeModel model, Object JavaDoc userObject, int index, int childCount, FacesContext context)
209     {
210         HtmlTreeNode node = createNode(model, userObject, childCount, index, context);
211         List JavaDoc children = getChildren();
212
213         if (!children.isEmpty())
214         {
215             if (index == 0)
216             {
217                 HtmlTreeNode first = (HtmlTreeNode) getChildren().get(0);
218                 int[] layout = first.getLayout();
219                 if (layout[layout.length - 1] % OFFSET == MOD_FIRST)
220                 {
221                     // change from *_FIRST to *
222
layout[layout.length - 1]--;
223                 }
224             } else if (index == childCount - 1)
225             {
226                 HtmlTreeNode last = (HtmlTreeNode) getChildren().get(childCount - 2);
227                 int[] layout = last.getLayout();
228                 if (layout[layout.length - 1] % OFFSET == MOD_LAST)
229                 {
230                     // change from *_LAST to *
231
layout[layout.length - 1] -= 2;
232                 }
233             }
234         }
235
236         children.add(index, node);
237     }
238
239
240     void childrenRemoved(int[] children)
241     {
242         if (!expanded)
243         {
244             // nothing to do
245
return;
246         }
247         List JavaDoc childNodes = getChildren();
248         int pathUpdateIndex = getTranslatedPath().length;
249
250         for (int i = children.length - 1; i >= 0; i--)
251         {
252             translateChildrenPath(pathUpdateIndex, children[i], -1);
253             HtmlTreeNode child = (HtmlTreeNode) childNodes.get(children[i]);
254
255             if (child.isSelected()) {
256                 child.setSelected(false);
257                 if (children[i] < childNodes.size() - 1) {
258                     ((HtmlTreeNode) childNodes.get(children[i] + 1)).setSelected(true);
259                 } else {
260                     if (children[i] > 0) {
261                         ((HtmlTreeNode) childNodes.get(children[i] - 1)).setSelected(true);
262                     } else {
263                         setSelected(true);
264                     }
265                 }
266             }
267             childNodes.remove(children[i]);
268         }
269     }
270
271
272     /**
273      * Update the translatedPath of all child nodes so the path points to the same object in the model
274      * after adding/removing a node
275      *
276      * @param pathUpdateIndex
277      * @param startIndex
278      * @param offset
279      */

280     private void translateChildrenPath(int pathUpdateIndex, int startIndex, int offset) {
281         List JavaDoc children = getChildren();
282         int childrenSize = children.size();
283
284         for (int i = startIndex; i < childrenSize; i++) {
285             HtmlTreeNode node = (HtmlTreeNode) children.get(i);
286             node.updateTranslatedPath(pathUpdateIndex, offset);
287         }
288     }
289
290
291     private void updateTranslatedPath(int pathUpdateIndex, int offset)
292     {
293         translatedPath[pathUpdateIndex] += offset;
294         // reset path and userObject so the values are acquired from the model
295
path = null;
296         userObject = null;
297
298         if (isExpanded()) {
299             // continue with the children of this node
300
translateChildrenPath(pathUpdateIndex, 0, offset);
301         }
302     }
303
304
305     public void setExpanded(boolean expanded)
306     {
307         if (this.expanded == expanded)
308         {
309             // no change
310
return;
311         }
312         this.expanded = expanded;
313
314         if (expanded)
315         {
316             FacesContext context = FacesContext.getCurrentInstance();
317             TreeModel model = getTreeModel(context);
318             int childCount = model.getChildCount(getUserObject());
319
320             for (int i = 0; i < childCount; i++)
321             {
322                 Object JavaDoc child = model.getChild(getUserObject(), i);
323                 HtmlTreeNode node = createNode(model, child, childCount, i, context);
324                 getChildren().add(node);
325             }
326             layout[layout.length - 1] -= OFFSET;
327         } else
328         {
329             if (clearSelection())
330             {
331                 setSelected(true);
332             }
333             getChildren().clear();
334             layout[layout.length - 1] += OFFSET;
335         }
336
337     }
338
339
340     private HtmlTreeNode createNode(TreeModel model, Object JavaDoc child, int childCount, int index, FacesContext context)
341     {
342         HtmlTreeNode node = (HtmlTreeNode) context.getApplication().createComponent(HtmlTreeNode.COMPONENT_TYPE);
343         String JavaDoc id = getTree().createUniqueId(context);
344         node.setId(id);
345
346         node.setPath(getPath().pathByAddingChild(child));
347         node.setUserObject(child);
348         int state = CHILD;
349         int childChildCount = model.getChildCount(child);
350
351         if (childChildCount == 0)
352         {
353
354             if (childCount > 1)
355             {
356                 if (index == 0)
357                 {
358                     state = CHILD;
359                 } else if (index == childCount - 1)
360                 {
361                     state = CHILD_LAST;
362                 }
363             } else
364             {
365                 state = CHILD_LAST;
366             }
367         } else
368         {
369             if (childCount > 1)
370             {
371                 if (index == 0)
372                 {
373                     state = CLOSED;
374                 } else if (index == childCount - 1)
375                 {
376                     state = CLOSED_LAST;
377                 } else
378                 {
379                     state = CLOSED;
380                 }
381             } else
382             {
383                 state = CLOSED_LAST;
384             }
385
386         }
387         node.setLayout(layout, state);
388
389         return node;
390     }
391
392
393     public void toggleExpanded()
394     {
395         setExpanded(!expanded);
396     }
397
398
399     public boolean isSelected()
400     {
401         return selected;
402     }
403
404
405     public void setSelected(boolean selected)
406     {
407         if (selected)
408         {
409             getTree().getRootNode().clearSelection();
410         }
411         this.selected = selected;
412         getTree().selectionChanged(this);
413     }
414
415
416     public void toggleSelected()
417     {
418         setSelected(!selected);
419     }
420
421
422     private boolean clearSelection()
423     {
424         if (isSelected())
425         {
426             selected = false;
427             return true;
428         }
429         for (Iterator JavaDoc iterator = getChildren().iterator(); iterator.hasNext();)
430         {
431             HtmlTreeNode node = (HtmlTreeNode) iterator.next();
432             if (node.clearSelection())
433             {
434                 return true;
435             }
436         }
437         return false;
438     }
439
440
441     public int[] getLayout()
442     {
443         return layout;
444     }
445
446
447     public void setLayout(int[] layout)
448     {
449         this.layout = layout;
450     }
451
452
453     public void setLayout(int[] parentLayout, int layout)
454     {
455         this.layout = new int[parentLayout.length + 1];
456         this.layout[parentLayout.length] = layout;
457
458         for (int i = 0; i < parentLayout.length; i++)
459         {
460             int state = parentLayout[i];
461             if (state == OPEN || state == OPEN_FIRST || state == CLOSED || state == CLOSED_FIRST || state == CHILD || state == CHILD_FIRST || state == LINE)
462             {
463                 this.layout[i] = LINE;
464             } else
465             {
466                 this.layout[i] = EMPTY;
467             }
468         }
469     }
470
471
472     public HtmlTreeImageCommandLink getExpandCollapseCommand(FacesContext context)
473     {
474         HtmlTreeImageCommandLink command = (HtmlTreeImageCommandLink) getFacet(EXPAND_COLLAPSE_FACET);
475
476         if (command == null)
477         {
478             command = (HtmlTreeImageCommandLink) context.getApplication().createComponent(HtmlTreeImageCommandLink.COMPONENT_TYPE);
479             String JavaDoc id = getTree().createUniqueId(context);
480             command.setId(id);
481             getFacets().put(EXPAND_COLLAPSE_FACET, command);
482         }
483         return command;
484     }
485
486
487     public Object JavaDoc saveState(FacesContext context)
488     {
489         Object JavaDoc values[] = new Object JavaDoc[5];
490         values[0] = super.saveState(context);
491         values[1] = Boolean.valueOf(expanded);
492         values[2] = layout;
493         values[3] = translatePath(getPath(), getTreeModel(context));
494         values[4] = Boolean.valueOf(selected);
495         return ((Object JavaDoc) (values));
496     }
497
498
499     public void restoreState(FacesContext context, Object JavaDoc state)
500     {
501         Object JavaDoc values[] = (Object JavaDoc[]) state;
502         super.restoreState(context, values[0]);
503         expanded = ((Boolean JavaDoc) values[1]).booleanValue();
504         layout = (int[]) values[2];
505         translatedPath = (int[]) values[3];
506         selected = ((Boolean JavaDoc) values[4]).booleanValue();
507     }
508
509
510     protected static int[] translatePath(TreePath treePath, TreeModel model)
511     {
512         Object JavaDoc[] path = treePath.getPath();
513         int[] translated = new int[path.length - 1];
514
515         Object JavaDoc parent = path[0];
516
517         for (int i = 1; i < path.length; i++)
518         {
519             Object JavaDoc element = path[i];
520             translated[i - 1] = model.getIndexOfChild(parent, element);
521             parent = element;
522         }
523         return translated;
524     }
525
526
527     protected static TreePath translatePath(int[] path, TreeModel model)
528     {
529         Object JavaDoc[] translated = new Object JavaDoc[path.length + 1];
530         Object JavaDoc parent = model.getRoot();
531
532         translated[0] = parent;
533
534         for (int i = 0; i < path.length; i++)
535         {
536             int index = path[i];
537             translated[i + 1] = model.getChild(parent, index);
538             parent = translated[i + 1];
539         }
540         return new TreePath(translated);
541     }
542
543
544     protected TreeModel getTreeModel(FacesContext context)
545     {
546         return getTree().getModel(context);
547     }
548
549
550     protected HtmlTree getTree()
551     {
552         if (getParent() instanceof HtmlTree)
553         {
554             return (HtmlTree) getParent();
555         }
556         return ((HtmlTreeNode) getParent()).getTree();
557     }
558
559
560     public boolean isLeaf(FacesContext context)
561     {
562         return getTreeModel(context).isLeaf(getUserObject());
563     }
564
565
566     public void expandPath(int[] translatedPath, int current)
567     {
568         if (current >= translatedPath.length)
569         {
570             return;
571         }
572
573         HtmlTreeNode child = (HtmlTreeNode) getChildren().get(translatedPath[current]);
574
575         if (!child.isExpanded())
576         {
577             child.setExpanded(true);
578         }
579
580         child.expandPath(translatedPath, current + 1);
581     }
582
583
584     public void restoreItemState(HtmlTreeNode node)
585     {
586         setExpanded(node.isExpanded());
587         selected = node.isSelected();
588         List JavaDoc children = getChildren();
589         List JavaDoc otherChildren = node.getChildren();
590         for (int i = 0; i < children.size(); i++)
591         {
592             HtmlTreeNode child = (HtmlTreeNode) children.get(i);
593             child.restoreItemState((HtmlTreeNode) otherChildren.get(i));
594         }
595     }
596 }
597
Popular Tags