001 package org.apache.myfaces.tobago.component;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_COLUMNS;
023 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DIRECT_LINK_COUNT;
024 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_FIRST;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_WIDTH;
026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_WIDTH;
027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ROWS;
028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SELECTABLE;
029 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SELECTED_LIST_STRING;
030 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SHOW_DIRECT_LINKS;
031 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SHOW_HEADER;
032 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SHOW_PAGE_RANGE;
033 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SHOW_ROW_RANGE;
034 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STATE;
035 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH_LIST_STRING;
036 import static org.apache.myfaces.tobago.TobagoConstants.FACET_RELOAD;
037 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_OUT;
038 import org.apache.myfaces.tobago.ajax.api.AjaxComponent;
039 import org.apache.myfaces.tobago.ajax.api.AjaxPhaseListener;
040 import org.apache.myfaces.tobago.ajax.api.AjaxUtils;
041 import org.apache.myfaces.tobago.event.PageActionEvent;
042 import org.apache.myfaces.tobago.event.SheetStateChangeEvent;
043 import org.apache.myfaces.tobago.event.SheetStateChangeListener;
044 import org.apache.myfaces.tobago.event.SheetStateChangeSource;
045 import org.apache.myfaces.tobago.event.SortActionEvent;
046 import org.apache.myfaces.tobago.event.SortActionSource;
047 import org.apache.myfaces.tobago.model.SheetState;
048 import org.apache.myfaces.tobago.renderkit.LayoutInformationProvider;
049 import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase;
050 import org.apache.myfaces.tobago.renderkit.SheetRendererWorkaround;
051 import org.apache.myfaces.tobago.util.LayoutInfo;
052 import org.apache.myfaces.tobago.util.LayoutUtil;
053 import org.apache.myfaces.tobago.util.StringUtils;
054
055 import javax.faces.component.UIColumn;
056 import javax.faces.component.UIComponent;
057 import javax.faces.context.FacesContext;
058 import javax.faces.el.EvaluationException;
059 import javax.faces.el.MethodBinding;
060 import javax.faces.el.ValueBinding;
061 import javax.faces.event.AbortProcessingException;
062 import javax.faces.event.FacesEvent;
063 import javax.faces.event.PhaseId;
064 import javax.servlet.http.HttpServletResponse;
065 import java.io.IOException;
066 import java.util.ArrayList;
067 import java.util.List;
068 import java.util.Map;
069
070 public class UIData extends javax.faces.component.UIData
071 implements SheetStateChangeSource, SortActionSource, AjaxComponent {
072
073 private static final Log LOG = LogFactory.getLog(UIData.class);
074
075 public static final String COMPONENT_TYPE = "org.apache.myfaces.tobago.Data";
076
077 public static final String FACET_SORTER = "sorter";
078 public static final String SORTER_ID = "sorter";
079 public static final String ATTR_SCROLL_POSITION = "attrScrollPosition";
080
081 public static final String NONE = "none";
082 public static final String SINGLE = "single";
083 public static final String MULTI = "multi";
084 public static final int DEFAULT_DIRECT_LINK_COUNT = 9;
085 public static final int DEFAULT_ROW_COUNT = 100;
086 private static final String DEFAULT_SELECTABLE = MULTI;
087
088 private MethodBinding stateChangeListener;
089 private List<Integer> widthList;
090 private MethodBinding sortActionListener;
091 private SheetState sheetState;
092 private Boolean showHeader;
093 private String showRowRange;
094 private String showPageRange;
095 private String showDirectLinks;
096 private String columns;
097 private Integer directLinkCount;
098 private Integer rows;
099
100 private String selectable;
101
102 private transient LayoutTokens columnLayout;
103
104 public void encodeBegin(FacesContext facesContext) throws IOException {
105 UILayout.prepareDimension(facesContext, this);
106 SheetState state = getSheetState(facesContext);
107 if (state.getFirst() > -1 && state.getFirst() < getRowCount()) {
108 ValueBinding valueBinding = getValueBinding(ATTR_FIRST);
109 if (valueBinding != null) {
110 valueBinding.setValue(facesContext, state.getFirst());
111 } else {
112 setFirst(state.getFirst());
113 }
114 }
115 super.encodeBegin(facesContext);
116 }
117
118 public void encodeEnd(FacesContext facesContext) throws IOException {
119 setupState(facesContext);
120 prepareDimensions(facesContext);
121 super.encodeEnd(facesContext);
122 }
123
124 public void processDecodes(FacesContext context) {
125 final String ajaxId = (String) context.getExternalContext()
126 .getRequestParameterMap().get(AjaxPhaseListener.AJAX_COMPONENT_ID);
127 if (ajaxId !=null && ajaxId.equals(getClientId(context))) {
128 if (getFacet(FACET_RELOAD) != null && getFacet(FACET_RELOAD) instanceof UIReload
129 && getFacet(FACET_RELOAD).isRendered()
130 && ((UIReload) getFacet(FACET_RELOAD)).isImmediate()
131 && ajaxId.equals(ComponentUtil.findPage(context, this).getActionId())) {
132 UIReload reload = (UIReload) getFacet(FACET_RELOAD);
133 if (!reload.getUpdate()) {
134 if (context.getExternalContext().getResponse() instanceof HttpServletResponse) {
135 ((HttpServletResponse) context.getExternalContext().getResponse())
136 .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
137 }
138 context.responseComplete();
139 return;
140 }
141 }
142 }
143 super.processDecodes(context);
144 }
145
146 public String getShowRowRange() {
147 if (showRowRange != null) {
148 return showRowRange;
149 }
150 ValueBinding vb = getValueBinding(ATTR_SHOW_ROW_RANGE);
151 if (vb != null) {
152 return (String) vb.getValue(getFacesContext());
153 } else {
154 return NONE;
155 }
156 }
157
158 public void setShowRowRange(String showRowRange) {
159 this.showRowRange = showRowRange;
160 }
161
162 public String getShowPageRange() {
163 if (showPageRange != null) {
164 return showPageRange;
165 }
166 ValueBinding vb = getValueBinding(ATTR_SHOW_PAGE_RANGE);
167 if (vb != null) {
168 return (String) vb.getValue(getFacesContext());
169 } else {
170 return NONE;
171 }
172 }
173
174 public void setShowPageRange(String showPageRange) {
175 this.showPageRange = showPageRange;
176 }
177
178 public String getColumns() {
179 if (columns != null) {
180 return columns;
181 }
182 ValueBinding vb = getValueBinding(ATTR_COLUMNS);
183 if (vb != null) {
184 return (String) vb.getValue(getFacesContext());
185 } else {
186 return null;
187 }
188 }
189
190 public void setColumns(String columns) {
191 this.columns = columns;
192 }
193
194 public String getShowDirectLinks() {
195 if (showDirectLinks != null) {
196 return showDirectLinks;
197 }
198 ValueBinding vb = getValueBinding(ATTR_SHOW_DIRECT_LINKS);
199 if (vb != null) {
200 return (String) vb.getValue(getFacesContext());
201 } else {
202 return NONE;
203 }
204 }
205
206 public void setShowDirectLinks(String showDirectLinks) {
207 this.showDirectLinks = showDirectLinks;
208 }
209
210 public String getSelectable() {
211 if (selectable != null) {
212 return selectable;
213 }
214 ValueBinding vb = getValueBinding(ATTR_SELECTABLE);
215 if (vb != null) {
216 return (String) vb.getValue(getFacesContext());
217 } else {
218 return DEFAULT_SELECTABLE;
219 }
220 }
221
222 public void setSelectable(String selectable) {
223 this.selectable = selectable;
224 }
225
226 public Integer getDirectLinkCount() {
227 if (directLinkCount != null) {
228 return directLinkCount;
229 }
230 ValueBinding vb = getValueBinding(ATTR_DIRECT_LINK_COUNT);
231 if (vb != null) {
232 return (Integer) vb.getValue(getFacesContext());
233 } else {
234 return DEFAULT_DIRECT_LINK_COUNT;
235 }
236 }
237
238 public void setDirectLinkCount(Integer directLinkCount) {
239 this.directLinkCount = directLinkCount;
240 }
241
242 private void setupState(FacesContext facesContext) {
243 SheetState state = getSheetState(facesContext);
244 ensureColumnWidthList(facesContext, state);
245 }
246
247 public void setState(SheetState state) {
248 this.sheetState = state;
249 }
250
251 public SheetState getSheetState(FacesContext facesContext) {
252 if (sheetState != null) {
253 return sheetState;
254 } else {
255 ValueBinding stateBinding = getValueBinding(ATTR_STATE);
256 if (stateBinding != null) {
257 SheetState state = (SheetState) stateBinding.getValue(facesContext);
258 if (state == null) {
259 state = new SheetState();
260 stateBinding.setValue(facesContext, state);
261 }
262 return state;
263 } else {
264 sheetState = new SheetState();
265 return sheetState;
266 }
267 }
268 }
269
270 public LayoutTokens getColumnLayout() {
271 if (columnLayout == null) {
272 String columns = getColumns();
273 if (columns != null) {
274 columnLayout = LayoutTokens.parse(columns);
275 }
276 }
277 return columnLayout;
278 }
279
280 private void ensureColumnWidthList(FacesContext facesContext, SheetState state) {
281 List<Integer> currentWidthList = null;
282 List<UIColumn> rendererdColumns = getRenderedColumns();
283
284 final Map attributes = getAttributes();
285 String widthListString = null;
286
287 if (state != null) {
288 widthListString = state.getColumnWidths();
289 }
290 if (widthListString == null) {
291 widthListString = (String) attributes.get(ATTR_WIDTH_LIST_STRING);
292 }
293
294 if (widthListString != null) {
295 currentWidthList = StringUtils.parseIntegerList(widthListString);
296 }
297 if (currentWidthList != null && currentWidthList.size() != rendererdColumns.size()) {
298 currentWidthList = null;
299 }
300
301
302 if (currentWidthList == null) {
303 LayoutTokens tokens = getColumnLayout();
304 List<UIColumn> allColumns = getAllColumns();
305 LayoutTokens newTokens = new LayoutTokens();
306 if (allColumns.size() > 0) {
307 for (int i = 0; i < allColumns.size(); i++) {
308 UIColumn column = allColumns.get(i);
309 if (column.isRendered()) {
310 if (tokens == null) {
311 if (column instanceof org.apache.myfaces.tobago.component.UIColumn) {
312 newTokens.addToken(
313 LayoutTokens.parseToken(((org.apache.myfaces.tobago.component.UIColumn) column).getWidth()));
314 } else {
315 newTokens.addToken(RelativeLayoutToken.DEFAULT_INSTANCE);
316 }
317 } else {
318 if (i < tokens.getSize()) {
319 newTokens.addToken(tokens.get(i));
320 } else {
321 newTokens.addToken(RelativeLayoutToken.DEFAULT_INSTANCE);
322 }
323 }
324 }
325 }
326 }
327
328
329 int space = LayoutUtil.getInnerSpace(facesContext, this, true);
330 SheetRendererWorkaround renderer
331 = (SheetRendererWorkaround) ComponentUtil.getRenderer(facesContext, this);
332 space -= renderer.getContentBorder(facesContext, this);
333 if (renderer.needVerticalScrollbar(facesContext, this)) {
334 space -= renderer.getScrollbarWidth(facesContext, this);
335 }
336 LayoutInfo layoutInfo = new LayoutInfo(newTokens.getSize(), space, newTokens, getClientId(facesContext), false);
337 parseFixedWidth(facesContext, layoutInfo, rendererdColumns);
338 layoutInfo.parseColumnLayout(space);
339 currentWidthList = layoutInfo.getSpaceList();
340 }
341
342 if (currentWidthList != null) {
343 if (rendererdColumns.size() != currentWidthList.size()) {
344 LOG.warn("widthList.size() = " + currentWidthList.size()
345 + " != columns.size() = " + rendererdColumns.size() + " widthList : "
346 + LayoutInfo.listToTokenString(currentWidthList));
347 } else {
348 this.widthList = currentWidthList;
349 }
350 }
351 }
352
353 private void parseFixedWidth(FacesContext facesContext, LayoutInfo layoutInfo, List<UIColumn> rendereredColumns) {
354 LayoutTokens tokens = layoutInfo.getLayoutTokens();
355 for (int i = 0; i < tokens.getSize(); i++) {
356 LayoutToken token = tokens.get(i);
357 if (token instanceof FixedLayoutToken) {
358 int width = 0;
359 if (!rendereredColumns.isEmpty()) {
360 if (i < rendereredColumns.size()) {
361 UIColumn column = rendereredColumns.get(i);
362 if (column instanceof UIColumnSelector) {
363 LayoutInformationProvider renderer
364 = ComponentUtil.getRenderer(facesContext, column);
365 if (renderer == null) {
366 LOG.warn("can't find renderer for " + column.getClass().getName());
367 renderer = ComponentUtil.getRenderer(facesContext, UIPanel.COMPONENT_FAMILY, RENDERER_TYPE_OUT);
368 }
369 width = renderer.getFixedWidth(facesContext, column);
370
371 } else {
372 for (UIComponent component : (List<UIComponent>) column.getChildren()) {
373 LayoutInformationProvider renderer
374 = ComponentUtil.getRenderer(facesContext, component);
375 width += renderer.getFixedWidth(facesContext, component);
376 }
377 }
378 layoutInfo.update(width, i);
379 } else {
380 layoutInfo.update(0, i);
381 if (LOG.isWarnEnabled()) {
382 LOG.warn("More LayoutTokens found than rows! skipping!");
383 }
384 }
385 }
386 if (LOG.isDebugEnabled()) {
387 LOG.debug("set column " + i + " from fixed to with " + width);
388 }
389 }
390 }
391 }
392
393
394 private void prepareDimensions(FacesContext facesContext) {
395 // prepare width's in column's children components
396
397 List<Integer> columnWidths = getWidthList();
398 int i = 0;
399 for (UIColumn column : getRenderedColumns()) {
400 if (i < columnWidths.size()) {
401 Integer width = columnWidths.get(i);
402 if (!(column instanceof UIColumnSelector)) {
403 if (column.getChildCount() == 1) {
404 UIComponent child = (UIComponent) column.getChildren().get(0);
405 int cellPaddingWidth = ((LayoutableRendererBase) getRenderer(facesContext))
406 .getConfiguredValue(facesContext, this, "cellPaddingWidth");
407 child.getAttributes().put(
408 ATTR_LAYOUT_WIDTH, width - cellPaddingWidth);
409 child.getAttributes().remove(ATTR_INNER_WIDTH);
410 } else {
411 LOG.warn("More or less than 1 child in column! "
412 + "Can't set width for column " + i + " to " + width);
413 }
414 }
415 } else {
416 LOG.warn("More columns than columnSizes! "
417 + "Can't set width for column " + i);
418 }
419 i++;
420 }
421 }
422
423 public int getLast() {
424 int last = getFirst() + getRows();
425 return last < getRowCount() ? last : getRowCount();
426 }
427
428 public int getPage() {
429 int first = getFirst() + 1;
430 int rows = getRows();
431 if (rows == 0) {
432 // avoid division by zero
433 return 0;
434 }
435 if ((first % rows) > 0) {
436 return (first / rows) + 1;
437 } else {
438 return (first / rows);
439 }
440 }
441
442 public int getPages() {
443 int rows = getRows();
444 if (rows == 0) {
445 return 0;
446 }
447 return getRowCount() / rows + (getRowCount() % rows == 0 ? 0 : 1);
448 }
449
450 public List<UIComponent> getRenderedChildrenOf(UIColumn column) {
451 List<UIComponent> children = new ArrayList<UIComponent>();
452 for (Object o : column.getChildren()) {
453 UIComponent kid = (UIComponent) o;
454 if (kid.isRendered()) {
455 children.add(kid);
456 }
457 }
458 return children;
459 }
460
461 public boolean isAtBeginning() {
462 return getFirst() == 0;
463 }
464
465 public boolean hasRowCount() {
466 return getRowCount() != -1;
467 }
468
469 public boolean isAtEnd() {
470 if (!hasRowCount()) {
471 setRowIndex(getFirst() + getRows() + 1);
472 return !isRowAvailable();
473 } else {
474 return getFirst() >= getLastPageIndex();
475 }
476 }
477
478 public int getLastPageIndex() {
479 int rows = getRows();
480 if (rows == 0) {
481 // avoid division by zero
482 return 0;
483 }
484 int rowCount = getRowCount();
485 int tail = rowCount % rows;
486 return rowCount - (tail != 0 ? tail : rows);
487 }
488
489 public void processUpdates(FacesContext context) {
490 super.processUpdates(context);
491 updateSheetState(context);
492 }
493
494 private void updateSheetState(FacesContext facesContext) {
495 SheetState state = getSheetState(facesContext);
496 if (state != null) {
497 // ensure sortActionListener
498 // getSortActionListener();
499 // state.setSortedColumn(sortActionListener != null ? sortActionListener.getColumn() : -1);
500 // state.setAscending(sortActionListener != null && sortActionListener.isAscending());
501 Map attributes = getAttributes();
502 //noinspection unchecked
503 state.setSelectedRows((List<Integer>) attributes.get(ATTR_SELECTED_LIST_STRING));
504 state.setColumnWidths((String) attributes.get(ATTR_WIDTH_LIST_STRING));
505 state.setScrollPosition((Integer[]) attributes.get(ATTR_SCROLL_POSITION));
506 attributes.remove(ATTR_SELECTED_LIST_STRING);
507 attributes.remove(ATTR_SCROLL_POSITION);
508 }
509 }
510
511
512 public Object saveState(FacesContext context) {
513 Object[] saveState = new Object[12];
514 saveState[0] = super.saveState(context);
515 saveState[1] = sheetState;
516 saveState[2] = saveAttachedState(context, sortActionListener);
517 saveState[3] = saveAttachedState(context, stateChangeListener);
518 saveState[4] = showHeader;
519 saveState[5] = showRowRange;
520 saveState[6] = showPageRange;
521 saveState[7] = showDirectLinks;
522 saveState[8] = directLinkCount;
523 saveState[9] = selectable;
524 saveState[10] = columns;
525 saveState[11] = rows;
526 return saveState;
527 }
528
529 public void restoreState(FacesContext context, Object savedState) {
530 Object[] values = (Object[]) savedState;
531 super.restoreState(context, values[0]);
532 sheetState = (SheetState) values[1];
533 sortActionListener = (MethodBinding) restoreAttachedState(context, values[2]);
534 stateChangeListener = (MethodBinding) restoreAttachedState(context, values[3]);
535 showHeader = (Boolean) values[4];
536 showRowRange = (String) values[5];
537 showPageRange = (String) values[6];
538 showDirectLinks = (String) values[7];
539 directLinkCount = (Integer) values[8];
540 selectable = (String) values[9];
541 columns = (String) values[10];
542 rows = (Integer) values[11];
543 }
544
545
546 public List<UIColumn> getAllColumns() {
547 List<UIColumn> columns = new ArrayList<UIColumn>();
548 for (UIComponent kid : (List<UIComponent>) getChildren()) {
549 if (kid instanceof UIColumn && !(kid instanceof UIColumnEvent)) {
550 columns.add((UIColumn) kid);
551 }
552 }
553 return columns;
554 }
555
556 public List<UIColumn> getRenderedColumns() {
557 List<UIColumn> columns = new ArrayList<UIColumn>();
558 for (UIComponent kid : (List<UIComponent>) getChildren()) {
559 if (kid instanceof UIColumn && kid.isRendered() && !(kid instanceof UIColumnEvent)) {
560 columns.add((UIColumn) kid);
561 }
562 }
563 return columns;
564 }
565
566 public MethodBinding getSortActionListener() {
567 if (sortActionListener != null) {
568 return sortActionListener;
569 } else {
570 return new Sorter();
571 }
572 }
573
574 public void setSortActionListener(MethodBinding sortActionListener) {
575 this.sortActionListener = sortActionListener;
576 }
577
578 public void queueEvent(FacesEvent facesEvent) {
579 UIComponent parent = getParent();
580 if (parent == null) {
581 throw new IllegalStateException(
582 "component is not a descendant of a UIViewRoot");
583 }
584
585 if (facesEvent.getComponent() == this
586 && (facesEvent instanceof SheetStateChangeEvent
587 || facesEvent instanceof PageActionEvent)) {
588 facesEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
589 if (LOG.isInfoEnabled()) {
590 LOG.info("queueEvent = \"" + facesEvent + "\"");
591 }
592 parent.queueEvent(facesEvent);
593 } else {
594 UIComponent source = facesEvent.getComponent();
595 UIComponent sourceParent = source.getParent();
596 if (sourceParent.getParent() == this
597 && source.getId() != null && source.getId().endsWith(SORTER_ID)) {
598 facesEvent.setPhaseId(PhaseId.INVOKE_APPLICATION);
599 parent.queueEvent(new SortActionEvent(this, (UIColumn) sourceParent));
600 } else {
601 super.queueEvent(facesEvent);
602 }
603 }
604 }
605
606 public void broadcast(FacesEvent facesEvent) throws AbortProcessingException {
607 super.broadcast(facesEvent);
608 if (facesEvent instanceof SheetStateChangeEvent) {
609 invokeMethodBinding(getStateChangeListener(), facesEvent);
610 } else if (facesEvent instanceof PageActionEvent) {
611 invokeMethodBinding(new Pager(), facesEvent);
612 invokeMethodBinding(getStateChangeListener(), new SheetStateChangeEvent(this));
613 } else if (facesEvent instanceof SortActionEvent) {
614 getSheetState(getFacesContext()).updateSortState((SortActionEvent) facesEvent);
615 invokeMethodBinding(getSortActionListener(), facesEvent);
616 }
617 }
618
619 private void invokeMethodBinding(MethodBinding methodBinding, FacesEvent event) {
620 if (methodBinding != null && event != null) {
621 try {
622 Object[] objects = new Object[]{event};
623 methodBinding.invoke(getFacesContext(), objects);
624 } catch (EvaluationException e) {
625 Throwable cause = e.getCause();
626 if (cause instanceof AbortProcessingException) {
627 throw (AbortProcessingException) cause;
628 } else {
629 throw e;
630 }
631 }
632 }
633 }
634
635 public void addStateChangeListener(SheetStateChangeListener listener) {
636 addFacesListener(listener);
637 }
638
639 public SheetStateChangeListener[] getStateChangeListeners() {
640 return (SheetStateChangeListener[]) getFacesListeners(SheetStateChangeListener.class);
641 }
642
643 public void removeStateChangeListener(SheetStateChangeListener listener) {
644 removeFacesListener(listener);
645 }
646
647 public MethodBinding getStateChangeListener() {
648 return stateChangeListener;
649 }
650
651 public void setStateChangeListener(MethodBinding stateChangeListener) {
652 this.stateChangeListener = stateChangeListener;
653 }
654
655 public List<Integer> getWidthList() {
656 return widthList;
657 }
658
659 public int getRows() {
660 if (rows != null) {
661 return rows;
662 }
663 ValueBinding vb = getValueBinding(ATTR_ROWS);
664 if (vb != null) {
665 return (Integer) vb.getValue(getFacesContext());
666 } else {
667 return DEFAULT_ROW_COUNT;
668 }
669 }
670
671 public void setRows(int rows) {
672 this.rows = rows;
673 }
674
675 public boolean isShowHeader() {
676 if (showHeader != null) {
677 return showHeader;
678 }
679 ValueBinding vb = getValueBinding(ATTR_SHOW_HEADER);
680 if (vb != null) {
681 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext())));
682 } else {
683 return true;
684 }
685 }
686
687 public void setShowHeader(boolean showHeader) {
688 this.showHeader = showHeader;
689 }
690
691 public void encodeAjax(FacesContext facesContext) throws IOException {
692 setupState(facesContext);
693 prepareDimensions(facesContext);
694 // TODO neets more testing!!!
695 //if (!facesContext.getRenderResponse() && !ComponentUtil.hasErrorMessages(facesContext)) {
696 // in encodeBegin of superclass is some logic which clears the DataModel
697 // this must here also done.
698 // in RI and myfaces this could done via setValue(null)
699 ValueBinding binding = getValueBinding("value");
700 if (binding != null) {
701 setValue(null);
702 } else {
703 setValue(getValue());
704 }
705 //}
706 AjaxUtils.encodeAjaxComponent(facesContext, this);
707 }
708
709 public void processAjax(FacesContext facesContext) throws IOException {
710 final String ajaxId = (String) facesContext.getExternalContext()
711 .getRequestParameterMap().get(AjaxPhaseListener.AJAX_COMPONENT_ID);
712 if (ajaxId.equals(getClientId(facesContext))) {
713 AjaxUtils.processActiveAjaxComponent(facesContext, this);
714 } else {
715 AjaxUtils.processAjaxOnChildren(facesContext, this);
716 }
717 }
718
719 public Integer[] getScrollPosition() {
720 Integer[] scrollPosition = (Integer[]) getAttributes().get(ATTR_SCROLL_POSITION);
721 if (scrollPosition == null) {
722 scrollPosition = getSheetState(FacesContext.getCurrentInstance()).getScrollPosition();
723 }
724 return scrollPosition;
725 }
726
727 public UIComponent findComponent(String searchId) {
728 return super.findComponent(stripRowIndex(searchId));
729 }
730
731 String stripRowIndex(String searchId) {
732 if (searchId.length() > 0 && Character.isDigit(searchId.charAt(0))) {
733 for (int i = 1; i < searchId.length(); ++i) {
734 char c = searchId.charAt(i);
735 if (c == SEPARATOR_CHAR) {
736 searchId = searchId.substring(i + 1);
737 break;
738 }
739 if (!Character.isDigit(c)) {
740 break;
741 }
742 }
743 }
744 return searchId;
745 }
746 }