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