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