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