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