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