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