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