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 }