1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.tree2;
20
21 import java.io.IOException;
22 import java.io.Serializable;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.faces.application.FacesMessage;
29 import javax.faces.component.EditableValueHolder;
30 import javax.faces.component.NamingContainer;
31 import javax.faces.component.UIComponent;
32 import javax.faces.component.UIComponentBase;
33 import javax.faces.context.FacesContext;
34 import javax.faces.el.ValueBinding;
35 import javax.faces.event.AbortProcessingException;
36 import javax.faces.event.ActionEvent;
37 import javax.faces.event.FacesEvent;
38 import javax.faces.event.FacesListener;
39 import javax.faces.event.PhaseId;
40
41 import org.apache.myfaces.shared_tomahawk.util.MessageUtils;
42 import org.apache.myfaces.tomahawk.util.Constants;
43
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class UITreeData extends UIComponentBase implements NamingContainer, Tree {
60 private Log log = LogFactory.getLog(UITreeData.class);
61
62 public static final String COMPONENT_TYPE = "org.apache.myfaces.UITree2";
63 public static final String COMPONENT_FAMILY = "org.apache.myfaces.HtmlTree2";
64
65 private static final String MISSING_NODE = "org.apache.myfaces.tree2.MISSING_NODE";
66 private static final int PROCESS_DECODES = 1;
67 private static final int PROCESS_VALIDATORS = 2;
68 private static final int PROCESS_UPDATES = 3;
69
70 private TreeModel _cachedModel;
71 private String _nodeId;
72 private TreeNode _node;
73
74 private Object _value;
75 private String _var;
76 private Map _saved = new HashMap();
77
78 private TreeState _restoredState = null;
79
80
81
82
83 public UITreeData()
84 {
85
86 }
87
88
89
90 public String getFamily()
91 {
92 return COMPONENT_FAMILY;
93 }
94
95
96 public Object saveState(FacesContext context)
97 {
98 Object values[] = new Object[3];
99 values[0] = super.saveState(context);
100 values[1] = _var;
101 values[2] = _restoredState;
102 return ((Object) (values));
103 }
104
105
106
107 public void restoreState(FacesContext context, Object state)
108 {
109 Object values[] = (Object[]) state;
110 super.restoreState(context, values[0]);
111
112 _var = (String)values[1];
113 _restoredState = (TreeState) values[2];
114 }
115
116 public void encodeEnd(FacesContext context) throws IOException {
117 super.encodeEnd(context);
118
119
120
121
122 TreeState state = getDataModel().getTreeState();
123 if ( state == null)
124 {
125
126 state = new TreeStateBase();
127 }
128
129 _restoredState = (state.isTransient()) ? null : state;
130
131 }
132
133 public void queueEvent(FacesEvent event)
134 {
135 super.queueEvent(new FacesEventWrapper(event, getNodeId(), this));
136 }
137
138
139 public void broadcast(FacesEvent event) throws AbortProcessingException
140 {
141 if (event instanceof FacesEventWrapper)
142 {
143 FacesEventWrapper childEvent = (FacesEventWrapper) event;
144 String currNodeId = getNodeId();
145 setNodeId(childEvent.getNodeId());
146 FacesEvent nodeEvent = childEvent.getFacesEvent();
147 nodeEvent.getComponent().broadcast(nodeEvent);
148 setNodeId(currNodeId);
149 return;
150 }
151 else if(event instanceof ToggleExpandedEvent)
152 {
153 ToggleExpandedEvent toggleEvent = (ToggleExpandedEvent) event;
154 String currentNodeId = getNodeId();
155 setNodeId(toggleEvent.getNodeId());
156 toggleExpanded();
157 setNodeId(currentNodeId);
158 }
159 else
160 {
161 super.broadcast(event);
162 return;
163 }
164 }
165
166
167
168 public void processDecodes(FacesContext context)
169 {
170 if (context == null) throw new NullPointerException("context");
171 if (!isRendered()) return;
172
173 _cachedModel = null;
174 _saved = new HashMap();
175
176 setNodeId(null);
177 decode(context);
178
179 processNodes(context, PROCESS_DECODES, getDataModel().getTreeWalker());
180
181
182
183 setNodeId(null);
184
185 }
186
187
188 public void processValidators(FacesContext context)
189 {
190 if (context == null) throw new NullPointerException("context");
191 if (!isRendered()) return;
192
193 processNodes(context, PROCESS_VALIDATORS, getDataModel().getTreeWalker());
194
195 setNodeId(null);
196 }
197
198
199
200 public void processUpdates(FacesContext context)
201 {
202 if (context == null) throw new NullPointerException("context");
203 if (!isRendered()) return;
204
205 processNodes(context, PROCESS_UPDATES, getDataModel().getTreeWalker());
206
207 setNodeId(null);
208 }
209
210
211 public String getClientId(FacesContext context)
212 {
213 String ownClientId = super.getClientId(context);
214 if (_nodeId != null)
215 {
216 return ownClientId + NamingContainer.SEPARATOR_CHAR + _nodeId;
217 } else
218 {
219 return ownClientId;
220 }
221 }
222
223
224 public void setValueBinding(String name, ValueBinding binding)
225 {
226 if ("value".equals(name))
227 {
228 _cachedModel = null;
229 } else if ("nodeVar".equals(name) || "nodeId".equals(name) || "treeVar".equals(name))
230 {
231 throw new IllegalArgumentException("name " + name);
232 }
233 super.setValueBinding(name, binding);
234 }
235
236
237 public void encodeBegin(FacesContext context) throws IOException
238 {
239
240
241
242
243
244
245
246 if (!keepSaved(context))
247 {
248 _saved = new HashMap();
249 }
250
251
252
253 _cachedModel = null;
254
255 super.encodeBegin(context);
256 }
257
258
259
260
261
262
263
264
265 public void setValue(Object value)
266 {
267 _cachedModel = null;
268 _value = value;
269 }
270
271
272
273
274
275
276
277
278 public Object getModel()
279 {
280 return getValue();
281 }
282
283
284
285
286
287
288
289 public void setModel(Object model)
290 {
291 setValue(model);
292 }
293
294
295
296
297
298
299
300
301
302
303
304 public Object getValue()
305 {
306 if (_value != null) return _value;
307 ValueBinding vb = getValueBinding("value");
308 return vb != null ? vb.getValue(getFacesContext()) : null;
309 }
310
311
312
313
314
315
316
317 public void setVar(String var)
318 {
319 _var = var;
320 }
321
322
323
324
325
326
327
328
329
330 public String getVar()
331 {
332 return _var;
333 }
334
335
336
337
338
339
340 public TreeNode getNode()
341 {
342 return _node;
343 }
344
345
346 public String getNodeId()
347 {
348 return _nodeId;
349 }
350
351
352 public void setNodeId(String nodeId)
353 {
354 saveDescendantState();
355
356 _nodeId = nodeId;
357
358 TreeModel model = getDataModel();
359 if (model == null)
360 {
361 return;
362 }
363
364 try
365 {
366 _node = model.getNodeById(nodeId);
367 }
368
369 catch (IndexOutOfBoundsException aob)
370 {
371
372
373
374
375
376
377 FacesMessage message = MessageUtils.getMessageFromBundle(Constants.TOMAHAWK_DEFAULT_BUNDLE, MISSING_NODE, new String[] {nodeId});
378 message.setSeverity(FacesMessage.SEVERITY_WARN);
379 FacesContext.getCurrentInstance().addMessage(getId(), message);
380
381
382
383 }
384
385 restoreDescendantState();
386
387 if (_var != null)
388 {
389 Map requestMap = getFacesContext().getExternalContext().getRequestMap();
390
391 if (nodeId == null)
392 {
393 requestMap.remove(_var);
394 } else
395 {
396 requestMap.put(_var, getNode());
397 }
398 }
399 }
400
401
402
403
404
405
406
407
408
409
410 public String[] getPathInformation(String nodeId)
411 {
412 return getDataModel().getPathInformation(nodeId);
413 }
414
415
416
417
418
419
420
421
422 public boolean isLastChild(String nodeId)
423 {
424 return getDataModel().isLastChild(nodeId);
425 }
426
427
428
429
430
431
432
433
434 public TreeModel getDataModel()
435 {
436 if (_cachedModel != null)
437 {
438 return _cachedModel;
439 }
440
441 Object value = getValue();
442 if (value != null)
443 {
444 if (value instanceof TreeModel)
445 {
446 _cachedModel = (TreeModel) value;
447 }
448 else if (value instanceof TreeNode)
449 {
450 _cachedModel = new TreeModelBase((TreeNode) value);
451 } else
452 {
453 throw new IllegalArgumentException("Value must be a TreeModel or TreeNode");
454 }
455 }
456
457 if (_restoredState != null)
458 _cachedModel.setTreeState(_restoredState);
459
460 return _cachedModel;
461 }
462
463
464
465
466 public void expandAll()
467 {
468 toggleAll(true);
469 }
470
471
472
473
474 public void collapseAll()
475 {
476 toggleAll(false);
477 }
478
479
480
481
482
483
484
485
486 private void toggleAll(boolean expanded)
487 {
488 TreeWalker walker = getDataModel().getTreeWalker();
489 walker.reset();
490
491 TreeState state = getDataModel().getTreeState();
492 walker.setCheckState(false);
493 walker.setTree(this);
494
495 while(walker.next())
496 {
497 String id = getNodeId();
498 if ((expanded && !state.isNodeExpanded(id)) || (!expanded && state.isNodeExpanded(id)))
499 {
500 state.toggleExpanded(id);
501 }
502 }
503 }
504
505
506
507
508
509 public void expandPath(String[] nodePath)
510 {
511 getDataModel().getTreeState().expandPath(nodePath);
512 }
513
514
515
516
517
518 public void collapsePath(String[] nodePath)
519 {
520 getDataModel().getTreeState().collapsePath(nodePath);
521 }
522
523
524 protected void processNodes(FacesContext context, int processAction, TreeWalker walker)
525 {
526 UIComponent facet = null;
527 walker.reset();
528 walker.setTree(this);
529
530 while(walker.next())
531 {
532 TreeNode node = getNode();
533 facet = getFacet(node.getType());
534
535 if (facet == null)
536 {
537 log.warn("Unable to locate facet with the name: " + node.getType());
538 continue;
539
540 }
541
542 switch (processAction)
543 {
544 case PROCESS_DECODES:
545
546 facet.processDecodes(context);
547 break;
548
549 case PROCESS_VALIDATORS:
550
551 facet.processValidators(context);
552 break;
553
554 case PROCESS_UPDATES:
555
556 facet.processUpdates(context);
557 break;
558 }
559 }
560
561 }
562
563
564
565
566
567
568 private void saveDescendantState()
569 {
570 FacesContext context = getFacesContext();
571 Iterator i = getFacets().values().iterator();
572 while (i.hasNext())
573 {
574 UIComponent facet = (UIComponent) i.next();
575 saveDescendantState(facet, context);
576 }
577 }
578
579
580
581
582
583
584
585 private void saveDescendantState(UIComponent component, FacesContext context)
586 {
587 if (component instanceof EditableValueHolder)
588 {
589 EditableValueHolder input = (EditableValueHolder) component;
590 String clientId = component.getClientId(context);
591 SavedState state = (SavedState) _saved.get(clientId);
592 if (state == null)
593 {
594 state = new SavedState();
595 _saved.put(clientId, state);
596 }
597 state.setValue(input.getLocalValue());
598 state.setValid(input.isValid());
599 state.setSubmittedValue(input.getSubmittedValue());
600 state.setLocalValueSet(input.isLocalValueSet());
601 }
602
603 List kids = component.getChildren();
604 for (int i = 0; i < kids.size(); i++)
605 {
606 saveDescendantState((UIComponent) kids.get(i), context);
607 }
608 }
609
610
611
612
613
614 private void restoreDescendantState()
615 {
616 FacesContext context = getFacesContext();
617 Iterator i = getFacets().values().iterator();
618 while (i.hasNext())
619 {
620 UIComponent facet = (UIComponent) i.next();
621 restoreDescendantState(facet, context);
622 }
623 }
624
625
626
627
628
629
630
631 private void restoreDescendantState(UIComponent component, FacesContext context)
632 {
633 String id = component.getId();
634 component.setId(id);
635
636 if (component instanceof EditableValueHolder)
637 {
638 EditableValueHolder input = (EditableValueHolder) component;
639 String clientId = component.getClientId(context);
640 SavedState state = (SavedState) _saved.get(clientId);
641 if (state == null)
642 {
643 state = new SavedState();
644 }
645 input.setValue(state.getValue());
646 input.setValid(state.isValid());
647 input.setSubmittedValue(state.getSubmittedValue());
648 input.setLocalValueSet(state.isLocalValueSet());
649 }
650
651 List kids = component.getChildren();
652 for (int i = 0; i < kids.size(); i++)
653 {
654 restoreDescendantState((UIComponent)kids.get(i), context);
655 }
656 Map facets = component.getFacets();
657 for(Iterator i = facets.values().iterator(); i.hasNext();)
658 {
659 restoreDescendantState((UIComponent)i.next(), context);
660 }
661 }
662
663
664
665
666
667
668
669
670 private static class SavedState implements Serializable
671 {
672 private static final long serialVersionUID = 273343276957070557L;
673 private Object submittedValue;
674 private boolean valid = true;
675 private Object value;
676 private boolean localValueSet;
677
678 Object getSubmittedValue()
679 {
680 return submittedValue;
681 }
682
683 void setSubmittedValue(Object submittedValue)
684 {
685 this.submittedValue = submittedValue;
686 }
687
688 boolean isValid()
689 {
690 return valid;
691 }
692
693 void setValid(boolean valid)
694 {
695 this.valid = valid;
696 }
697
698 Object getValue()
699 {
700 return value;
701 }
702
703 void setValue(Object value)
704 {
705 this.value = value;
706 }
707
708 boolean isLocalValueSet()
709 {
710 return localValueSet;
711 }
712
713 void setLocalValueSet(boolean localValueSet)
714 {
715 this.localValueSet = localValueSet;
716 }
717 }
718
719
720
721
722
723
724
725 private static class FacesEventWrapper extends FacesEvent
726 {
727 private static final long serialVersionUID = -3056153249469828447L;
728 private FacesEvent _wrappedFacesEvent;
729 private String _nodeId;
730
731
732 public FacesEventWrapper(FacesEvent facesEvent, String nodeId, UIComponent component)
733 {
734 super(component);
735 _wrappedFacesEvent = facesEvent;
736 _nodeId = nodeId;
737 }
738
739
740 public PhaseId getPhaseId()
741 {
742 return _wrappedFacesEvent.getPhaseId();
743 }
744
745
746 public void setPhaseId(PhaseId phaseId)
747 {
748 _wrappedFacesEvent.setPhaseId(phaseId);
749 }
750
751
752 public void queue()
753 {
754 _wrappedFacesEvent.queue();
755 }
756
757
758 public String toString()
759 {
760 return _wrappedFacesEvent.toString();
761 }
762
763
764 public boolean isAppropriateListener(FacesListener faceslistener)
765 {
766
767 return false;
768 }
769
770
771 public void processListener(FacesListener faceslistener)
772 {
773 throw new UnsupportedOperationException("This event type is only intended for wrapping a real event");
774 }
775
776
777 public FacesEvent getFacesEvent()
778 {
779 return _wrappedFacesEvent;
780 }
781
782
783 public String getNodeId()
784 {
785 return _nodeId;
786 }
787 }
788
789
790
791
792
793
794
795 private boolean keepSaved(FacesContext context)
796 {
797 Iterator clientIds = _saved.keySet().iterator();
798 while (clientIds.hasNext())
799 {
800 String clientId = (String) clientIds.next();
801 Iterator messages = context.getMessages(clientId);
802 while (messages.hasNext())
803 {
804 FacesMessage message = (FacesMessage) messages.next();
805 if (message.getSeverity().compareTo(FacesMessage.SEVERITY_ERROR) >= 0)
806 {
807 return true;
808 }
809 }
810 }
811
812 return false;
813 }
814
815
816
817
818 public void toggleExpanded()
819 {
820 getDataModel().getTreeState().toggleExpanded(getNodeId());
821 }
822
823
824
825
826
827 public boolean isNodeExpanded()
828 {
829 return getDataModel().getTreeState().isNodeExpanded(getNodeId());
830 }
831
832
833
834
835
836
837
838
839 public void setNodeSelected(ActionEvent event)
840 {
841 getDataModel().getTreeState().setSelected(getNodeId());
842 }
843
844
845
846
847
848 public boolean isNodeSelected()
849 {
850 return (getNodeId() != null) ? getDataModel().getTreeState().isSelected(getNodeId()) : false;
851 }
852 }