1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.component.html.ext;
20
21 import java.io.IOException;
22 import java.sql.ResultSet;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.StringTokenizer;
30
31 import javax.el.ValueExpression;
32 import javax.faces.FacesException;
33 import javax.faces.application.Application;
34 import javax.faces.component.ContextCallback;
35 import javax.faces.component.EditableValueHolder;
36 import javax.faces.component.NamingContainer;
37 import javax.faces.component.UIColumn;
38 import javax.faces.component.UIComponent;
39 import javax.faces.component.UINamingContainer;
40 import javax.faces.context.FacesContext;
41 import javax.faces.el.ValueBinding;
42 import javax.faces.model.DataModel;
43
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46 import org.apache.myfaces.component.NewspaperTable;
47 import org.apache.myfaces.component.UserRoleAware;
48 import org.apache.myfaces.component.UserRoleUtils;
49 import org.apache.myfaces.custom.column.HtmlSimpleColumn;
50 import org.apache.myfaces.custom.crosstable.UIColumns;
51 import org.apache.myfaces.custom.sortheader.HtmlCommandSortHeader;
52 import org.apache.myfaces.renderkit.html.ext.HtmlTableRenderer;
53 import org.apache.myfaces.renderkit.html.util.TableContext;
54 import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
55 import org.apache.myfaces.shared_tomahawk.util.ClassUtils;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public abstract class AbstractHtmlDataTable extends HtmlDataTableHack implements UserRoleAware, NewspaperTable
84 {
85 private static final Log log = LogFactory.getLog(AbstractHtmlDataTable.class);
86
87 private static final int PROCESS_DECODES = 1;
88 private static final int PROCESS_VALIDATORS = 2;
89 private static final int PROCESS_UPDATES = 3;
90
91 private static final boolean DEFAULT_SORTASCENDING = true;
92 private static final boolean DEFAULT_SORTABLE = false;
93 private static final boolean DEFAULT_EMBEDDED = false;
94 private static final boolean DEFAULT_DETAILSTAMP_EXPANDED = false;
95 private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
96
97 private static final Integer DEFAULT_NEWSPAPER_COLUMNS = new Integer(1);
98 private static final String DEFAULT_NEWSPAPER_ORIENTATION = "vertical";
99 private static final String DEFAULT_DETAILSTAMP_LOCATION = "after";
100
101
102
103
104 public static final String NEWSPAPER_COLUMNS_PROPERTY = "newspaperColumns";
105 public static final String SPACER_FACET_NAME = "spacer";
106 public static final String NEWSPAPER_ORIENTATION_PROPERTY = "newspaperOrientation";
107
108 public static final String DETAIL_STAMP_FACET_NAME = "detailStamp";
109
110 private _SerializableDataModel _preservedDataModel;
111
112 private String _forceIdIndexFormula = null;
113 private String _sortColumn = null;
114 private Boolean _sortAscending = null;
115 private String _sortProperty = null;
116 private String _rowStyleClass = null;
117 private String _rowStyle = null;
118 private String _varDetailToggler = null;
119
120 private int _sortColumnIndex = -1;
121
122 private boolean _isValidChildren = true;
123
124 private Map _expandedNodes = new HashMap();
125
126
127
128 private TableContext _tableContext = null;
129
130 public TableContext getTableContext()
131 {
132 if (_tableContext == null)
133 {
134 _tableContext = new TableContext();
135 }
136 return _tableContext;
137 }
138
139 public void setDetailStamp(UIComponent facet)
140 {
141 getFacets().put(DETAIL_STAMP_FACET_NAME, facet);
142 }
143
144
145
146
147
148
149
150
151
152 public UIComponent getDetailStamp()
153 {
154 return (UIComponent) getFacets().get(DETAIL_STAMP_FACET_NAME);
155 }
156
157 public String getClientId(FacesContext context)
158 {
159 String standardClientId = super.getClientId(context);
160 int rowIndex = getRowIndex();
161 if (rowIndex == -1)
162 {
163 return standardClientId;
164 }
165
166 String forcedIdIndex = getForceIdIndexFormula();
167 if (forcedIdIndex == null || forcedIdIndex.length() == 0)
168 return standardClientId;
169
170
171
172
173 int indexLast_ = standardClientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
174 if (indexLast_ == -1)
175 {
176 log.info("Could not parse super.getClientId. forcedIdIndex will contain the rowIndex.");
177 return standardClientId + NamingContainer.SEPARATOR_CHAR + forcedIdIndex;
178 }
179
180
181 String parsedForcedClientId = standardClientId.substring(0, indexLast_ + 1) + forcedIdIndex;
182 return parsedForcedClientId;
183 }
184
185 public UIComponent findComponent(String expr)
186 {
187 if (expr.length() > 0 && Character.isDigit(expr.charAt(0)))
188 {
189 int separatorIndex = expr.indexOf(NamingContainer.SEPARATOR_CHAR);
190
191 String rowIndexStr = expr;
192 String remainingPart = null;
193
194 if (separatorIndex != -1)
195 {
196 rowIndexStr = expr.substring(0, separatorIndex);
197 remainingPart = expr.substring(separatorIndex + 1);
198 }
199
200 int rowIndex = Integer.valueOf(rowIndexStr).intValue();
201
202 if (remainingPart == null)
203 {
204 log.error("Wrong syntax of expression : " + expr +
205 " rowIndex was provided, but no component name.");
206 return null;
207 }
208
209 UIComponent comp = super.findComponent(remainingPart);
210
211 if (comp == null)
212 return null;
213
214
215 UIComponentPerspective perspective = new UIComponentPerspective(this, comp, rowIndex);
216 return perspective;
217 }
218 else
219 {
220 return super.findComponent(expr);
221 }
222 }
223
224 @Override
225 public boolean invokeOnComponent(FacesContext context, String clientId,
226 ContextCallback callback) throws FacesException
227 {
228 if (context == null || clientId == null || callback == null)
229 {
230 throw new NullPointerException();
231 }
232
233 final String baseClientId = getClientId(context);
234
235
236 boolean returnValue = baseClientId.equals(clientId);
237
238 if (returnValue)
239 {
240 try
241 {
242 callback.invokeContextCallback(context, this);
243 return true;
244 }
245 catch (Exception e)
246 {
247 throw new FacesException(e);
248 }
249 }
250
251
252 for (Iterator<UIComponent> it = this.getFacets().values().iterator(); !returnValue && it.hasNext();)
253 {
254 returnValue = it.next().invokeOnComponent(context, clientId, callback);
255 }
256
257 if (returnValue)
258 {
259 return returnValue;
260 }
261
262
263 if (clientId.startsWith(baseClientId))
264 {
265
266
267 char separator = UINamingContainer.SEPARATOR_CHAR;
268
269 ValueExpression rowKeyVE = getValueExpression("rowKey");
270 boolean rowKeyFound = false;
271
272 if (rowKeyVE != null)
273 {
274 int oldRow = this.getRowIndex();
275 try
276 {
277
278 int rowsToProcess = getRows();
279
280 if (rowsToProcess == 0)
281 {
282 rowsToProcess = getRowCount();
283 }
284 int rowIndex = getFirst();
285 for (int rowsProcessed = 0; rowsProcessed < rowsToProcess; rowsProcessed++, rowIndex++)
286 {
287 setRowIndex(rowIndex);
288 if (!isRowAvailable())
289 {
290 break;
291 }
292
293 if (clientId.startsWith(getContainerClientId(context)))
294 {
295 rowKeyFound = true;
296 break;
297 }
298 }
299
300 if (rowKeyFound)
301 {
302 returnValue = invokeOnComponentTraverseRow(context, clientId, callback);
303 }
304 }
305 finally
306 {
307 this.setRowIndex(oldRow);
308 }
309 }
310 if (rowKeyVE == null && clientId.matches(baseClientId + separator+"[0-9]+"+separator+".*"))
311 {
312 String subId = clientId.substring(baseClientId.length() + 1);
313 String clientRow = subId.substring(0, subId.indexOf(separator));
314
315
316 int oldRow = this.getRowIndex();
317
318
319 try
320 {
321
322
323 this.setRowIndex(Integer.parseInt(clientRow));
324
325
326 if (!isRowAvailable())
327 {
328 return false;
329 }
330
331 returnValue = invokeOnComponentTraverseRow(context, clientId, callback);
332 }
333 finally
334 {
335
336
337 this.setRowIndex(oldRow);
338 }
339 }
340 else
341 {
342
343
344
345
346
347 for (Iterator<UIComponent> itChildren = this.getChildren().iterator();
348 !returnValue && itChildren.hasNext();)
349 {
350 UIComponent child = itChildren.next();
351
352
353
354
355 if (child instanceof UIColumn && clientId.equals(child.getClientId(context)))
356 {
357 try {
358 callback.invokeContextCallback(context, child);
359 } catch (Exception e) {
360 throw new FacesException(e);
361 }
362 returnValue = true;
363 }
364
365 for (Iterator<UIComponent> itChildFacets = child.getFacets().values().iterator();
366 !returnValue && itChildFacets.hasNext();)
367 {
368
369 returnValue = itChildFacets.next().invokeOnComponent(context, clientId, callback);
370 }
371 }
372 }
373 }
374
375 return returnValue;
376 }
377
378 private boolean invokeOnComponentTraverseRow(FacesContext context, String clientId,
379 ContextCallback callback)
380 {
381 boolean returnValue = false;
382 for (Iterator<UIComponent> it1 = getChildren().iterator();
383 !returnValue && it1.hasNext();)
384 {
385
386 returnValue = it1.next().invokeOnComponent(context, clientId, callback);
387 }
388
389 if (!returnValue)
390 {
391 UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME);
392 if (detailStampFacet != null)
393 {
394 returnValue = detailStampFacet.invokeOnComponent(context, clientId, callback);
395 }
396 }
397 return returnValue;
398 }
399
400 public void setRowIndex(int rowIndex)
401 {
402
403
404 if (rowIndex < -1)
405 {
406 throw new IllegalArgumentException("rowIndex is less than -1");
407 }
408
409
410
411
412
413
414
415
416
417
418 String rowIndexVar = getRowIndexVar();
419 String rowCountVar = getRowCountVar();
420 String previousRowDataVar = getPreviousRowDataVar();
421 if (rowIndexVar != null || rowCountVar != null || previousRowDataVar != null)
422 {
423 Map requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
424
425 if (previousRowDataVar != null && rowIndex >= 0)
426 {
427 if (isRowAvailable())
428 {
429
430 requestMap.put(previousRowDataVar, getRowData());
431 }
432 else
433 {
434
435 requestMap.put(previousRowDataVar, null);
436 }
437 }
438
439 super.setRowIndex(rowIndex);
440
441 if (rowIndex >= 0)
442 {
443
444 if (rowIndexVar != null)
445 {
446 requestMap.put(rowIndexVar, new Integer(rowIndex));
447 }
448
449 if (rowCountVar != null)
450 {
451 requestMap.put(rowCountVar, new Integer(getRowCount()));
452 }
453 }
454 else
455 {
456
457 if (rowIndexVar != null)
458 {
459 requestMap.remove(rowIndexVar);
460 }
461
462 if (rowCountVar != null)
463 {
464 requestMap.remove(rowCountVar);
465 }
466
467 if (previousRowDataVar != null)
468 {
469 requestMap.remove(previousRowDataVar);
470 }
471 }
472 }
473 else
474 {
475
476 super.setRowIndex(rowIndex);
477 }
478
479
480
481
482
483
484
485
486
487
488 if (_varDetailToggler != null)
489 {
490 Map requestMap = getFacesContext().getExternalContext().getRequestMap();
491 requestMap.put(_varDetailToggler, this);
492 }
493 }
494
495 protected Object saveDescendantComponentStates()
496 {
497 if (!getFacets().isEmpty())
498 {
499 UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME);
500 if (detailStampFacet != null)
501 {
502 return saveDescendantComponentStates(new _DetailStampFacetAndChildrenIterator(detailStampFacet, getChildren()), false);
503 }
504 }
505 return super.saveDescendantComponentStates();
506 }
507
508 protected void restoreDescendantComponentStates(Object state)
509 {
510 if (!getFacets().isEmpty())
511 {
512 UIComponent detailStampFacet = getFacet(DETAIL_STAMP_FACET_NAME);
513 if (detailStampFacet != null)
514 {
515 restoreDescendantComponentStates(new _DetailStampFacetAndChildrenIterator(detailStampFacet, getChildren()), state, false);
516 return;
517 }
518 }
519 super.restoreDescendantComponentStates(state);
520 }
521
522 public void processDecodes(FacesContext context)
523 {
524 if (!isRendered())
525 {
526 return;
527 }
528
529
530
531
532
533
534
535 setRowIndex(-1);
536 processFacets(context, PROCESS_DECODES);
537 processColumnFacets(context, PROCESS_DECODES);
538 processColumnChildren(context, PROCESS_DECODES);
539 setRowIndex(-1);
540 try
541 {
542 decode(context);
543 }
544 catch (RuntimeException e)
545 {
546 context.renderResponse();
547 throw e;
548 }
549
550 setRowIndex(-1);
551 processColumns(context, PROCESS_DECODES);
552 setRowIndex(-1);
553 processDetails(context, PROCESS_DECODES);
554 setRowIndex(-1);
555 }
556
557 private void processFacets(FacesContext context, int processAction)
558 {
559 for (Iterator it = getFacets().entrySet().iterator(); it.hasNext(); )
560 {
561 Map.Entry entry = (Map.Entry) it.next();
562 if (!DETAIL_STAMP_FACET_NAME.equals((String)entry.getKey()))
563 {
564 process(context, (UIComponent) entry.getValue(), processAction);
565 }
566 }
567 }
568
569
570
571
572
573
574
575
576
577
578 private void processColumnFacets(FacesContext context, int processAction)
579 {
580 for (Iterator childIter = getChildren().iterator(); childIter.hasNext();)
581 {
582 UIComponent child = (UIComponent) childIter.next();
583 if (child instanceof UIColumn)
584 {
585 if (!child.isRendered())
586 {
587
588 continue;
589 }
590 for (Iterator facetsIter = child.getFacets().values()
591 .iterator(); facetsIter.hasNext();)
592 {
593 UIComponent facet = (UIComponent) facetsIter.next();
594 process(context, facet, processAction);
595 }
596 }
597 }
598 }
599
600
601
602
603
604
605
606
607
608
609 private void processColumnChildren(FacesContext context, int processAction)
610 {
611 int first = getFirst();
612 int rows = getRows();
613 int last;
614 if (rows == 0)
615 {
616 last = getRowCount();
617 }
618 else
619 {
620 last = first + rows;
621 }
622 for (int rowIndex = first; last==-1 || rowIndex < last; rowIndex++)
623 {
624 setRowIndex(rowIndex);
625
626
627 if (!isRowAvailable())
628 break;
629
630 for (Iterator it = getChildren().iterator(); it.hasNext();)
631 {
632 UIComponent child = (UIComponent) it.next();
633 if (child instanceof UIColumn)
634 {
635 if (!child.isRendered())
636 {
637
638 continue;
639 }
640 for (Iterator columnChildIter = child.getChildren()
641 .iterator(); columnChildIter.hasNext();)
642 {
643 UIComponent columnChild = (UIComponent) columnChildIter
644 .next();
645 process(context, columnChild, processAction);
646 }
647 }
648 }
649 }
650 }
651
652
653
654
655
656 private void processDetails(FacesContext context, int processAction)
657 {
658 UIComponent facet = getFacet(HtmlTableRenderer.DETAIL_STAMP_FACET_NAME);
659
660 if (facet != null)
661 {
662 int first = getFirst();
663 int rows = getRows();
664 int last;
665 if (rows == 0)
666 {
667 last = getRowCount();
668 }
669 else
670 {
671 last = first + rows;
672 }
673 for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++)
674 {
675 setRowIndex(rowIndex);
676
677
678 if (!isRowAvailable())
679 {
680 break;
681 }
682
683 if (!isCurrentDetailExpanded())
684 {
685 continue;
686 }
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 if (PROCESS_DECODES == processAction)
707 {
708 resetAllSubmittedValues(facet);
709 }
710
711 process(context, facet, processAction);
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726 }
727 }
728 }
729
730 private void resetAllSubmittedValues(UIComponent component)
731 {
732 if (component instanceof EditableValueHolder)
733 {
734 ((EditableValueHolder) component).setSubmittedValue(null);
735 }
736
737 for (Iterator it = component.getFacetsAndChildren(); it.hasNext();)
738 {
739 resetAllSubmittedValues((UIComponent) it.next());
740 }
741 }
742
743
744
745
746
747 private void processColumns(FacesContext context, int processAction)
748 {
749 for (Iterator it = getChildren().iterator(); it.hasNext();)
750 {
751 UIComponent child = (UIComponent) it.next();
752 if (child instanceof UIColumns)
753 {
754 process(context, child, processAction);
755 }
756 }
757 }
758
759 private void process(FacesContext context, UIComponent component, int processAction)
760 {
761 switch (processAction)
762 {
763 case PROCESS_DECODES:
764 component.processDecodes(context);
765 break;
766 case PROCESS_VALIDATORS:
767 component.processValidators(context);
768 break;
769 case PROCESS_UPDATES:
770 component.processUpdates(context);
771 break;
772 }
773 }
774
775 public void processValidators(FacesContext context)
776 {
777 if (!isRendered())
778 {
779 return;
780 }
781
782
783
784
785
786
787 setRowIndex(-1);
788 processFacets(context, PROCESS_VALIDATORS);
789 processColumnFacets(context, PROCESS_VALIDATORS);
790 processColumnChildren(context, PROCESS_VALIDATORS);
791 setRowIndex(-1);
792
793 processColumns(context, PROCESS_VALIDATORS);
794 setRowIndex(-1);
795 processDetails(context, PROCESS_VALIDATORS);
796 setRowIndex(-1);
797
798 if (context.getRenderResponse())
799 {
800 _isValidChildren = false;
801 }
802 }
803
804 public void processUpdates(FacesContext context)
805 {
806 if (!isRendered())
807 {
808 return;
809 }
810
811
812
813
814
815
816
817
818 setRowIndex(-1);
819 processFacets(context, PROCESS_UPDATES);
820 processColumnFacets(context, PROCESS_UPDATES);
821 processColumnChildren(context, PROCESS_UPDATES);
822 setRowIndex(-1);
823
824 processColumns(context, PROCESS_UPDATES);
825 setRowIndex(-1);
826 processDetails(context, PROCESS_UPDATES);
827 setRowIndex(-1);
828
829 if (isPreserveDataModel())
830 {
831 updateModelFromPreservedDataModel(context);
832 }
833
834 if (context.getRenderResponse())
835 {
836 _isValidChildren = false;
837 }
838 }
839
840 private void updateModelFromPreservedDataModel(FacesContext context)
841 {
842 ValueBinding vb = getValueBinding("value");
843 if (vb != null && !vb.isReadOnly(context))
844 {
845 _SerializableDataModel dm = (_SerializableDataModel) getDataModel();
846 Class type = (getValueType() == null) ?
847 vb.getType(context) :
848 ClassUtils.simpleClassForName(getValueType());
849 Class dmType = dm.getClass();
850 if (DataModel.class.isAssignableFrom(type))
851 {
852 vb.setValue(context, dm);
853 }
854 else if (List.class.isAssignableFrom(type) || _SerializableListDataModel.class.isAssignableFrom(dmType))
855 {
856 vb.setValue(context, dm.getWrappedData());
857 }
858 else if (OBJECT_ARRAY_CLASS.isAssignableFrom(type))
859 {
860 List lst = (List) dm.getWrappedData();
861 vb.setValue(context, lst.toArray(new Object[lst.size()]));
862 }
863 else if (ResultSet.class.isAssignableFrom(type))
864 {
865 throw new UnsupportedOperationException(this.getClass().getName()
866 + " UnsupportedOperationException");
867 }
868 else
869 {
870
871 List lst = (List) dm.getWrappedData();
872 if (lst!= null && lst.size() > 0)
873 {
874 vb.setValue(context, lst.get(0));
875 }
876 else
877 {
878 vb.setValue(context, null);
879 }
880 }
881 }
882 _preservedDataModel = null;
883 }
884
885 public void encodeBegin(FacesContext context) throws IOException
886 {
887 if (!isRendered())
888 return;
889
890 if (_isValidChildren && !hasErrorMessages(context))
891 {
892 _preservedDataModel = null;
893 }
894
895 for (Iterator iter = getChildren().iterator(); iter.hasNext();)
896 {
897 UIComponent component = (UIComponent) iter.next();
898 if (component instanceof UIColumns)
899 {
900
901
902 ((UIColumns) component).encodeTableBegin(context);
903 }
904 }
905
906
907
908 for (Iterator iter = getChildren().iterator(); iter.hasNext();)
909 {
910 UIComponent component = (UIComponent) iter.next();
911 if (component instanceof UIColumn)
912 {
913 UIColumn aColumn = (UIColumn) component;
914 UIComponent headerFacet = aColumn.getHeader();
915
916 boolean replaceHeaderFacets = isSortable();
917
918 String columnName = null;
919 String propertyName = null;
920 boolean defaultSorted = false;
921
922 if (aColumn instanceof HtmlSimpleColumn)
923 {
924 HtmlSimpleColumn asColumn = (HtmlSimpleColumn) aColumn;
925 propertyName = asColumn.getSortPropertyName();
926 defaultSorted = asColumn.isDefaultSorted();
927
928 if (asColumn.isSortable())
929 replaceHeaderFacets = true;
930 }
931
932
933 if (replaceHeaderFacets && isSortHeaderNeeded(aColumn, headerFacet))
934 {
935 propertyName = propertyName != null ? propertyName : getSortPropertyFromEL(aColumn);
936 if (propertyName == null)
937 log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "].");
938
939 if (headerFacet != null)
940 {
941 HtmlCommandSortHeader sortHeader = createSortHeaderComponent(context, aColumn, headerFacet, propertyName);
942 columnName = sortHeader.getColumnName();
943
944 aColumn.setHeader(sortHeader);
945 sortHeader.setParent(aColumn);
946 }
947 }
948 else if (headerFacet instanceof HtmlCommandSortHeader)
949 {
950
951 HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) headerFacet;
952 columnName = sortHeader.getColumnName();
953 propertyName = sortHeader.getPropertyName();
954
955
956 if (propertyName == null)
957 {
958 propertyName = getSortPropertyFromEL(aColumn);
959 sortHeader.setPropertyName(propertyName);
960 }
961
962 if (propertyName == null)
963 log.warn("Couldn't determine sort property for column [" + aColumn.getId() + "].");
964 }
965
966
967 if (defaultSorted && getSortColumn() == null)
968 {
969 setSortColumn(columnName);
970 setSortProperty(propertyName);
971 }
972 }
973 }
974
975
976
977 super.encodeBegin(context);
978 }
979
980
981
982
983 protected boolean isSortHeaderNeeded(UIColumn parentColumn, UIComponent headerFacet)
984 {
985 return !(headerFacet instanceof HtmlCommandSortHeader);
986 }
987
988
989
990
991 protected HtmlCommandSortHeader createSortHeaderComponent(FacesContext context, UIColumn parentColumn, UIComponent initialHeaderFacet, String propertyName)
992 {
993 Application application = context.getApplication();
994
995 HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) application.createComponent(HtmlCommandSortHeader.COMPONENT_TYPE);
996 String id = context.getViewRoot().createUniqueId();
997 sortHeader.setId(id);
998 sortHeader.setColumnName(id);
999 sortHeader.setPropertyName(propertyName);
1000 sortHeader.setArrow(true);
1001 sortHeader.setImmediate(true);
1002 sortHeader.getChildren().add(initialHeaderFacet);
1003 initialHeaderFacet.setParent(sortHeader);
1004
1005 return sortHeader;
1006 }
1007
1008
1009
1010
1011 protected String getSortPropertyFromEL(UIComponent component)
1012 {
1013 if (getVar() == null)
1014 {
1015 log.warn("There is no 'var' specified on the dataTable, sort properties cannot be determined automaticaly.");
1016 return null;
1017 }
1018
1019 for (Iterator iter = component.getChildren().iterator(); iter.hasNext();)
1020 {
1021 UIComponent aChild = (UIComponent) iter.next();
1022 if (aChild.isRendered())
1023 {
1024 ValueBinding vb = aChild.getValueBinding("value");
1025 if (vb != null)
1026 {
1027 String expressionString = vb.getExpressionString();
1028
1029 int varIndex = expressionString.indexOf(getVar() + ".");
1030 if (varIndex != -1)
1031 {
1032 int varEndIndex = varIndex + getVar().length();
1033 String tempProp = expressionString.substring(varEndIndex + 1, expressionString.length());
1034
1035 StringTokenizer tokenizer = new StringTokenizer(tempProp, " +[]{}-/*|?:&<>!=()%");
1036 if (tokenizer.hasMoreTokens())
1037 return tokenizer.nextToken();
1038 }
1039 }
1040 else
1041 {
1042 String sortProperty = getSortPropertyFromEL(aChild);
1043 if (sortProperty != null)
1044 return sortProperty;
1045 }
1046 }
1047 }
1048
1049 return null;
1050 }
1051
1052
1053
1054
1055 protected int columnNameToIndex(String columnName)
1056 {
1057 int index = 0;
1058 for (Iterator iter = getChildren().iterator(); iter.hasNext();)
1059 {
1060 UIComponent aChild = (UIComponent) iter.next();
1061 if (aChild instanceof UIColumn)
1062 {
1063 UIComponent headerFacet = ((UIColumn) aChild).getHeader();
1064 if (headerFacet != null && headerFacet instanceof HtmlCommandSortHeader)
1065 {
1066 HtmlCommandSortHeader sortHeader = (HtmlCommandSortHeader) headerFacet;
1067 if (columnName != null && columnName.equals(sortHeader.getColumnName()))
1068 return index;
1069 }
1070 }
1071
1072 index += 1;
1073 }
1074
1075 return -1;
1076 }
1077
1078
1079
1080
1081 public void encodeEnd(FacesContext context) throws IOException
1082 {
1083 super.encodeEnd(context);
1084 for (Iterator iter = getChildren().iterator(); iter.hasNext();)
1085 {
1086 UIComponent component = (UIComponent) iter.next();
1087 if (component instanceof UIColumns)
1088 {
1089 ((UIColumns) component).encodeTableEnd(context);
1090 }
1091 }
1092 }
1093
1094
1095
1096
1097
1098
1099 public int getFirst()
1100 {
1101 if (_preservedDataModel != null)
1102 {
1103
1104 return _preservedDataModel.getFirst();
1105 }
1106 else
1107 {
1108 return super.getFirst();
1109 }
1110 }
1111
1112 public void setFirst(int first)
1113 {
1114 if (_preservedDataModel != null)
1115 {
1116
1117 _preservedDataModel.setFirst(first);
1118 }
1119 super.setFirst(first);
1120 }
1121
1122
1123
1124
1125
1126
1127 public int getRows()
1128 {
1129 if (_preservedDataModel != null)
1130 {
1131
1132 return _preservedDataModel.getRows();
1133 }
1134 else
1135 {
1136 return super.getRows();
1137 }
1138 }
1139
1140 public void setRows(int rows)
1141 {
1142 if (_preservedDataModel != null)
1143 {
1144
1145 _preservedDataModel.setRows(rows);
1146 }
1147 super.setRows(rows);
1148 }
1149
1150 public Object saveState(FacesContext context)
1151 {
1152 boolean preserveSort = isPreserveSort();
1153
1154 Object[] values = new Object[15];
1155 values[0] = super.saveState(context);
1156 values[1] = _preserveDataModel;
1157
1158 if (isPreserveDataModel())
1159 {
1160 _preservedDataModel = getSerializableDataModel();
1161 values[2] = saveAttachedState(context, _preservedDataModel);
1162 }
1163 else
1164 {
1165 values[2] = null;
1166 }
1167 values[3] = _preserveSort;
1168 values[4] = _forceIdIndexFormula;
1169 values[5] = _sortColumn;
1170 values[6] = _sortAscending;
1171 values[7] = _sortProperty;
1172
1173 values[8] = _rowStyleClass;
1174 values[9] = _rowStyle;
1175
1176 values[10] = preserveSort ? getSortColumn() : null;
1177 values[11] = preserveSort ? Boolean.valueOf(isSortAscending()) : null;
1178
1179 values[12] = _varDetailToggler;
1180 values[13] = _expandedNodes;
1181 values[14] = new Integer(_sortColumnIndex);
1182
1183 return values;
1184 }
1185
1186
1187
1188
1189 protected DataModel getDataModel()
1190 {
1191 if (_preservedDataModel != null)
1192 {
1193 setDataModel(_preservedDataModel);
1194 _preservedDataModel = null;
1195 }
1196
1197 return super.getDataModel();
1198 }
1199
1200
1201
1202
1203 protected DataModel createDataModel()
1204 {
1205 DataModel dataModel = super.createDataModel();
1206
1207 boolean isSortable = isSortable();
1208
1209 if (!(dataModel instanceof SortableModel))
1210 {
1211
1212
1213
1214 for (Iterator iter = getChildren().iterator(); iter.hasNext();)
1215 {
1216 UIComponent component = (UIComponent) iter.next();
1217 if (component instanceof HtmlSimpleColumn)
1218 {
1219 HtmlSimpleColumn aColumn = (HtmlSimpleColumn) component;
1220 if (isSortable())
1221 aColumn.setSortable(true);
1222
1223 if (aColumn.isSortable())
1224 isSortable = true;
1225
1226 if (aColumn.isDefaultSorted() && getSortColumn() == null)
1227 setSortProperty(aColumn.getSortPropertyName());
1228 }
1229 }
1230
1231 if (isSortable)
1232 dataModel = new SortableModel(dataModel);
1233 }
1234
1235 if (isSortable && getSortProperty() != null)
1236 {
1237 SortCriterion criterion = new SortCriterion(getSortProperty(), isSortAscending());
1238 List criteria = new ArrayList();
1239 criteria.add(criterion);
1240
1241 ((SortableModel) dataModel).setSortCriteria(criteria);
1242 }
1243
1244 return dataModel;
1245 }
1246
1247 public void restoreState(FacesContext context, Object state)
1248 {
1249 Object[] values = (Object[]) state;
1250 super.restoreState(context, values[0]);
1251 _preserveDataModel = (Boolean) values[1];
1252 if (isPreserveDataModel())
1253 {
1254 _preservedDataModel = (_SerializableDataModel) restoreAttachedState(context, values[2]);
1255 }
1256 else
1257 {
1258 _preservedDataModel = null;
1259 }
1260 _preserveSort = (Boolean) values[3];
1261 _forceIdIndexFormula = (String) values[4];
1262 _sortColumn = (String) values[5];
1263 _sortAscending = (Boolean) values[6];
1264 _sortProperty = (String) values[7];
1265
1266 _rowStyleClass = (String) values[8];
1267 _rowStyle = (String) values[9];
1268
1269 if (isPreserveSort())
1270 {
1271 String sortColumn = (String) values[10];
1272 Boolean sortAscending = (Boolean) values[11];
1273 if (sortColumn != null && sortAscending != null)
1274 {
1275 ValueBinding vb = getValueBinding("sortColumn");
1276 if (vb != null && !vb.isReadOnly(context))
1277 {
1278 vb.setValue(context, sortColumn);
1279 }
1280
1281 vb = getValueBinding("sortAscending");
1282 if (vb != null && !vb.isReadOnly(context))
1283 {
1284 vb.setValue(context, sortAscending);
1285 }
1286 }
1287 }
1288
1289 _varDetailToggler = (String) values[12];
1290 _expandedNodes = (Map) values[13];
1291 _sortColumnIndex = values[14] != null ? ((Integer) values[14]).intValue() : -1;
1292 }
1293
1294 public _SerializableDataModel getSerializableDataModel()
1295 {
1296 DataModel dm = getDataModel();
1297 if (dm instanceof _SerializableDataModel)
1298 {
1299 return (_SerializableDataModel) dm;
1300 }
1301 return createSerializableDataModel();
1302 }
1303
1304
1305
1306
1307 private _SerializableDataModel createSerializableDataModel()
1308 {
1309 Object value = getValue();
1310 if (value == null)
1311 {
1312 return null;
1313 }
1314 else if (value instanceof DataModel)
1315 {
1316 return new _SerializableDataModel(getFirst(), getRows(), (DataModel) value);
1317 }
1318 else if (value instanceof List)
1319 {
1320 return new _SerializableListDataModel(getFirst(), getRows(), (List) value);
1321 }
1322
1323 else if (value instanceof Collection)
1324 {
1325 return new _SerializableListDataModel(getFirst(), getRows(), new ArrayList((Collection) value));
1326 }
1327 else if (OBJECT_ARRAY_CLASS.isAssignableFrom(value.getClass()))
1328 {
1329 return new _SerializableArrayDataModel(getFirst(), getRows(), (Object[]) value);
1330 }
1331 else if (value instanceof ResultSet)
1332 {
1333 return new _SerializableResultSetDataModel(getFirst(), getRows(), (ResultSet) value);
1334 }
1335 else if (value instanceof javax.servlet.jsp.jstl.sql.Result)
1336 {
1337 return new _SerializableResultDataModel(getFirst(), getRows(),
1338 (javax.servlet.jsp.jstl.sql.Result) value);
1339 }
1340 else
1341 {
1342 return new _SerializableScalarDataModel(getFirst(), getRows(), value);
1343 }
1344 }
1345
1346 public boolean isRendered()
1347 {
1348 if (!UserRoleUtils.isVisibleOnUserRole(this))
1349 return false;
1350 return super.isRendered();
1351 }
1352
1353 public void setForceIdIndexFormula(String forceIdIndexFormula)
1354 {
1355 _forceIdIndexFormula = forceIdIndexFormula;
1356 ValueBinding vb = getValueBinding("forceIdIndexFormula");
1357 if (vb != null)
1358 {
1359 vb.setValue(getFacesContext(), _forceIdIndexFormula);
1360 _forceIdIndexFormula = null;
1361 }
1362 }
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373 public String getForceIdIndexFormula()
1374 {
1375 if (_forceIdIndexFormula != null)
1376 return _forceIdIndexFormula;
1377 ValueBinding vb = getValueBinding("forceIdIndexFormula");
1378 if (vb == null)
1379 return null;
1380 Object eval = vb.getValue(getFacesContext());
1381 return eval == null ? null : eval.toString();
1382 }
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397 public void setSortColumn(String sortColumn)
1398 {
1399 _sortColumn = sortColumn;
1400
1401
1402 ValueBinding vb = getValueBinding("sortColumn");
1403 if (vb != null)
1404 {
1405 vb.setValue(getFacesContext(), _sortColumn);
1406 _sortColumn = null;
1407 }
1408
1409 setSortColumnIndex(columnNameToIndex(sortColumn));
1410 }
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423 public String getSortColumn()
1424 {
1425 if (_sortColumn != null) return _sortColumn;
1426 ValueBinding vb = getValueBinding("sortColumn");
1427 return vb != null ? (String) vb.getValue(getFacesContext()) : null;
1428 }
1429
1430 public void setSortAscending(boolean sortAscending)
1431 {
1432 _sortAscending = Boolean.valueOf(sortAscending);
1433
1434
1435 ValueBinding vb = getValueBinding("sortAscending");
1436 if (vb != null)
1437 {
1438 vb.setValue(getFacesContext(), _sortAscending);
1439 _sortAscending = null;
1440 }
1441 }
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455 public boolean isSortAscending()
1456 {
1457 if (_sortAscending != null)
1458 return _sortAscending.booleanValue();
1459 ValueBinding vb = getValueBinding("sortAscending");
1460 Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
1461 return v != null ? v.booleanValue() : DEFAULT_SORTASCENDING;
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475 public void setSortProperty(String sortProperty)
1476 {
1477 _sortProperty = sortProperty;
1478 }
1479
1480
1481
1482
1483
1484
1485 public String getSortProperty()
1486 {
1487 return _sortProperty;
1488 }
1489
1490
1491
1492
1493
1494
1495
1496 public abstract boolean isSortable();
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 public abstract boolean isEmbedded();
1512
1513
1514
1515
1516
1517
1518
1519 public abstract boolean isDetailStampExpandedDefault();
1520
1521
1522
1523
1524
1525
1526
1527
1528 public abstract String getDetailStampLocation();
1529
1530
1531
1532
1533
1534
1535 public abstract String getRowOnMouseOver();
1536
1537
1538
1539
1540
1541
1542 public abstract String getRowOnMouseOut();
1543
1544
1545
1546
1547
1548
1549 public abstract String getRowOnClick();
1550
1551
1552
1553
1554
1555
1556 public abstract String getRowOnDblClick();
1557
1558
1559
1560
1561
1562
1563 public abstract String getRowOnKeyDown();
1564
1565
1566
1567
1568
1569
1570 public abstract String getRowOnKeyPress();
1571
1572
1573
1574
1575
1576
1577 public abstract String getRowOnKeyUp();
1578
1579
1580
1581
1582
1583
1584 public String getRowStyleClass()
1585 {
1586 if (_rowStyleClass != null)
1587 return _rowStyleClass;
1588
1589
1590 ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLECLASS");
1591 if (vb != null)
1592 log.warn("org.apache.myfaces.dataTable.ROW_STYLECLASS is deprecated. Please use rowStyleClass instead.");
1593 else
1594 vb = getValueBinding(JSFAttr.ROW_STYLECLASS_ATTR);
1595 if(vb == null)
1596 return null;
1597 String bindingValue = (String) vb.getValue(getFacesContext());
1598 if(bindingValue == "")
1599 return null;
1600 return bindingValue;
1601 }
1602
1603 public void setRowStyleClass(String rowStyleClass)
1604 {
1605 _rowStyleClass = rowStyleClass;
1606 }
1607
1608
1609
1610
1611
1612
1613 public String getRowStyle()
1614 {
1615 if (_rowStyle != null)
1616 return _rowStyle;
1617
1618
1619 ValueBinding vb = getValueBinding("org.apache.myfaces.dataTable.ROW_STYLE");
1620 if (vb != null)
1621 log.warn("org.apache.myfaces.dataTable.ROW_STYLE is deprecated. Please use rowStyle instead.");
1622 else
1623 vb = getValueBinding(JSFAttr.ROW_STYLE_ATTR);
1624 if(vb == null)
1625 return null;
1626 String bindingValue = (String) vb.getValue(getFacesContext());
1627 if(bindingValue == "")
1628 return null;
1629 return bindingValue;
1630 }
1631
1632 public void setRowStyle(String rowStyle)
1633 {
1634 _rowStyle = rowStyle;
1635 }
1636
1637
1638
1639
1640
1641
1642 public abstract String getRowOnMouseDown();
1643
1644
1645
1646
1647
1648
1649 public abstract String getRowOnMouseMove();
1650
1651
1652
1653
1654
1655
1656 public abstract String getRowOnMouseUp();
1657
1658
1659
1660
1661
1662 protected boolean isValidChildren()
1663 {
1664 return _isValidChildren;
1665 }
1666
1667 protected void setIsValidChildren(boolean isValidChildren)
1668 {
1669 _isValidChildren = isValidChildren;
1670 }
1671
1672 protected _SerializableDataModel getPreservedDataModel()
1673 {
1674 return _preservedDataModel;
1675 }
1676
1677 protected void setPreservedDataModel(_SerializableDataModel preservedDataModel)
1678 {
1679 _preservedDataModel = preservedDataModel;
1680 }
1681
1682
1683 public boolean isCurrentDetailExpanded()
1684 {
1685 Boolean expanded = (Boolean) _expandedNodes.get(getClientId(getFacesContext()));
1686 if (expanded != null)
1687 {
1688 return expanded.booleanValue();
1689 }
1690
1691 return isDetailStampExpandedDefault();
1692 }
1693
1694 public void setVarDetailToggler(String varDetailToggler)
1695 {
1696 _varDetailToggler = varDetailToggler;
1697 }
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707 public String getVarDetailToggler()
1708 {
1709 if (_varDetailToggler != null)
1710 return _varDetailToggler;
1711 ValueBinding vb = getValueBinding("varDetailToggler");
1712 return vb != null ? (String) vb.getValue(getFacesContext()) : null;
1713 }
1714
1715
1716
1717
1718
1719
1720 public abstract String getRowGroupStyle();
1721
1722
1723
1724
1725
1726
1727 public abstract String getRowGroupStyleClass();
1728
1729
1730
1731
1732
1733
1734 public abstract String getBodyStyle();
1735
1736
1737
1738
1739
1740
1741 public abstract String getBodyStyleClass();
1742
1743 public AbstractHtmlDataTable()
1744 {
1745 setRendererType(DEFAULT_RENDERER_TYPE);
1746 }
1747
1748
1749
1750
1751
1752 public void toggleDetail()
1753 {
1754 String derivedRowKey = getClientId(getFacesContext());
1755
1756
1757 boolean expanded = isDetailExpanded();
1758 if (expanded)
1759 {
1760
1761
1762 if (isDetailStampExpandedDefault())
1763 {
1764
1765 _expandedNodes.put(derivedRowKey, Boolean.FALSE);
1766 }
1767 else
1768 {
1769
1770 _expandedNodes.remove(derivedRowKey);
1771 }
1772 }
1773 else
1774 {
1775
1776
1777 if (isDetailStampExpandedDefault())
1778 {
1779
1780 _expandedNodes.remove(derivedRowKey);
1781 }
1782 else
1783 {
1784
1785 _expandedNodes.put(derivedRowKey, Boolean.TRUE);
1786 }
1787 }
1788 }
1789
1790
1791
1792
1793
1794
1795 public boolean isDetailExpanded()
1796 {
1797 Boolean expanded = (Boolean) _expandedNodes.get(getClientId(getFacesContext()));
1798 if (expanded == null)
1799 {
1800 return isDetailStampExpandedDefault();
1801 }
1802
1803 return expanded.booleanValue();
1804 }
1805
1806 public int getSortColumnIndex()
1807 {
1808 if (_sortColumnIndex == -1)
1809 _sortColumnIndex = columnNameToIndex(getSortColumn());
1810
1811 return _sortColumnIndex;
1812 }
1813
1814 public void setSortColumnIndex(int sortColumnIndex)
1815 {
1816 _sortColumnIndex = sortColumnIndex;
1817 }
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827 public abstract int getNewspaperColumns();
1828
1829
1830
1831
1832
1833
1834
1835
1836 public abstract String getNewspaperOrientation();
1837
1838
1839
1840
1841
1842
1843
1844 public UIComponent getSpacer()
1845 {
1846 return (UIComponent) getFacets().get(SPACER_FACET_NAME);
1847 }
1848
1849 public void setSpacer(UIComponent spacer)
1850 {
1851 getFacets().put(SPACER_FACET_NAME, spacer);
1852 }
1853
1854
1855
1856
1857 public void expandAllDetails()
1858 {
1859 int rowCount = getRowCount();
1860
1861 _expandedNodes.clear();
1862
1863 if (getRowKey() != null)
1864 {
1865 int oldRow = getRowIndex();
1866 try
1867 {
1868 for (int row = 0; row < rowCount; row++)
1869 {
1870 setRowIndex(row);
1871 _expandedNodes.put(getClientId(getFacesContext()), Boolean.TRUE);
1872 }
1873 }
1874 finally
1875 {
1876 setRowIndex(oldRow);
1877 }
1878 }
1879 else
1880 {
1881 for (int row = 0; row < rowCount; row++)
1882 {
1883 _expandedNodes.put(new Integer(row).toString(), Boolean.TRUE);
1884 }
1885 }
1886 }
1887
1888
1889
1890
1891 public void collapseAllDetails()
1892 {
1893 _expandedNodes.clear();
1894 }
1895
1896
1897
1898
1899 public boolean isExpandedEmpty()
1900 {
1901 boolean expandedEmpty = true;
1902 if (_expandedNodes != null)
1903 {
1904 expandedEmpty = _expandedNodes.isEmpty();
1905 }
1906 return expandedEmpty;
1907 }
1908
1909
1910
1911
1912
1913
1914 public void setExpandedEmpty(boolean expandedEmpty)
1915 {
1916 if (expandedEmpty)
1917 {
1918 if (_expandedNodes != null)
1919 {
1920 _expandedNodes.clear();
1921 }
1922 }
1923 }
1924
1925
1926
1927 public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlDataTable";
1928 public static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.Table";
1929
1930 private static final boolean DEFAULT_PRESERVEDATAMODEL = false;
1931 private static final boolean DEFAULT_PRESERVESORT = true;
1932 private static final boolean DEFAULT_RENDEREDIFEMPTY = true;
1933
1934 private Boolean _preserveDataModel = null;
1935 private Boolean _preserveSort = null;
1936
1937 public void setPreserveDataModel(boolean preserveDataModel)
1938 {
1939 _preserveDataModel = Boolean.valueOf(preserveDataModel);
1940 }
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956 public boolean isPreserveDataModel()
1957 {
1958 if (_preserveDataModel != null)
1959 return _preserveDataModel.booleanValue();
1960 ValueBinding vb = getValueBinding("preserveDataModel");
1961 Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
1962 return v != null ? v.booleanValue() : DEFAULT_PRESERVEDATAMODEL;
1963 }
1964
1965 public void setPreserveSort(boolean preserveSort)
1966 {
1967 _preserveSort = Boolean.valueOf(preserveSort);
1968 }
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978 public boolean isPreserveSort()
1979 {
1980 if (_preserveSort != null)
1981 return _preserveSort.booleanValue();
1982 ValueBinding vb = getValueBinding("preserveSort");
1983 Boolean v = vb != null ? (Boolean) vb.getValue(getFacesContext()) : null;
1984 return v != null ? v.booleanValue() : DEFAULT_PRESERVESORT;
1985 }
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002 public abstract boolean isRenderedIfEmpty();
2003
2004
2005
2006
2007
2008
2009
2010 public abstract String getRowIndexVar();
2011
2012
2013
2014
2015
2016
2017
2018 public abstract String getRowCountVar();
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029 public abstract String getPreviousRowDataVar();
2030
2031
2032
2033
2034
2035
2036
2037
2038 public abstract String getSortedColumnVar();
2039
2040
2041
2042
2043
2044
2045
2046 public abstract String getAlign();
2047
2048
2049
2050
2051
2052
2053 public abstract String getRowId();
2054
2055
2056
2057
2058
2059
2060 public abstract String getDatafld();
2061
2062
2063
2064
2065
2066
2067 public abstract String getDatasrc();
2068
2069
2070
2071
2072
2073
2074 public abstract String getDataformatas();
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084 public abstract String getValueType();
2085
2086 }