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