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