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