Source Code Cross Referenced for TableRowGroup.java in  » IDE-Netbeans » visualweb.api.designer » com » sun » rave » web » ui » component » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » visualweb.api.designer » com.sun.rave.web.ui.component 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package com.sun.rave.web.ui.component;
0042:
0043:        import com.sun.data.provider.FieldKey;
0044:        import com.sun.data.provider.RowKey;
0045:        import com.sun.data.provider.FilterCriteria;
0046:        import com.sun.data.provider.SortCriteria;
0047:        import com.sun.data.provider.TableDataFilter;
0048:        import com.sun.data.provider.TableDataProvider;
0049:        import com.sun.data.provider.TableDataSorter;
0050:        import com.sun.data.provider.impl.BasicTableDataFilter;
0051:        import com.sun.data.provider.impl.BasicTableDataSorter;
0052:        import com.sun.data.provider.impl.ObjectListDataProvider;
0053:        import com.sun.data.provider.impl.ObjectArrayDataProvider;
0054:        import com.sun.data.provider.impl.TableRowDataProvider;
0055:        import com.sun.rave.web.ui.theme.Theme;
0056:        import com.sun.rave.web.ui.theme.ThemeImages;
0057:        import com.sun.rave.web.ui.theme.ThemeStyles;
0058:        import com.sun.rave.web.ui.util.ConversionUtilities;
0059:        import com.sun.rave.web.ui.util.LogUtil;
0060:        import com.sun.rave.web.ui.util.ThemeUtilities;
0061:
0062:        import java.beans.Beans;
0063:        import java.io.IOException;
0064:        import java.io.Serializable;
0065:        import java.util.ArrayList;
0066:        import java.util.HashMap;
0067:        import java.util.Iterator;
0068:        import java.util.List;
0069:        import java.util.Map;
0070:
0071:        import javax.faces.application.FacesMessage;
0072:        import javax.faces.context.FacesContext;
0073:        import javax.faces.component.EditableValueHolder;
0074:        import javax.faces.component.NamingContainer;
0075:        import javax.faces.component.UIComponent;
0076:        import javax.faces.component.UIComponentBase;
0077:        import javax.faces.component.UIViewRoot;
0078:        import javax.faces.el.ValueBinding;
0079:        import javax.faces.event.AbortProcessingException;
0080:        import javax.faces.event.FacesEvent;
0081:        import javax.faces.event.FacesListener;
0082:        import javax.faces.event.PhaseId;
0083:
0084:        /**
0085:         * Component that represents a group of table rows.
0086:         * <p>
0087:         * The TableRowGroup component provides a layout mechanism for displaying rows 
0088:         * of data. UI guidelines describe specific behavior that can applied to the 
0089:         * rows and columns of data such as sorting, filtering, pagination, selection, 
0090:         * and custom user actions. In addition, UI guidelines also define sections of 
0091:         * the table that can be used for titles, row group headers, and placement of 
0092:         * pre-defined and user defined actions.
0093:         * </p><p>
0094:         * The TableRowGroup component supports a data binding to a collection of data 
0095:         * objects represented by a TableDataProvider instance, which is the 
0096:         * current value of this component itself. During iterative processing over the
0097:         * rows of data in the data provider, the TableDataProvider for the current row 
0098:         * is exposed as a request attribute under the key specified by the 
0099:         * var property.
0100:         * </p><p>
0101:         * Only children of type TableColumn should be processed by renderers associated
0102:         * with this component.
0103:         * </p><p>
0104:         * Note: Column headers and footers are rendered by TableRowGroupRenderer. Table
0105:         * column footers are rendered by TableRenderer.
0106:         * </p><p>
0107:         * Note: To see the messages logged by this class, set the following global
0108:         * defaults in your JDK's "jre/lib/logging.properties" file.
0109:         * </p><p><pre>
0110:         * java.util.logging.ConsoleHandler.level = FINE
0111:         * com.sun.rave.web.ui.component.TableRowGroup.level = FINE
0112:         * </pre></p><p>
0113:         * See TLD docs for more information.
0114:         * </p>
0115:         */
0116:        public class TableRowGroup extends TableRowGroupBase implements 
0117:                NamingContainer {
0118:            /** The id for the column footer bar. */
0119:            public static final String COLUMN_FOOTER_BAR_ID = "_columnFooterBar"; //NOI18N
0120:
0121:            /** The id for the column header bar. */
0122:            public static final String COLUMN_HEADER_BAR_ID = "_columnHeaderBar"; //NOI18N
0123:
0124:            /** The component id for the empty data column. */
0125:            public static final String EMPTY_DATA_COLUMN_ID = "_emptyDataColumn"; //NOI18N
0126:
0127:            /** The facet name for the empty data column. */
0128:            public static final String EMPTY_DATA_COLUMN_FACET = "emptyDataColumn"; //NOI18N
0129:
0130:            /** The component id for the empty data text. */
0131:            public static final String EMPTY_DATA_TEXT_ID = "_emptyDataText"; //NOI18N
0132:
0133:            /** The facet name for the empty data text. */
0134:            public static final String EMPTY_DATA_TEXT_FACET = "emptyDataText"; //NOI18N
0135:
0136:            /** The facet name for the group footer area. */
0137:            public static final String FOOTER_FACET = "footer"; //NOI18N
0138:
0139:            /** The id for the group footer bar. */
0140:            public static final String GROUP_FOOTER_BAR_ID = "_groupFooterBar"; //NOI18N
0141:
0142:            /** The component id for the group footer. */
0143:            public static final String GROUP_FOOTER_ID = "_groupFooter"; //NOI18N
0144:
0145:            /** The facet name for the group footer. */
0146:            public static final String GROUP_FOOTER_FACET = "groupFooter"; //NOI18N
0147:
0148:            /** The id for the table row group header bar. */
0149:            public static final String GROUP_HEADER_BAR_ID = "_groupHeaderBar"; //NOI18N
0150:
0151:            /** The component id for the table row group header. */
0152:            public static final String GROUP_HEADER_ID = "_groupHeader"; //NOI18N
0153:
0154:            /** The facet name for the table row group header. */
0155:            public static final String GROUP_HEADER_FACET = "groupHeader"; //NOI18N
0156:
0157:            /** The facet name for the group header area. */
0158:            public static final String HEADER_FACET = "header"; //NOI18N
0159:
0160:            /** The id for the table column footers bar. */
0161:            public static final String TABLE_COLUMN_FOOTER_BAR_ID = "_tableColumnFooterBar"; //NOI18N
0162:
0163:            // Key prefix for properties cached in the request map.
0164:            private static final String REQUEST_KEY_PREFIX = "com.sun.rave.web.ui_"; //NOI18N
0165:
0166:            // Key for properties cached in the request map.
0167:            private static final String PROPERTIES = "_properties"; //NOI18N
0168:
0169:            // This map contains SavedState instances for each descendant
0170:            // component, keyed by the client identifier of the descendant. Because
0171:            // descendant client identifiers will contain the RowKey value of the
0172:            // parent, per-row state information is actually preserved.
0173:            private Map saved = new HashMap();
0174:
0175:            // TableDataFilter object used to apply filter. This object is not part of
0176:            // the saved and restored state of the component.
0177:            private transient TableDataFilter filter = null;
0178:
0179:            // TableDataSorter object used to apply sort. This object is not part of
0180:            // the saved and restored state of the component.
0181:            private transient TableDataSorter sorter = null;
0182:
0183:            // Flag indicating paginated state.
0184:            private boolean paginated = false;
0185:            private boolean paginated_set = false;
0186:
0187:            // The TableRowDataProvider associated with this component, lazily
0188:            // instantiated if requested. This object is not part of the saved and
0189:            // restored state of the component.
0190:            private TableRowDataProvider provider = null;
0191:
0192:            // The Table ancestor enclosing this component.
0193:            private Table table = null;
0194:
0195:            /** Default constructor */
0196:            public TableRowGroup() {
0197:                super ();
0198:            }
0199:
0200:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0201:            // Child methods
0202:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0203:
0204:            /**
0205:             * Get the closest Table ancestor that encloses this component.
0206:             *
0207:             * @return The Table ancestor.
0208:             */
0209:            public Table getTableAncestor() {
0210:                // Don't cache in the request since it's used as the properties key.
0211:                if (table == null) {
0212:                    UIComponent component = this ;
0213:                    while (component != null) {
0214:                        component = component.getParent();
0215:                        if (component instanceof  Table) {
0216:                            table = (Table) component;
0217:                            break;
0218:                        }
0219:                    }
0220:                }
0221:                return table;
0222:            }
0223:
0224:            /**
0225:             * Get an Iterator over the TableColumn children found for
0226:             * this component.
0227:             *
0228:             * @return An Iterator over the TableColumn children.
0229:             */
0230:            public Iterator getTableColumnChildren() {
0231:                // Get properties cached in request map.
0232:                Properties properties = getProperties();
0233:                List tableColumnChildren = (properties != null) ? properties
0234:                        .getTableColumnChildren() : null;
0235:
0236:                // Get TableColumn children.
0237:                if (tableColumnChildren == null) {
0238:                    tableColumnChildren = new ArrayList();
0239:                    Iterator kids = getChildren().iterator();
0240:                    while (kids.hasNext()) {
0241:                        UIComponent kid = (UIComponent) kids.next();
0242:                        if ((kid instanceof  TableColumn)) {
0243:                            tableColumnChildren.add(kid);
0244:                        }
0245:                    }
0246:                    // Save property in request map.
0247:                    if (properties != null) {
0248:                        properties.setTableColumnChildren(tableColumnChildren);
0249:                    }
0250:                }
0251:                return tableColumnChildren.iterator();
0252:            }
0253:
0254:            /**
0255:             * Get the number of columns found for this component that have a rendered
0256:             * property of true.
0257:             *
0258:             * @return The number of rendered columns.
0259:             */
0260:            public int getColumnCount() {
0261:                // Get properties cached in request map.
0262:                Properties properties = getProperties();
0263:                int columnCount = (properties != null) ? properties
0264:                        .getColumnCount() : -1;
0265:
0266:                // Get column count.
0267:                if (columnCount == -1) {
0268:                    columnCount = 0; // Initialize min value.
0269:                    Iterator kids = getTableColumnChildren();
0270:                    while (kids.hasNext()) {
0271:                        TableColumn col = (TableColumn) kids.next();
0272:                        columnCount += col.getColumnCount();
0273:                    }
0274:                    // Save property in request map.
0275:                    if (properties != null) {
0276:                        properties.setColumnCount(columnCount);
0277:                    }
0278:                }
0279:                return columnCount;
0280:            }
0281:
0282:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0283:            // Component methods
0284:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0285:
0286:            /**
0287:             * Get empty data column.
0288:             *
0289:             * @return The empty data column.
0290:             */
0291:            public UIComponent getEmptyDataColumn() {
0292:                UIComponent facet = getFacet(EMPTY_DATA_COLUMN_FACET);
0293:                if (facet != null) {
0294:                    return facet;
0295:                }
0296:
0297:                // Get child.
0298:                TableColumn child = new TableColumn();
0299:                child.setId(EMPTY_DATA_COLUMN_ID);
0300:                child.setColSpan(getColumnCount());
0301:                child.getChildren().add(getEmptyDataText());
0302:
0303:                // Save facet and return child.
0304:                getFacets().put(child.getId(), child);
0305:                return child;
0306:            }
0307:
0308:            /**
0309:             * Get empty data text.
0310:             *
0311:             * @return The empty data text.
0312:             */
0313:            public UIComponent getEmptyDataText() {
0314:                UIComponent facet = getFacet(EMPTY_DATA_TEXT_FACET);
0315:                if (facet != null) {
0316:                    return facet;
0317:                }
0318:
0319:                Theme theme = getTheme();
0320:
0321:                // Get message.
0322:                String msg = null;
0323:                if (getEmptyDataMsg() != null) {
0324:                    msg = getEmptyDataMsg();
0325:                } else {
0326:                    // Get unfiltered row keys.
0327:                    RowKey[] rowKeys = getRowKeys();
0328:                    if (rowKeys != null && rowKeys.length > 0) {
0329:                        msg = theme.getMessage("table.filteredData"); //NOI18N
0330:                    } else {
0331:                        msg = theme.getMessage("table.emptyData"); //NOI18N
0332:                    }
0333:                }
0334:
0335:                // Get child.
0336:                StaticText child = new StaticText();
0337:                child.setId(EMPTY_DATA_TEXT_ID);
0338:                child.setStyleClass(theme
0339:                        .getStyleClass(ThemeStyles.TABLE_MESSAGE_TEXT));
0340:                child.setText(msg);
0341:
0342:                // Save facet and return child.
0343:                getFacets().put(child.getId(), child);
0344:                return child;
0345:            }
0346:
0347:            /**
0348:             * Get group footer.
0349:             *
0350:             * @return The group footer.
0351:             */
0352:            public UIComponent getGroupFooter() {
0353:                UIComponent facet = getFacet(GROUP_FOOTER_FACET);
0354:                if (facet != null) {
0355:                    return facet;
0356:                }
0357:
0358:                // Get child.
0359:                TableFooter child = new TableFooter();
0360:                child.setId(GROUP_FOOTER_ID);
0361:                child.setColSpan(getColumnCount());
0362:                child.setExtraHtml(getExtraFooterHtml());
0363:                child.setGroupFooter(true);
0364:
0365:                // Set rendered.
0366:                facet = getFacet(FOOTER_FACET);
0367:                if (!(facet != null && facet.isRendered() || getFooterText() != null)) {
0368:                    child.setRendered(false);
0369:                } else {
0370:                    log("getGroupFooter", //NOI18N
0371:                            "Group footer not rendered, nothing to display"); //NOI18N
0372:                }
0373:
0374:                // Save facet and return child.
0375:                getFacets().put(child.getId(), child);
0376:                return child;
0377:            }
0378:
0379:            /**
0380:             * Get group header.
0381:             *
0382:             * @return The group header.
0383:             */
0384:            public UIComponent getGroupHeader() {
0385:                UIComponent facet = getFacet(GROUP_HEADER_FACET);
0386:                if (facet != null) {
0387:                    return facet;
0388:                }
0389:
0390:                // Get child.
0391:                TableHeader child = new TableHeader();
0392:                child.setId(GROUP_HEADER_ID);
0393:                child.setScope("colgroup"); //NOI18N
0394:                child.setColSpan(getColumnCount());
0395:                child.setExtraHtml(getExtraHeaderHtml());
0396:                child.setGroupHeader(true);
0397:
0398:                // Don't render for an empty table.
0399:                boolean emptyTable = getRowCount() == 0;
0400:                boolean renderControls = !emptyTable
0401:                        && (isSelectMultipleToggleButton() || isGroupToggleButton());
0402:
0403:                // Set rendered.
0404:                facet = getFacet(HEADER_FACET);
0405:                if (!(facet != null && facet.isRendered()
0406:                        || getHeaderText() != null || renderControls)) {
0407:                    child.setRendered(false);
0408:                } else {
0409:                    log("getGroupHeader", //NOI18N
0410:                            "Group header not rendered, nothing to display"); //NOI18N
0411:                }
0412:
0413:                // Save facet and return child.
0414:                getFacets().put(child.getId(), child);
0415:                return child;
0416:            }
0417:
0418:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0419:            // Filter methods
0420:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0421:
0422:            /**
0423:             * Clear FilterCriteria objects from the TableDataFilter instance used by
0424:             * this component. 
0425:             * <p>
0426:             * Note: This method clears the cached filter and sort, then resets
0427:             * pagination to the first page per UI guidelines.
0428:             * </p>
0429:             */
0430:            public void clearFilter() {
0431:                getTableDataFilter().setFilterCriteria(null); // Clear all FilterCriteria.
0432:                setFirst(0); // Reset to first page.
0433:
0434:                // Clear properties cached in request map.
0435:                Properties properties = getProperties();
0436:                if (properties != null) {
0437:                    properties.setFilteredRowKeys(null); // Clear filtered row keys.
0438:                    properties.setSortedRowKeys(null); // Clear sorted row keys.
0439:                } else {
0440:                    log("clearFilter", //NOI18N
0441:                            "Cannot clear filtered and sorted row keys, Properties is null"); //NOI18N
0442:                }
0443:            }
0444:
0445:            /**
0446:             * Get an array containing filtered RowKey objects.
0447:             * <p>
0448:             * Note: This filter depends on the FilterCriteria objects provided to the
0449:             * TableDataFilter instance used by this component. Due to filtering, the
0450:             * size of the returned array may be less than the total number of RowKey
0451:             * objects for the underlying TableDataProvider.
0452:             * </p><p>
0453:             * Note: The returned RowKey objects are cached. If the TableDataFilter
0454:             * instance used by this component is modified directly, invoke the
0455:             * clearFilter method to clear the previous filter.
0456:             * </p>
0457:             * @return An array containing filtered RowKey objects.
0458:             */
0459:            public RowKey[] getFilteredRowKeys() {
0460:                // Get properties cached in request map.
0461:                Properties properties = getProperties();
0462:                RowKey[] filteredRowKeys = (properties != null) ? properties
0463:                        .getFilteredRowKeys() : null;
0464:
0465:                // Initialize RowKey objects, if not cached already.
0466:                if (filteredRowKeys != null) {
0467:                    return filteredRowKeys;
0468:                } else {
0469:                    filteredRowKeys = getRowKeys();
0470:                }
0471:
0472:                // Do not attempt to filter with a null provider.
0473:                TableDataProvider provider = getTableRowDataProvider()
0474:                        .getTableDataProvider();
0475:                if (provider == null) {
0476:                    log("getFilteredRowKeys", //NOI18N
0477:                            "Cannot obtain filtered row keys, TableDataProvider is null"); //NOI18N
0478:                    return filteredRowKeys;
0479:                }
0480:
0481:                // If TableDataFilter and TableDataProvider are the same instance, the
0482:                // filter method is never called. The filter order is assumed to be
0483:                // intrinsic in the row data of the TableDataProvider.
0484:                TableDataFilter filter = getTableDataFilter();
0485:                if (provider != filter) {
0486:                    filteredRowKeys = filter.filter(provider, filteredRowKeys);
0487:                } else {
0488:                    log(
0489:                            "getFilteredRowKeys", //NOI18N
0490:                            "Row keys already filtered, TableDataFilter and TableDataProvider are the same instance"); //NOI18N
0491:                }
0492:
0493:                // Save properties.
0494:                if (properties != null) {
0495:                    properties.setFilteredRowKeys(filteredRowKeys);
0496:                } else {
0497:                    log("getFilteredRowKeys", //NOI18N
0498:                            "Cannot save filtered row keys, Properties is null"); //NOI18N
0499:                }
0500:                return filteredRowKeys;
0501:            }
0502:
0503:            /**
0504:             * Get the TableDataFilter object used to filter rows.
0505:             *
0506:             * @return The TableDataFilter object used to filter rows.
0507:             */
0508:            public TableDataFilter getTableDataFilter() {
0509:                // Method is overriden because TableDataFilter is not serializable.
0510:                TableDataFilter tdf = super .getTableDataFilter();
0511:                if (tdf != null) {
0512:                    return tdf;
0513:                }
0514:
0515:                // Get default filter.
0516:                if (filter == null) {
0517:                    filter = new BasicTableDataFilter();
0518:                }
0519:                return filter;
0520:            }
0521:
0522:            /**
0523:             * Set FilterCriteria objects for the TableDataFilter instance used by this
0524:             * component. 
0525:             * <p>
0526:             * Note: This method clears the cached filter and sort, then resets
0527:             * pagination to the first page per UI guidelines.
0528:             * </p>
0529:             * @param filterCriteria An array of FilterCriteria objects defining the
0530:             * filter order on this TableDataFilter.
0531:             */
0532:            public void setFilterCriteria(FilterCriteria[] filterCriteria) {
0533:                clearFilter();
0534:                getTableDataFilter().setFilterCriteria(filterCriteria);
0535:            }
0536:
0537:            /**
0538:             * Set the TableDataFilter object used to filter rows.
0539:             *
0540:             * @param filter The TableDataFilter object used to filter rows.
0541:             */
0542:            public void setTableDataFilter(TableDataFilter filter) {
0543:                // Method is overriden because TableDataFilter is not serializable.
0544:                this .filter = filter;
0545:            }
0546:
0547:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0548:            // Pagination methods
0549:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0550:
0551:            /**
0552:             * Get the zero-relative row number of the first row to be displayed for
0553:             * a paginated table.
0554:             * <p>
0555:             * Note: When ever a new DataProvider is used, UI Guiedlines recommend that
0556:             * pagination should be reset (e.g., remaining on the 4th page of a new set
0557:             * of data makes no sense).
0558:             * </p><p>
0559:             * Note: If rows have been removed from the table, there is a chance that 
0560:             * the first row could be greater than the total number of rows. In this 
0561:             * case, the zero-relative row number of the last page to be displayed is 
0562:             * returned.
0563:             * </p>
0564:             * @return The zero-relative row number of the first row to be displayed.
0565:             */
0566:            public int getFirst() {
0567:                // Ensure the first row is less than the row number of the last page.
0568:                int last = getLast();
0569:                int first = isPaginated() ? Math.max(0, super .getFirst()) : 0;
0570:                return (first < last) ? first : last;
0571:            }
0572:
0573:            /**
0574:             * Set the zero-relative row number of the first row to be displayed for
0575:             * a paginated table.
0576:             *
0577:             * @param first The first row number.
0578:             * @exception IllegalArgumentException for negative values.
0579:             */
0580:            public void setFirst(int first) {
0581:                if (first < 0) {
0582:                    log("setFirst", "First row cannot be < 0"); //NOI18N
0583:                    throw new IllegalArgumentException(Integer.toString(first));
0584:                }
0585:                super .setFirst(first);
0586:            }
0587:
0588:            /**
0589:             * Get the zero-relative row number of the last page to be displayed.
0590:             *
0591:             * @return The zero-relative row number of the last page to be displayed.
0592:             */
0593:            public int getLast() {
0594:                return Math.max(0, getPages() - 1) * getRows();
0595:            }
0596:
0597:            /**
0598:             * Get current page number to be displayed.
0599:             * <p>
0600:             * Note: The default is 1 when the table is not paginated.
0601:             * </p>
0602:             * @return The current page number to be displayed.
0603:             */
0604:            public int getPage() {
0605:                if (!isPaginated()) { // Rows is zero when paginated.
0606:                    return 1;
0607:                }
0608:                return (getFirst() / getRows()) + 1;
0609:            }
0610:
0611:            /**
0612:             * Get total number of pages to be displayed. The default is 1 when the
0613:             * table is not paginated.
0614:             * <p>
0615:             * Note: The page count depends on the FilterCriteria objects provided to
0616:             * the TableDataFilter instance used by this component. Further, the filter
0617:             * used to obtain the page count is cached. If the TableDataFilter instance 
0618:             * used by this component is to be modified directly, invoke the clearFilter
0619:             * method to clear the previous filter.
0620:             * </p>
0621:             * @return The total number of pages to be displayed.
0622:             */
0623:            public int getPages() {
0624:                if (!isPaginated()) {
0625:                    return 1;
0626:                }
0627:
0628:                int rowCount = getRowCount(); // Get row count.
0629:                int rows = getRows(); // Get rows per page. 
0630:
0631:                // Note: Rows should be > 0 when paginated.
0632:                int modulus = (rows > 0) ? rowCount % rows : 0;
0633:                int result = (rows > 0) ? rowCount / rows : 1;
0634:
0635:                // Increment result for extra rows.
0636:                return (modulus > 0) ? ++result : result;
0637:            }
0638:
0639:            /**
0640:             * Test the paginated state of this component.
0641:             * <p>
0642:             * Note: If the paginationControls property of the Table component is true,
0643:             * this property will be initialized as true.
0644:             * </p>
0645:             * @return true for paginate mode, false for scroll mode.
0646:             */
0647:            public boolean isPaginated() {
0648:                if (!paginated_set) {
0649:                    Table table = getTableAncestor();
0650:                    if (table != null) {
0651:                        setPaginated(table.isPaginationControls());
0652:                    } else {
0653:                        log("isPaginated", //NOI18N
0654:                                "Cannot initialize paginated state, Table is null"); //NOI18N
0655:                    }
0656:                }
0657:                return paginated;
0658:            }
0659:
0660:            /**
0661:             * A convenience method to set the current page to be displayed.
0662:             * <p>
0663:             * Note: You can also set the current, first, next, prev, and last pages by
0664:             * invoking the setFirst(int) method directly. For example, you could use
0665:             * setFirst(0) to display the first page and setFirst(getLast()) to display
0666:             * the last page. The setFirst(int) method is particularly useful when a
0667:             * subset of data is displayed in scroll mode or when overriding pagination.
0668:             * </p><p>
0669:             * Note: When ever a new DataProvider is used, UI Guiedlines recommend that
0670:             * pagination should be reset (e.g., remaining on the 4th page of a new set
0671:             * of data makes no sense).
0672:             * </p>
0673:             * @param page The current page.
0674:             */
0675:            public void setPage(int page) {
0676:                // Set the starting row for the new page.
0677:                int row = (page - 1) * getRows();
0678:
0679:                // Result cannot be greater than the row index for the last page.
0680:                int result = Math.min(row, getLast());
0681:
0682:                // Result cannot be greater than total number of rows or less than zero.
0683:                setFirst(Math.min(Math.max(result, 0), getRowCount()));
0684:            }
0685:
0686:            /**
0687:             * Set the paginated state of this component.
0688:             * <p>
0689:             * Note: When pagination controls are used, a value of true allows both
0690:             * pagination controls and paginate buttons to be displayed. A value of
0691:             * false allows only paginate buttons to be displayed. However, when all
0692:             * data fits on one page, neither pagination controls or paginate buttons
0693:             * are displayed.
0694:             * </p><p>
0695:             * Note: To properly maintain the paginated state of the table per UI
0696:             * guidelines, the paginated property is cached. If the paginationControls 
0697:             * property of the table component changes (e.g., in an application builder 
0698:             * environment), use this method to set the paginated property accordingly.
0699:             * </p>
0700:             * @param paginated The paginated state of this component.
0701:             */
0702:            public void setPaginated(boolean paginated) {
0703:                this .paginated = paginated;
0704:                paginated_set = true;
0705:            }
0706:
0707:            /**
0708:             * Get the number of rows to be displayed for a paginated table.
0709:             * <p>
0710:             * Note: UI guidelines recommend a default value of 25 rows per page.
0711:             * </p>
0712:             * @return The number of rows to be displayed for a paginated table.
0713:             */
0714:            public int getRows() {
0715:                return isPaginated() ? Math.max(1, super .getRows()) : 0;
0716:            }
0717:
0718:            /**
0719:             * Set the number of rows to be displayed for a paginated table.
0720:             *
0721:             * @param rows The number of rows to be displayed for a paginated table.
0722:             * @exception IllegalArgumentException for negative values.
0723:             */
0724:            public void setRows(int rows) {
0725:                if (rows < 0) {
0726:                    log("setRows", "Paginated rows cannot be < 0"); //NOI18N
0727:                    throw new IllegalArgumentException(Integer.toString(rows));
0728:                }
0729:                super .setRows(rows);
0730:            }
0731:
0732:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0733:            // Row methods
0734:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0735:
0736:            /**
0737:             * Get the flag indicating whether there is row data available for the
0738:             * current RowKey. If no row data is available, false is returned.
0739:             *
0740:             * @return The flag indicating whether there is row data available.
0741:             */
0742:            public boolean isRowAvailable() {
0743:                boolean result = false;
0744:                TableDataProvider provider = getTableRowDataProvider()
0745:                        .getTableDataProvider();
0746:                if (provider != null) {
0747:                    result = provider.isRowAvailable(getRowKey());
0748:                } else {
0749:                    log("isRowAvailable", //NOI18N
0750:                            "Cannot determine if row is available, TableDataProvider is null"); //NOI18N
0751:                }
0752:                return result;
0753:            }
0754:
0755:            /**
0756:             * Get an array of hidden RowKey objects from the underlying 
0757:             * TableDataProvider taking filtering, sorting, and pagination into account.
0758:             * <p>
0759:             * Note: The returned RowKey objects depend on the FilterCriteria and 
0760:             * SortCriteria objects provided to the TableDataFilter and TableDataSorter
0761:             * instances used by this component. If TableDataFilter and TableDataSorter
0762:             * are modified directly, invoke the clearSort and clearFilter method to
0763:             * clear the previous sort and filter.
0764:             * </p>
0765:             * @return An array of RowKey objects.
0766:             */
0767:            public RowKey[] getHiddenRowKeys() {
0768:                if (!isPaginated()) {
0769:                    return null; // No rows are hidden during scroll mode.
0770:                }
0771:
0772:                // Get sorted RowKey objects.
0773:                RowKey[] rowKeys = getSortedRowKeys();
0774:                if (rowKeys == null) {
0775:                    return rowKeys;
0776:                }
0777:
0778:                // Find the number of selected rows hidden from view.
0779:                ArrayList list = new ArrayList();
0780:                int first = getFirst();
0781:                int rows = getRows();
0782:                for (int i = 0; i < rowKeys.length; i++) {
0783:                    // Have we displayed the paginated number of rows?
0784:                    if (i >= first && i < first + rows) {
0785:                        continue;
0786:                    }
0787:                    list.add(rowKeys[i]);
0788:                }
0789:                rowKeys = new RowKey[list.size()];
0790:                return (RowKey[]) list.toArray(rowKeys);
0791:            }
0792:
0793:            /**
0794:             * Get the FieldKey from the underlying TableDataProvider.
0795:             *
0796:             * @param fieldId The id of the requested FieldKey.
0797:             * @return The RowKey from the underlying TableDataProvider.
0798:             */
0799:            public FieldKey getFieldKey(String fieldId) {
0800:                return getTableRowDataProvider().getFieldKey(fieldId);
0801:            }
0802:
0803:            /**
0804:             * Get the number of rows in the underlying TableDataProvider. If the
0805:             * number of available rows is unknown, -1 is returned.
0806:             * <p>
0807:             * Note: This row count depends on the FilterCriteria objects provided to
0808:             * the TableDataFilter instance used by this component. Further, the filter
0809:             * used to obtain the row count is cached. If the TableDataFilter instance 
0810:             * used by this component is modified directly, invoke the clearFilter
0811:             * method to clear the previous filter.
0812:             * </p>
0813:             * @return The number of rows in the underlying TableDataProvider.
0814:             */
0815:            public int getRowCount() {
0816:                RowKey[] rowKeys = getFilteredRowKeys();
0817:                return (rowKeys != null) ? rowKeys.length : 0;
0818:            }
0819:
0820:            /**
0821:             * Get the RowKey associated with the current row.
0822:             *
0823:             * @return The RowKey associated with the current row.
0824:             */
0825:            public RowKey getRowKey() {
0826:                return getTableRowDataProvider().getTableRow();
0827:            }
0828:
0829:            /**
0830:             * Get all RowKey objects for the underlying TableDataProvider.
0831:             *
0832:             * @return All RowKey objects for the underlying TableDataProvider.
0833:             */
0834:            public RowKey[] getRowKeys() {
0835:                RowKey[] rowKeys = null;
0836:                TableDataProvider provider = getTableRowDataProvider()
0837:                        .getTableDataProvider();
0838:                if (provider == null) {
0839:                    log("getRowKeys", //NOI18N
0840:                            "Cannot obtain row keys, TableDataProvider is null"); //NOI18N
0841:                    return rowKeys;
0842:                }
0843:
0844:                // Create fake data for design-time behavior. The ResultSetDataProvider 
0845:                // returns 3 rows of dummy data; however, this is not enough to display
0846:                // pagination controls properly. When all rows fit on a single page, or 
0847:                // when we have an empty table, certain controls are hidden from view. 
0848:                // Thus, if a user specifies 20 rows per page, we want to create 20 + 1 
0849:                // rows of data forcing controls to be displayed.
0850:                if (Beans.isDesignTime()) {
0851:                    log("getRowKeys",
0852:                            "Creating dummy data for design-time behavior"); //NOI18N
0853:                    rowKeys = provider.getRowKeys(provider.getRowCount(), null);
0854:                    // If pagination is not enabled, dummy data is not required.
0855:                    if (getRows() == 0 || rowKeys == null
0856:                            || rowKeys.length == 0) {
0857:                        log("getRowKeys", //NOI18N
0858:                                "Cannot create dummy data, DataProvider has no rows"); //NOI18N
0859:                        return rowKeys;
0860:                    } else {
0861:                        ArrayList list = new ArrayList();
0862:                        for (int i = 0; i < getRows() + 1; i++) {
0863:                            list.add(rowKeys[i % rowKeys.length]);
0864:                        }
0865:                        rowKeys = new RowKey[list.size()];
0866:                        return ((RowKey[]) list.toArray(rowKeys));
0867:                    }
0868:                }
0869:
0870:                // It's possible that the provider returned -1 because it does not
0871:                // actually have all the rows, so it's up to the consumer of the
0872:                // interface to fetch them. Typically, 99% of the data providers will
0873:                // return a valid row count (at least our providers will), but we still
0874:                // need to handle the scenario where -1 is returned.
0875:                int rowCount = provider.getRowCount();
0876:                if (rowCount == -1) {
0877:                    log("getRowKeys", //NOI18N
0878:                            "Manually calculating row count, DataProvider.getRowCount() is -1"); //NOI18N
0879:                    int index = 0;
0880:                    do {
0881:                        // Keep trying until all rows are obtained.
0882:                        rowCount = 1000000 * ++index;
0883:                        rowKeys = provider.getRowKeys(rowCount, null);
0884:                    } while (rowKeys != null && rowKeys.length - 1 == rowCount);
0885:                } else {
0886:                    rowKeys = provider.getRowKeys(rowCount, null);
0887:                }
0888:                return rowKeys;
0889:            }
0890:
0891:            /**
0892:             * Get the TableRowDataProvider object representing the data objects that
0893:             * we will iterate over in this component's rendering.
0894:             *
0895:             * @return The TableRowDataProvider object.
0896:             */
0897:            protected TableRowDataProvider getTableRowDataProvider() {
0898:                // Get properties cached in request map.
0899:                Properties properties = getProperties();
0900:                TableRowDataProvider provider = (properties != null) ? properties
0901:                        .getTableRowDataProvider()
0902:                        : null;
0903:
0904:                // Get provider.
0905:                if (provider == null) {
0906:                    log("getTableRowDataProvider", //NOI18N
0907:                            "Re-evaluating sourceData, TableRowDataProvider is null"); //NOI18N
0908:
0909:                    // Synthesize a TableDataProvider around source data, if possible.
0910:                    TableDataProvider tdp;
0911:                    Object obj = getSourceData();
0912:                    if (obj == null) {
0913:                        tdp = null;
0914:                    } else if (obj instanceof  TableDataProvider) {
0915:                        tdp = (TableDataProvider) obj;
0916:                    } else if (obj instanceof  List) {
0917:                        tdp = new ObjectListDataProvider((List) obj);
0918:                    } else if (Object[].class.isAssignableFrom(obj.getClass())) {
0919:                        tdp = new ObjectArrayDataProvider((Object[]) obj);
0920:                    } else {
0921:                        // Default "single variable" case.
0922:                        ArrayList list = new ArrayList(1);
0923:                        list.add(obj);
0924:                        tdp = new ObjectListDataProvider(list);
0925:                    }
0926:                    provider = new TableRowDataProvider(tdp);
0927:
0928:                    // Save property in request map.
0929:                    if (properties != null) {
0930:                        properties.setTableRowDataProvider(provider);
0931:                    } else {
0932:                        log("getTableRowDataProvider", //NOI18N
0933:                                "Cannot save TableRowDataProvider, Properties is null"); //NOI18N
0934:                    }
0935:                }
0936:                return provider;
0937:            }
0938:
0939:            /**
0940:             * Get the data type of the data element referenced by the given FieldKey.
0941:             *
0942:             * @param fieldKey The FieldKey identifying the data element whose type is
0943:             * to be returned.
0944:             * @return The data type of the data element referenced by the given FieldKey.
0945:             */
0946:            public Class getType(FieldKey fieldKey) {
0947:                return getTableRowDataProvider().getType(fieldKey);
0948:            }
0949:
0950:            /**
0951:             * Get an array of rendered RowKey objects from the underlying 
0952:             * TableDataProvider taking filtering, sorting, and pagination into account.
0953:             * <p>
0954:             * Note: The returned RowKey objects depend on the FilterCriteria and 
0955:             * SortCriteria objects provided to the TableDataFilter and TableDataSorter
0956:             * instances used by this component. If TableDataFilter and TableDataSorter
0957:             * are modified directly, invoke the clearSort and clearFilter method to
0958:             * clear the previous sort and filter.
0959:             * </p>
0960:             * @return An array of RowKey objects.
0961:             */
0962:            public RowKey[] getRenderedRowKeys() {
0963:                // Get sorted RowKey objects.
0964:                RowKey[] rowKeys = getSortedRowKeys();
0965:                if (rowKeys == null) {
0966:                    return rowKeys;
0967:                }
0968:
0969:                // Find the number of selected rows hidden from view.
0970:                ArrayList list = new ArrayList();
0971:                int first = getFirst();
0972:                int rows = getRows();
0973:                for (int i = first; i < rowKeys.length; i++) {
0974:                    // Have we displayed the paginated number of rows?
0975:                    if (isPaginated() && i >= first + rows) {
0976:                        break;
0977:                    }
0978:                    list.add(rowKeys[i]);
0979:                }
0980:                rowKeys = new RowKey[list.size()];
0981:                return (RowKey[]) list.toArray(rowKeys);
0982:            }
0983:
0984:            /**
0985:             * Set the RowKey associated with the current row or null for no current row
0986:             * association.
0987:             * <p>
0988:             * Note: It is possible to set the RowKey at a value for which the 
0989:             * underlying TableDataProvider does not contain any row data. Therefore,
0990:             * callers may use the isRowAvailable() method to detect whether row data
0991:             * will be available.
0992:             * <ul>
0993:             * <li>Save current state information for all descendant components (as
0994:             *     described below).
0995:             * <li>Store the new RowKey, and pass it on to the TableDataProvider 
0996:             *     associated with this TableRowGroup instance.</li>
0997:             * <li>If the new RowKey value is null:
0998:             *     <ul>
0999:             *     <li>If the var property is not null,
1000:             *         remove the corresponding request scope attribute (if any).</li>
1001:             *     <li>Reset the state information for all descendant components
1002:             *         (as described below).</li>
1003:             *     </ul></li>
1004:             * <li>If the new RowKey value is not null:
1005:             *     <ul>
1006:             *     <li>If the var property is not null, expose the
1007:             *         data provider as a request scope attribute whose key is the
1008:             *         var property value.</li>
1009:             *     <li>Reset the state information for all descendant components
1010:             *         (as described below).
1011:             *     </ul></li>
1012:             * </ul></p><p>
1013:             * To save current state information for all descendant components,
1014:             * TableRowGroup must maintain per-row information for each descendant as
1015:             * follows:
1016:             * <ul>
1017:             * <li>If the descendant is an instance of EditableValueHolder,
1018:             *     save the state of its localValue property.</li>
1019:             * <li>If the descendant is an instance of EditableValueHolder,
1020:             *     save the state of the localValueSet property.</li>
1021:             * <li>If the descendant is an instance of EditableValueHolder,
1022:             *     save the state of the valid property.</li>
1023:             * <li>If the descendant is an instance of EditableValueHolder,
1024:             *     save the state of the submittedValue property.</li>
1025:             * </ul></p><p>
1026:             * To restore current state information for all descendant components,
1027:             * TableRowGroup must reference its previously stored information
1028:             * for the current RowKey and call setters for each descendant
1029:             * as follows:
1030:             * <ul>
1031:             * <li>If the descendant is an instance of EditableValueHolder,
1032:             *     restore the value property.</li>
1033:             * <li>If the descendant is an instance of EditableValueHolder,
1034:             *     restore the state of the localValueSet property.</li>
1035:             * <li>If the descendant is an instance of EditableValueHolder,
1036:             *     restore the state of the valid property.</li>
1037:             * <li>If the descendant is an instance of EditableValueHolder,
1038:             *     restore the state of the submittedValue property.</li>
1039:             * </ul></p>
1040:             *
1041:             * @param rowKey The RowKey associated with the current row or
1042:             * null for no association.
1043:             */
1044:            public void setRowKey(RowKey rowKey) {
1045:                // Save current state for the previous row.
1046:                saveDescendantState();
1047:
1048:                // Update to the new row.
1049:                getTableRowDataProvider().setTableRow(rowKey);
1050:
1051:                // Clear or expose the current row data as a request scope attribute
1052:                String sourceVar = getSourceVar();
1053:                if (sourceVar != null) {
1054:                    Map requestMap = getFacesContext().getExternalContext()
1055:                            .getRequestMap();
1056:                    if (rowKey == null) {
1057:                        requestMap.remove(sourceVar);
1058:                    } else if (isRowAvailable()) {
1059:                        requestMap.put(sourceVar, getTableRowDataProvider());
1060:                    } else {
1061:                        requestMap.remove(sourceVar);
1062:                    }
1063:                } else {
1064:                    log("setRowKey",
1065:                            "Cannot set row key, sourceVar property is null"); //NOI18N
1066:                }
1067:
1068:                // Reset current state information for the new row.
1069:                restoreDescendantState();
1070:            }
1071:
1072:            /**
1073:             * Set the source data of the TableRowGroup.
1074:             * <p>
1075:             * Note: When ever a new DataProvider is used, UI Guiedlines recommend that
1076:             * pagination should be reset (e.g., remaining on the 4th page of a new set
1077:             * of data makes no sense). However, properties such as the sort and filter 
1078:             * criteria should not automatically be cleared (e.g., there may be 
1079:             * situations where one or both should be left as specified by the user). In
1080:             * this scenario, pagination is set to the first page.
1081:             * </p>
1082:             * @param sourceData The source data of the TableRowGroup.
1083:             */
1084:            public void setSourceData(Object sourceData) {
1085:                super .setSourceData(sourceData);
1086:                init();
1087:            }
1088:
1089:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1090:            // Selected methods
1091:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1092:
1093:            /**
1094:             * Get the number of objects from the underlying data provider where the
1095:             * selected property of this component is set to true and the row is 
1096:             * currently hidden from view.
1097:             * <p>
1098:             * Note: UI guidelines recomend that rows should be unselected when no
1099:             * longer in view. For example, when a user selects rows of the table and 
1100:             * navigates to another page. Or, when a user applies a filter or sort that
1101:             * may hide previously selected rows from view. If a user invokes an action
1102:             * to delete the currently selected rows, they may inadvertently remove rows
1103:             * not displayed on the current page. That said, there are cases when
1104:             * maintaining state across table pages is necessary. When maintaining state
1105:             * and there are currently no hidden selections, UI guidelines recomend that
1106:             * the number zero should be shown.
1107:             * </p><p>
1108:             * Note: This count depends on the FilterCriteria and SortCriteria objects
1109:             * provided to the TableDataFilter and TableDataSorter instances used by
1110:             * this component. If TableDataFilter and TableFilterSorter are modified
1111:             * directly, invoke the clearFilter method to clear the previous filter and
1112:             * sort.
1113:             * </p>
1114:             * @return The number of selected rows currently hidden from view.
1115:             */
1116:            public int getHiddenSelectedRowsCount() {
1117:                RowKey[] rowKeys = getHiddenSelectedRowKeys();
1118:                return (rowKeys != null) ? rowKeys.length : 0;
1119:            }
1120:
1121:            /**
1122:             * Get an array of RowKey objects from the underlying data provider where
1123:             * the selected property of this component is set to true and the row is
1124:             * currently hidden from view.
1125:             * <p>
1126:             * Note: UI guidelines recomend that rows should be unselected when no
1127:             * longer in view. For example, when a user selects rows of the table and 
1128:             * navigates to another page. Or, when a user applies a filter or sort that
1129:             * may hide previously selected rows from view. If a user invokes an action
1130:             * to delete the currently selected rows, they may inadvertently remove rows
1131:             * not displayed on the current page.
1132:             * </p><p>
1133:             * Note: The returned RowKey objects depend on the FilterCriteria and 
1134:             * SortCriteria objects provided to the TableDataFilter and TableDataSorter
1135:             * instances used by this component. If TableDataFilter and TableDataSorter
1136:             * are modified directly, invoke the clearSort and clearFilter method to
1137:             * clear the previous sort and filter.
1138:             * </p>
1139:             * @return An array of RowKey objects.
1140:             */
1141:            public RowKey[] getHiddenSelectedRowKeys() {
1142:                // Get hidden RowKey objects.
1143:                RowKey[] rowKeys = getHiddenRowKeys();
1144:                if (rowKeys == null) {
1145:                    return rowKeys;
1146:                }
1147:
1148:                // Save the current RowKey.
1149:                RowKey rowKey = getRowKey();
1150:
1151:                // Find the number of selected rows hidden from view.
1152:                ArrayList list = new ArrayList();
1153:                for (int i = 0; i < rowKeys.length; i++) {
1154:                    setRowKey(rowKeys[i]);
1155:                    if (isRowAvailable() && isSelected()) {
1156:                        list.add(rowKeys[i]);
1157:                    }
1158:                }
1159:                setRowKey(rowKey); // Restore the current RowKey.
1160:                rowKeys = new RowKey[list.size()];
1161:                return (RowKey[]) list.toArray(rowKeys);
1162:            }
1163:
1164:            /**
1165:             * Get the number of selected rows from the underlying data provider where
1166:             * the selected property of this component is set to true.
1167:             * <p>
1168:             * Note: This count depends on the FilterCriteria objects provided to the
1169:             * TableDataFilter instance used by this component. If TableDataFilter is
1170:             * modified directly, invoke the clearFilter method to clear the previous
1171:             * filter.
1172:             * </p>
1173:             * @return The number of selected rows.
1174:             */
1175:            public int getSelectedRowsCount() {
1176:                RowKey[] rowKeys = getSelectedRowKeys();
1177:                return (rowKeys != null) ? rowKeys.length : 0;
1178:            }
1179:
1180:            /**
1181:             * Get an array of RowKey objects from the underlying data provider where
1182:             * the selected property of this component is set to true.
1183:             * <p>
1184:             * Note: The returned RowKey objects depend on the FilterCriteria objects 
1185:             * provided to the TableDataFilter instance used by this component. If 
1186:             * TableDataFilter is modified directly, invoke the clearFilter method to
1187:             * clear the previous filter.
1188:             * </p>
1189:             * @return An array of RowKey objects.
1190:             */
1191:            public RowKey[] getSelectedRowKeys() {
1192:                // Get filtered RowKey objects.
1193:                RowKey[] rowKeys = getFilteredRowKeys();
1194:                if (rowKeys == null) {
1195:                    return rowKeys;
1196:                }
1197:
1198:                // Save the current RowKey.
1199:                RowKey rowKey = getRowKey();
1200:
1201:                // Find the number of selected rows.
1202:                ArrayList list = new ArrayList();
1203:                for (int i = 0; i < rowKeys.length; i++) {
1204:                    setRowKey(rowKeys[i]);
1205:                    if (isRowAvailable() && isSelected()) {
1206:                        list.add(rowKeys[i]);
1207:                    }
1208:                }
1209:                setRowKey(rowKey); // Restore the current RowKey.
1210:                rowKeys = new RowKey[list.size()];
1211:                return (RowKey[]) list.toArray(rowKeys);
1212:            }
1213:
1214:            /**
1215:             * Get the number of objects from the underlying data provider where the
1216:             * selected property of this component is set to true and the row is 
1217:             * rendered.
1218:             * <p>
1219:             * Note: UI guidelines recomend that rows should be unselected when no
1220:             * longer in view. For example, when a user selects rows of the table and 
1221:             * navigates to another page. Or, when a user applies a filter or sort that
1222:             * may hide previously selected rows from view. If a user invokes an action
1223:             * to delete the currently selected rows, they may inadvertently remove rows
1224:             * not displayed on the current page.
1225:             * </p><p>
1226:             * Note: This count depends on the FilterCriteria and SortCriteria objects
1227:             * provided to the TableDataFilter and TableDataSorter instances used by
1228:             * this component. If TableDataFilter and TableFilterSorter are modified
1229:             * directly, invoke the clearFilter method to clear the previous filter and
1230:             * sort.
1231:             * </p>
1232:             * @return The number of selected rows currently hidden from view.
1233:             */
1234:            public int getRenderedSelectedRowsCount() {
1235:                RowKey[] rowKeys = getRenderedSelectedRowKeys();
1236:                return (rowKeys != null) ? rowKeys.length : 0;
1237:            }
1238:
1239:            /**
1240:             * Get an array of RowKey objects from the underlying data provider where
1241:             * the selected property of this component is set to true and the row is
1242:             * rendered.
1243:             * <p>
1244:             * Note: UI guidelines recomend that rows should be unselected when no
1245:             * longer in view. For example, when a user selects rows of the table and 
1246:             * navigates to another page. Or, when a user applies a filter or sort that
1247:             * may hide previously selected rows from view. If a user invokes an action
1248:             * to delete the currently selected rows, they may inadvertently remove rows
1249:             * not displayed on the current page.
1250:             * </p><p>
1251:             * Note: The returned RowKey objects depend on the FilterCriteria and 
1252:             * SortCriteria objects provided to the TableDataFilter and TableDataSorter
1253:             * instances used by this component. If TableDataFilter and TableDataSorter
1254:             * are modified directly, invoke the clearSort and clearFilter method to
1255:             * clear the previous sort and filter.
1256:             * </p>
1257:             * @return An array of RowKey objects.
1258:             */
1259:            public RowKey[] getRenderedSelectedRowKeys() {
1260:                // Get rendered RowKey objects.
1261:                RowKey[] rowKeys = getRenderedRowKeys();
1262:                if (rowKeys == null) {
1263:                    return rowKeys;
1264:                }
1265:
1266:                // Save the current RowKey.
1267:                RowKey rowKey = getRowKey();
1268:
1269:                // Find the number of selected rows in view.
1270:                ArrayList list = new ArrayList();
1271:                for (int i = 0; i < rowKeys.length; i++) {
1272:                    setRowKey(rowKeys[i]);
1273:                    if (isRowAvailable() && isSelected()) {
1274:                        list.add(rowKeys[i]);
1275:                    }
1276:                }
1277:                setRowKey(rowKey); // Restore the current RowKey.
1278:                rowKeys = new RowKey[list.size()];
1279:                return (RowKey[]) list.toArray(rowKeys);
1280:            }
1281:
1282:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1283:            // Sort methods
1284:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1285:
1286:            /**
1287:             * Add a SortCriteria object to sort.
1288:             * <p>
1289:             * Note: Objects are sorted in the reverse order they were added. For 
1290:             * example, the first object added, will be the last sort applied as the 
1291:             * primary sort. The second object added, will be the second to last sort
1292:             * applied as the secondary sort. The third object added, will be the third
1293:             * to last sort applied as the tertiary sort and so on. If an existing
1294:             * SortCriteria object is found with the same FieldKey, the sort order is
1295:             * replaced with the new value. Note that sorts are not actually applied
1296:             * until the getSortedRowKeys() method is invoked, which happens
1297:             * automatically by the renderer.
1298:             * </p><p>
1299:             * Note: This method also resets pagination to the first page per UI 
1300:             * guidelines.
1301:             * </p>
1302:             * @param criteria The SortCriteria object to sort.
1303:             */
1304:            public void addSort(SortCriteria criteria) {
1305:                if (criteria == null) {
1306:                    return;
1307:                }
1308:
1309:                TableDataSorter sorter = getTableDataSorter();
1310:                SortCriteria[] oldCriteria = sorter.getSortCriteria();
1311:
1312:                // Iterate over each SortCriteria object and check for a match.
1313:                if (oldCriteria != null) {
1314:                    for (int i = 0; i < oldCriteria.length; i++) {
1315:                        if (oldCriteria[i] == null) {
1316:                            continue;
1317:                        }
1318:                        String key = oldCriteria[i].getCriteriaKey();
1319:                        if (key != null
1320:                                && key.equals(criteria.getCriteriaKey())) {
1321:                            oldCriteria[i] = criteria;
1322:                            return; // No further processing is required.
1323:                        }
1324:                    }
1325:                }
1326:
1327:                // Create array to hold new criteria.
1328:                int oldLength = (oldCriteria != null) ? oldCriteria.length : 0;
1329:                SortCriteria[] newCriteria = new SortCriteria[oldLength + 1];
1330:                for (int i = 0; i < oldLength; i++) {
1331:                    newCriteria[i] = oldCriteria[i];
1332:                }
1333:
1334:                // Add new SortCriteria object.
1335:                newCriteria[oldLength] = criteria;
1336:                sorter.setSortCriteria(newCriteria); // Set new SortCriteria.
1337:                setFirst(0); // Reset to first page.
1338:
1339:                // Clear properties cached in request map.
1340:                Properties properties = getProperties();
1341:                if (properties != null) {
1342:                    properties.setSortedRowKeys(null);
1343:                } else {
1344:                    log("addSort",
1345:                            "Cannot clear sorted row keys, Properties is null"); //NOI18N
1346:                }
1347:            }
1348:
1349:            /**
1350:             * Clear SortCriteria objects from the TableDataSorter instance used by this
1351:             * component. 
1352:             * <p>
1353:             * Note: This method clears the cached sort, then resets pagination to the
1354:             * first page per UI guidelines.
1355:             * </p>
1356:             */
1357:            public void clearSort() {
1358:                getTableDataSorter().setSortCriteria(null); // Clear all SortCriteria.
1359:                setFirst(0); // Reset to first page.
1360:
1361:                // Clear properties cached in request map.
1362:                Properties properties = getProperties();
1363:                if (properties != null) {
1364:                    properties.setSortedRowKeys(null);
1365:                } else {
1366:                    log("clearSort",
1367:                            "Cannot clear sorted row keys, Properties is null"); //NOI18N
1368:                }
1369:            }
1370:
1371:            /**
1372:             * Get the number of SortCriteria objects to sort.
1373:             *
1374:             * @return The number of SortCriteria objects to sort.
1375:             */
1376:            public int getSortCount() {
1377:                int result = 0;
1378:                SortCriteria[] sortCriteria = getTableDataSorter()
1379:                        .getSortCriteria();
1380:                if (sortCriteria != null) {
1381:                    result = sortCriteria.length;
1382:                }
1383:                return result;
1384:            }
1385:
1386:            /**
1387:             * Get the level of the given SortCriteria object to sort.
1388:             * <p>
1389:             * Note: The primary sort is level 1, the secondary sort is level 2, the 
1390:             * tertiary sort is level 3, and so on. If the SortCriteria 
1391:             * object was not previously added using the addSort method, the level will
1392:             * be returned as -1.
1393:             * </p>
1394:             * @param criteria The SortCriteria object to sort.
1395:             * @return The sort level or -1 if the SortCriteria object was not 
1396:             * previously added.
1397:             */
1398:            public int getSortLevel(SortCriteria criteria) {
1399:                int result = -1;
1400:                if (criteria == null) {
1401:                    return result;
1402:                }
1403:
1404:                // Iterate over each SortCriteria object and check for a match.
1405:                SortCriteria[] sortCriteria = getTableDataSorter()
1406:                        .getSortCriteria();
1407:                if (sortCriteria != null) {
1408:                    for (int i = 0; i < sortCriteria.length; i++) {
1409:                        if (sortCriteria[i] == null) {
1410:                            continue;
1411:                        }
1412:                        String key = sortCriteria[i].getCriteriaKey();
1413:                        if (key != null
1414:                                && key.equals(criteria.getCriteriaKey())) {
1415:                            result = i + 1;
1416:                            break;
1417:                        }
1418:                    }
1419:                }
1420:                return result;
1421:            }
1422:
1423:            /**
1424:             * Test if given SortCriteria object is a descending sort.
1425:             *
1426:             * @param criteria The SortCriteria object to sort.
1427:             * @return true if descending, else false.
1428:             */
1429:            public boolean isDescendingSort(SortCriteria criteria) {
1430:                boolean result = false;
1431:                if (criteria == null) {
1432:                    return result;
1433:                }
1434:
1435:                // Iterate over each SortCriteria object and check for a match.
1436:                SortCriteria[] sortCriteria = getTableDataSorter()
1437:                        .getSortCriteria();
1438:                if (sortCriteria != null) {
1439:                    for (int i = 0; i < sortCriteria.length; i++) {
1440:                        if (sortCriteria[i] == null) {
1441:                            continue;
1442:                        }
1443:                        String key = sortCriteria[i].getCriteriaKey();
1444:                        if (key != null
1445:                                && key.equals(criteria.getCriteriaKey())) {
1446:                            // Note: SortCriteria tests ascending instead of descending.
1447:                            result = !sortCriteria[i].isAscending();
1448:                            break;
1449:                        }
1450:                    }
1451:                }
1452:                return result;
1453:            }
1454:
1455:            /**
1456:             * Get an array containing sorted RowKey objects.
1457:             * <p>
1458:             * Note: This sort depends on the SortCriteria objects provided to the
1459:             * TableDataSorter instance used by this component. For better performance,
1460:             * this sort also depends on the FilterCriteria objects provided to the
1461:             * TableDataFilter instance used by this component. Due to filtering, the
1462:             * size of the returned array may be less than the total number of RowKey
1463:             * objects for the underlying TableDataProvider.
1464:             * </p><p>
1465:             * Note: The returned RowKey objects are cached. If the TableDataSorter and
1466:             * TableDataFilter instances used by this component are modified directly,
1467:             * invoke the clearSort and clearFilter methods to clear the previous sort
1468:             * and filter.
1469:             * </p>
1470:             * @return An array containing sorted RowKey objects.
1471:             */
1472:            public RowKey[] getSortedRowKeys() {
1473:                // Get properties cached in request map.
1474:                Properties properties = getProperties();
1475:                RowKey[] sortedRowKeys = (properties != null) ? properties
1476:                        .getSortedRowKeys() : null;
1477:
1478:                // Initialize RowKey objects, if not cached already.
1479:                if (sortedRowKeys != null) {
1480:                    return sortedRowKeys;
1481:                } else {
1482:                    sortedRowKeys = getFilteredRowKeys();
1483:                }
1484:
1485:                // Do not attempt to sort with a null provider. BasicTableDataSorter
1486:                // throws NullPointerException -- bugtraq id #6268451.
1487:                TableDataProvider provider = getTableRowDataProvider()
1488:                        .getTableDataProvider();
1489:                if (provider == null) {
1490:                    log("getSortedRowKeys", //NOI18N
1491:                            "Cannot obtain sorted row keys, TableDataProvider is null"); //NOI18N
1492:                    return sortedRowKeys;
1493:                }
1494:
1495:                // If TableDataSorter and TableDataProvider are the same instance, the
1496:                // sort method is never called. The sort order is assumed to be
1497:                // intrinsic in the row order of the TableDataProvider.
1498:                TableDataSorter sorter = getTableDataSorter();
1499:                if (provider != sorter) {
1500:                    sortedRowKeys = sorter.sort(provider, sortedRowKeys);
1501:                }
1502:
1503:                // Save properties.
1504:                if (properties != null) {
1505:                    properties.setSortedRowKeys(sortedRowKeys);
1506:                } else {
1507:                    log("getSortedRowKeys", //NOI18N
1508:                            "Cannot save sorted row keys, Properties is null"); //NOI18N
1509:                }
1510:                return sortedRowKeys;
1511:            }
1512:
1513:            /**
1514:             * Get the TableDataSorter object used to sort rows.
1515:             *
1516:             * @return The TableDataSorter object used to sort rows.
1517:             */
1518:            public TableDataSorter getTableDataSorter() {
1519:                // Method is overriden because TableDataSorter is not serializable.
1520:                TableDataSorter tds = super .getTableDataSorter();
1521:                if (tds != null) {
1522:                    return tds;
1523:                }
1524:
1525:                // Get default sorter.
1526:                if (sorter == null) {
1527:                    sorter = new BasicTableDataSorter();
1528:                }
1529:                return sorter;
1530:            }
1531:
1532:            /**
1533:             * Set the TableDataSorter object used to sort rows.
1534:             *
1535:             * @param sorter The TableDataSorter object used to sort rows.
1536:             */
1537:            public void setTableDataSorter(TableDataSorter sorter) {
1538:                // Method is overriden because TableDataSorter is not serializable.
1539:                this .sorter = sorter;
1540:            }
1541:
1542:            /**
1543:             * Set SortCriteria objects for the TableDataSorter instance used by this
1544:             * component. 
1545:             * <p>
1546:             * Note: This method clears the cached sort, then resets pagination to the 
1547:             * first page per UI guidelines.
1548:             * </p>
1549:             * @param sortCriteria An array of SortCriteria objects defining the sort
1550:             * order on this TableDataSorter.
1551:             */
1552:            public void setSortCriteria(SortCriteria[] sortCriteria) {
1553:                clearSort();
1554:                getTableDataSorter().setSortCriteria(sortCriteria);
1555:            }
1556:
1557:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1558:            // State methods
1559:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1560:
1561:            /**
1562:             * Restore the state of this component.
1563:             */
1564:            public void restoreState(FacesContext context, Object state) {
1565:                Object values[] = (Object[]) state;
1566:                super .restoreState(context, values[0]);
1567:                saved = (Map) values[1];
1568:                setPaginated(((Boolean) values[2]).booleanValue());
1569:
1570:                // Note: When the iterate method is called (during the decode, validate,
1571:                // update phases), the previously displayed sort must be used to iterate
1572:                // over the previously displayed children. If child values have changed
1573:                // (e.g., TableSelectPhaseListener has cleared checkbox state after the
1574:                // rendering phase), a new sort would not represent the same rows and
1575:                // state may be lost. Thus, we must restore the previously sorted RowKey
1576:                // objects.
1577:
1578:                // Restore SortCriteria.
1579:                TableDataSorter sorter = getTableDataSorter();
1580:                sorter.setSortCriteria((SortCriteria[]) values[3]);
1581:
1582:                // Restore FilterCriteria.
1583:                TableDataFilter filter = getTableDataFilter();
1584:                filter.setFilterCriteria((FilterCriteria[]) values[4]);
1585:
1586:                // Restore previously filtered and sorted RowKey objects.
1587:                Properties properties = getProperties();
1588:                if (properties != null) {
1589:                    properties.setFilteredRowKeys((RowKey[]) values[5]);
1590:                    properties.setSortedRowKeys((RowKey[]) values[6]);
1591:                } else {
1592:                    log("restoreState", //NOI18N
1593:                            "Cannot save sorted and filtered row keys, Properties is null"); //NOI18N
1594:                }
1595:            }
1596:
1597:            /**
1598:             * Save the state of this component.
1599:             *
1600:             * @return An array of Object values.
1601:             */
1602:            public Object saveState(FacesContext context) {
1603:                Object values[] = new Object[8];
1604:                values[0] = super .saveState(context);
1605:                values[1] = saved;
1606:                values[2] = isPaginated() ? Boolean.TRUE : Boolean.FALSE;
1607:                values[3] = getTableDataSorter().getSortCriteria(); // Save SortCriteria.
1608:                values[4] = getTableDataFilter().getFilterCriteria(); // Save FilterCriteria.
1609:                values[5] = getFilteredRowKeys(); // Save filtered RowKey objects.
1610:                values[6] = getSortedRowKeys(); // Save sorted RowKey objects.
1611:                return values;
1612:            }
1613:
1614:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1615:            // UIComponent methods
1616:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1617:
1618:            /**
1619:             * Set the ValueBinding used to calculate the value for the specified
1620:             * attribute or property name, if any.  In addition, if a ValueBinding is
1621:             * set for the value property, remove any synthesized TableDataProvider for
1622:             * the data previously bound to this component.
1623:             *
1624:             * @param name Name of the attribute or property for which to set a
1625:             * ValueBinding.
1626:             * @param binding The ValueBinding to set, or null to remove any currently
1627:             * set ValueBinding.
1628:             *
1629:             * @exception IllegalArgumentException If name is one of sourceVar.
1630:             * @exception NullPointerException If name is null.
1631:             */
1632:            public void setValueBinding(String name, ValueBinding binding) {
1633:                if ("sourceData".equals(name)) { //NOI18N
1634:                    init();
1635:                } else if ("sourceVar".equals(name)) { //NOI18N
1636:                    log("setValueBinding", "sourceVar cannot equal given name"); //NOI18N
1637:                    throw new IllegalArgumentException();
1638:                }
1639:                super .setValueBinding(name, binding);
1640:            }
1641:
1642:            /**
1643:             * Return a client identifier for this component that includes the current
1644:             * value of the RowKey property, if it is not set to null. This implies that
1645:             * multiple calls to getClientId() may return different results, but ensures
1646:             * that child components can themselves generate row-specific client
1647:             * identifiers (since TableRowGroup is a NamingContainer).
1648:             *
1649:             * @exception NullPointerException if FacesContext is null.
1650:             * @return The client id.
1651:             */
1652:            public String getClientId(FacesContext context) {
1653:                if (context == null) {
1654:                    log("getClientId",
1655:                            "Cannot obtain client Id, FacesContext is null"); //NOI18N
1656:                    throw new NullPointerException();
1657:                }
1658:
1659:                String baseClientId = super .getClientId(context);
1660:                if (getRowKey() != null) {
1661:                    return (baseClientId + NamingContainer.SEPARATOR_CHAR + getRowKey()
1662:                            .getRowId());
1663:                } else {
1664:                    return (baseClientId);
1665:                }
1666:            }
1667:
1668:            /**
1669:             * Override the default UIComponentBase.queueEvent() processing to wrap any
1670:             * queued events in a wrapper so that we can reset the current RowKey in
1671:             * broadcast().
1672:             *
1673:             * @param event FacesEvent to be queued.
1674:             *
1675:             * @exception IllegalStateException If this component is not a descendant
1676:             * of a UIViewRoot.
1677:             * @exception NullPointerException If FacesEvent is null.
1678:             */
1679:            public void queueEvent(FacesEvent event) {
1680:                super .queueEvent(new WrapperEvent(this , event, getRowKey()));
1681:            }
1682:
1683:            /**
1684:             * Override the default UIComponentBase.broadcast() processing to unwrap any
1685:             * wrapped FacesEvent and reset the current RowKey, before the event is
1686:             * actually broadcast. For events that we did not wrap (in queueEvent()), 
1687:             * default processing will occur.
1688:             *
1689:             * @param event The FacesEvent to be broadcast.
1690:             *
1691:             * @exception AbortProcessingException Signal the JavaServer Faces
1692:             * implementation that no further processing on the current event
1693:             * should be performed.
1694:             * @exception IllegalArgumentException if the implementation class
1695:             * of this FacesEvent is not supported by this component.
1696:             * @exception NullPointerException if FacesEvent is null.
1697:             */
1698:            public void broadcast(FacesEvent event)
1699:                    throws AbortProcessingException {
1700:                if (!(event instanceof  WrapperEvent)) {
1701:                    super .broadcast(event);
1702:                    return;
1703:                }
1704:
1705:                // Set up the correct context and fire our wrapped event
1706:                WrapperEvent revent = (WrapperEvent) event;
1707:                RowKey oldRowKey = getRowKey();
1708:                setRowKey(revent.getRowKey());
1709:                FacesEvent rowEvent = revent.getFacesEvent();
1710:                rowEvent.getComponent().broadcast(rowEvent);
1711:                setRowKey(oldRowKey);
1712:                return;
1713:            }
1714:
1715:            /**
1716:             * In addition to the default behavior, ensure that any saved per-row state
1717:             * for our child input components is discarded unless it is needed to
1718:             * rerender the current page with errors.
1719:             *
1720:             * @param context FacesContext for the current request.
1721:             *
1722:             * @exception IOException if an input/output error occurs while rendering.
1723:             * @exception NullPointerException if FacesContext is null.
1724:             */
1725:            public void encodeBegin(FacesContext context) throws IOException {
1726:                // Clear objects cached during the decode, validate, and update phases
1727:                // so nested tables can render new TableDataProvider objects.
1728:                if (isNestedWithinTableRowGroup()) {
1729:                    init();
1730:                }
1731:                if (!keepSaved(context)) {
1732:                    saved = new HashMap();
1733:                }
1734:                super .encodeBegin(context);
1735:            }
1736:
1737:            /**
1738:             * Override the default UIComponentBase.processDecodes() processing to
1739:             * perform the following steps.
1740:             *
1741:             * <ul>
1742:             * <li>If the rendered property of this UIComponent is false, skip further
1743:             *     processing.</li>
1744:             * <li>Set the current RowKey to null.</li>
1745:             * <li>Call the processDecodes() method of all facets of this TableRowGroup,
1746:             *     in the order determined by a call to getFacets().keySet().iterator().</li>
1747:             * <li>Call the processDecodes() method of all facets of the TableColumn
1748:             *     children of this TableRowGroup.</li>
1749:             * <li>Iterate over the set of rows that were included when this component
1750:             *     was rendered (i.e. those defined by the first and rows properties),
1751:             *     performing the following processing for each row:</li>
1752:             * <li>Set the current RowKey to the appropriate value for this row.</li>
1753:             * <li>If isRowAvailable() returns true, iterate over the children
1754:             *     components of each TableColumn child of this TableRowGroup component,
1755:             *     calling the processDecodes() method for each such child.</li>
1756:             * <li>Set the current RowKey to null.</li>
1757:             * <li>Call the decode() method of this component.</li>
1758:             * <li>If a RuntimeException is thrown during decode processing, call 
1759:             *    FacesContext.renderResponse() and re-throw the exception.</li>
1760:             * </ul>
1761:             *
1762:             * @param context FacesContext for the current request.
1763:             *
1764:             * @exception NullPointerException if FacesContext is null.
1765:             */
1766:            public void processDecodes(FacesContext context) {
1767:                if (context == null) {
1768:                    log("processDecodes", "Cannot decode, FacesContext is null"); //NOI18N
1769:                    throw new NullPointerException();
1770:                }
1771:                if (!isRendered()) {
1772:                    log("processDecodes",
1773:                            "Component not rendered, nothing to decode"); //NOI18N
1774:                    return;
1775:                }
1776:                if (saved == null || !keepSaved(context)) {
1777:                    saved = new HashMap(); // We don't need saved state here
1778:                }
1779:                iterate(context, PhaseId.APPLY_REQUEST_VALUES);
1780:                decode(context);
1781:            }
1782:
1783:            /**
1784:             * Override the default UIComponentBase.processValidators() processing to
1785:             * perform the following steps.
1786:             *
1787:             * <ul>
1788:             * <li>If the rendered property of this UIComponent is false, skip further
1789:             *     processing.</li>
1790:             * <li>Set the current RowKey to null.</li>
1791:             * <li>Call the processValidators() method of all facets of this
1792:             *     TableRowGroup, in the order determined by a call to 
1793:             *     getFacets().keySet().iterator().</li>
1794:             * <li>Call the processValidators() method of all facets of the TableColumn
1795:             *     children of this TableRowGroup.</li>
1796:             * <li>Iterate over the set of rows that were included when this component
1797:             *     was rendered (i.e. those defined by the first and rows properties),
1798:             *     performing the following processing for each row:</li>
1799:             * <li>Set the current RowKey to the appropriate value for this row.</li>
1800:             * <li>If isRowAvailable() returns true, iterate over the children
1801:             *     components of each TableColumn child of this TableRowGroup component,
1802:             *     calling the processValidators() method for each such child.</li>
1803:             * <li>Set the current RowKey to null.</li>
1804:             * </ul>
1805:             *
1806:             * @param context FacesContext for the current request.
1807:             *
1808:             * @exception NullPointerException if FacesContext is null.
1809:             */
1810:            public void processValidators(FacesContext context) {
1811:                if (context == null) {
1812:                    log("processValidators",
1813:                            "Cannot validate, FacesContext is null"); //NOI18N
1814:                    throw new NullPointerException();
1815:                }
1816:                if (!isRendered()) {
1817:                    log("processValidators", //NOI18N
1818:                            "Component not rendered, nothing to validate"); //NOI18N
1819:                    return;
1820:                }
1821:                iterate(context, PhaseId.PROCESS_VALIDATIONS);
1822:                // This is not a EditableValueHolder, so no further processing is required
1823:            }
1824:
1825:            /**
1826:             * Override the default UIComponentBase.processUpdates() processing to
1827:             * perform the following steps.
1828:             *
1829:             * <ul>
1830:             * <li>If the rendered property of this UIComponent is false, skip further
1831:             *     processing.</li>
1832:             * <li>Set the current RowKey to null.</li>
1833:             * <li>Call the processUpdates() method of all facets of this TableRowGroup,
1834:             *     in the order determined by a call to getFacets().keySet().iterator().</li>
1835:             * <li>Call the processUpdates() method of all facets of the TableColumn
1836:             *     children of this TableRowGroup.</li>
1837:             * <li>Iterate over the set of rows that were included when this component
1838:             *     was rendered (i.e. those defined by the first and rows properties),
1839:             *     performing the following processing for each row:</li>
1840:             * <li>Set the current RowKey to the appropriate value for this row.</li>
1841:             * <li>If isRowAvailable() returns true, iterate over the children
1842:             *     components of each TableColumn child of this TableRowGroup component,
1843:             *     calling the processUpdates() method for each such child.</li>
1844:             * <li>Set the current RowKey to null.</li>
1845:             * </ul>
1846:             *
1847:             * @param context FacesContext for the current request.
1848:             *
1849:             * @exception NullPointerException if FacesContext is null.
1850:             */
1851:            public void processUpdates(FacesContext context) {
1852:                if (context == null) {
1853:                    log("processUpdates", "Cannot update, FacesContext is null"); //NOI18N
1854:                    throw new NullPointerException();
1855:                }
1856:                if (!isRendered()) {
1857:                    log("processUpdates",
1858:                            "Component not rendered, nothing to update"); //NOI18N
1859:                    return;
1860:                }
1861:                iterate(context, PhaseId.UPDATE_MODEL_VALUES);
1862:
1863:                // Set collapsed property applied client-side.
1864:                UIComponent header = getFacet(GROUP_HEADER_ID);
1865:                UIComponent field = (header != null) ? (UIComponent) header
1866:                        .getFacets().get(TableHeader.COLLAPSED_HIDDEN_FIELD_ID)
1867:                        : null;
1868:                if (field instanceof  HiddenField) {
1869:                    Boolean value = (field != null) ? (Boolean) ((HiddenField) field)
1870:                            .getValue()
1871:                            : null;
1872:                    setCollapsed(value.booleanValue());
1873:                } else {
1874:                    log("processUpdates",
1875:                            "Cannot obtain collapsed hidden field value"); //NOI18N
1876:                }
1877:                // This is not a EditableValueHolder, so no further processing is required
1878:            }
1879:
1880:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1881:            // Private methods
1882:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1883:
1884:            /**
1885:             * Get the properties for this component cached in the request map.
1886:             * <p>
1887:             * Note: Properties may have been cached via the apply request values, 
1888:             * validate, and update phases and must be initialized for the render 
1889:             * response phase. Table components are forced to reinitialize by setting 
1890:             * the cached properties map to null when the table title and actions bar 
1891:             * are rendered. New column and row counts are required each time the table
1892:             * is redisplayed, for example.
1893:             * </p>
1894:             * @return The properties for this component.
1895:             */
1896:            private Properties getProperties() {
1897:                // Get Table ancestor.
1898:                Table table = getTableAncestor();
1899:                if (table == null) {
1900:                    log("getProperties",
1901:                            "Cannot obtain Properties, Table is null"); //NOI18N
1902:                    return null;
1903:                }
1904:
1905:                // Get properties for all components.
1906:                FacesContext context = getFacesContext();
1907:                Map requestMap = context.getExternalContext().getRequestMap();
1908:                String propertiesMapId = REQUEST_KEY_PREFIX
1909:                        + table.getClientId(context) + PROPERTIES;
1910:                Map propertiesMap = (Map) requestMap.get(propertiesMapId);
1911:                if (propertiesMap == null) {
1912:                    propertiesMap = new HashMap();
1913:                    requestMap.put(propertiesMapId, propertiesMap);
1914:                }
1915:
1916:                // Get properties for this component.
1917:                String propertiesId = super .getClientId(context); // Don't append row ID.
1918:                Properties properties = (Properties) propertiesMap
1919:                        .get(propertiesId);
1920:                if (properties == null) {
1921:                    properties = new Properties();
1922:                    propertiesMap.put(propertiesId, properties);
1923:                }
1924:
1925:                return properties;
1926:            }
1927:
1928:            /**
1929:             * Helper method to get Theme objects.
1930:             *
1931:             * @return The current theme.
1932:             */
1933:            private Theme getTheme() {
1934:                return ThemeUtilities.getTheme(getFacesContext());
1935:            }
1936:
1937:            /**
1938:             * Initialize member variables.
1939:             * <p>
1940:             * Note: When ever a new DataProvider is used, UI Guiedlines recommend that
1941:             * pagination should be reset (e.g., remaining on the 4th page of a new set
1942:             * of data makes no sense). However, properties such as the sort and filter 
1943:             * criteria should not automatically be cleared (e.g., there may be 
1944:             * situations where one or both should be left as specified by the user). In
1945:             * this scenario, pagination is set to the first page.
1946:             * </p><p>
1947:             * Note: When ever the underlying DataProvider has changed, cached 
1948:             * properties must be re-evaluated even with server-side state saving -- 
1949:             * bugtraq #6304818.
1950:             * </p>
1951:             */
1952:            private void init() {
1953:                setFirst(0); // Reset to first page.
1954:
1955:                // Get Table ancestor.
1956:                Table table = getTableAncestor();
1957:                if (table == null) {
1958:                    log("init", "Cannot initialize Properties, Table is null"); //NOI18N
1959:                    return;
1960:                }
1961:
1962:                // Get properties for all components.
1963:                FacesContext context = getFacesContext();
1964:                Map requestMap = context.getExternalContext().getRequestMap();
1965:                String propertiesId = REQUEST_KEY_PREFIX
1966:                        + table.getClientId(context) + PROPERTIES;
1967:                Map propertiesMap = (Map) requestMap.get(propertiesId);
1968:
1969:                // Clear all properties cached in request map for this component.
1970:                if (propertiesMap != null) {
1971:                    propertiesMap.put(super .getClientId(context), null);
1972:                } else {
1973:                    log("init", //NOI18N
1974:                            "Cannot initialize Properties, request properties map is null"); //NOI18N
1975:                }
1976:            }
1977:
1978:            /**
1979:             * Helper method to determine if this component is nested within another
1980:             * TableRowGroup component.
1981:             *
1982:             * @return true if this component is nested, else false.
1983:             */
1984:            private boolean isNestedWithinTableRowGroup() {
1985:                UIComponent parent = this ;
1986:                while (null != (parent = parent.getParent())) {
1987:                    if (parent instanceof  TableRowGroup) {
1988:                        return true;
1989:                    }
1990:                }
1991:                return (false);
1992:            }
1993:
1994:            /**
1995:             * Helper method to perform the appropriate phase-specific processing and
1996:             * per-row iteration for the specified phase, as follows:
1997:             *
1998:             * <ul>
1999:             * <li>Set the RowKey property to null, and process the facets
2000:             *     of this TableRowGroup component exactly once.</li>
2001:             * <li>Set the RowKey property to null, and process the facets
2002:             *     of the TableColumn children of this TableRowGroup component exactly
2003:             *     once.</li>
2004:             * <li>Iterate over the relevant rows, based on the first and row
2005:             *     properties, and process the children of the TableColumn children of
2006:             *     this TableRowGroup component once per row.</li>
2007:             * </ul>
2008:             *
2009:             * @param context FacesContext for the current request.
2010:             * @param phaseId PhaseId of the phase we are currently running.
2011:             */
2012:            private void iterate(FacesContext context, PhaseId phaseId) {
2013:                // Note: When the iterate method is called via the processDecode,
2014:                // processValidate, and processUpdate methods), the previously displayed
2015:                // sort must be used to iterate over the previously displayed children.
2016:                // (The previously displayed sort is cached/restored via the 
2017:                // save/restoreState methods.) If child values have changed (e.g., 
2018:                // TableSelectPhaseListener has cleared checkbox state after the 
2019:                // rendering phase), obtaining a new sort here may not represent the 
2020:                // same rows and state may be lost. Thus, don't clear cached properties
2021:                // unless nested.
2022:                if (isNestedWithinTableRowGroup()) {
2023:                    // Re-evaluate even with server-side state saving.
2024:                    init();
2025:                }
2026:
2027:                // Process each facet of this component exactly once.
2028:                setRowKey(null);
2029:                Iterator facets = getFacets().keySet().iterator(); // Get facet keys.
2030:                while (facets.hasNext()) {
2031:                    // Get facet.
2032:                    UIComponent facet = (UIComponent) getFacets().get(
2033:                            facets.next());
2034:                    if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
2035:                        facet.processDecodes(context);
2036:                    } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
2037:                        facet.processValidators(context);
2038:                    } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) {
2039:                        facet.processUpdates(context);
2040:                    } else {
2041:                        log("iterate", //NOI18N
2042:                                "Cannot process component facets, Invalid phase ID"); //NOI18N
2043:                        throw new IllegalArgumentException();
2044:                    }
2045:                }
2046:
2047:                // Process the facet of each TableColumn child exactly once.
2048:                setRowKey(null);
2049:                Iterator kids = getTableColumnChildren();
2050:                while (kids.hasNext()) {
2051:                    TableColumn kid = (TableColumn) kids.next();
2052:                    if (!kid.isRendered()) {
2053:                        log("iterate", //NOI18N
2054:                                "Cannot process TableColumn facets, TableColumn not rendered"); //NOI18N
2055:                        continue;
2056:                    }
2057:                    iterateTableColumnFacets(context, kid, phaseId);
2058:                }
2059:
2060:                // Get rendered row keys.
2061:                RowKey[] rowKeys = getRenderedRowKeys();
2062:                if (rowKeys == null) {
2063:                    log("iterate", //NOI18N
2064:                            "Cannot iterate over TableColumn children, RowKey array is null"); //NOI18N
2065:                    return;
2066:                }
2067:
2068:                // Iterate over the sorted, rendered RowKey objects.
2069:                for (int i = 0; i < rowKeys.length; i++) {
2070:                    setRowKey(rowKeys[i]);
2071:                    if (!isRowAvailable()) {
2072:                        log("iterate", //NOI18N
2073:                                "Cannot iterate over TableColumn children, row not available"); //NOI18N
2074:                        break;
2075:                    }
2076:
2077:                    // Perform phase-specific processing as required on the children
2078:                    // of the TableColumn (facets have been done a single time with
2079:                    // setRowKey(null) already)
2080:                    kids = getTableColumnChildren();
2081:                    while (kids.hasNext()) {
2082:                        TableColumn kid = (TableColumn) kids.next();
2083:                        if (!kid.isRendered()) {
2084:                            log("iterate",
2085:                                    "Cannot process TableColumn, not rendered"); //NOI18N
2086:                            continue;
2087:                        }
2088:                        Iterator grandkids = kid.getChildren().iterator();
2089:                        while (grandkids.hasNext()) {
2090:                            UIComponent grandkid = (UIComponent) grandkids
2091:                                    .next();
2092:                            if (!grandkid.isRendered()) {
2093:                                log("iterate", //NOI18N
2094:                                        "Cannot process TableColumn child, not rendered"); //NOI18N
2095:                                continue;
2096:                            }
2097:                            iterateTableColumnChildren(context, grandkid,
2098:                                    phaseId);
2099:                        }
2100:                    }
2101:                }
2102:                setRowKey(null); // Clean up after ourselves.
2103:            }
2104:
2105:            /**
2106:             * Helper method to iterate over nested TableColumn facets.
2107:             *
2108:             * @param context FacesContext for the current request.
2109:             * @param component The TableColumn component to be rendered.
2110:             * @param phaseId PhaseId of the phase we are currently running.
2111:             */
2112:            private void iterateTableColumnFacets(FacesContext context,
2113:                    TableColumn component, PhaseId phaseId) {
2114:                if (component == null) {
2115:                    log("iterateTableColumnFacets", //NOI18N
2116:                            "Cannot iterate over TableColumn facets, TableColumn is null"); //NOI18N
2117:                    return;
2118:                }
2119:
2120:                Iterator kids = component.getTableColumnChildren();
2121:                if (kids.hasNext()) {
2122:                    while (kids.hasNext()) {
2123:                        TableColumn col = (TableColumn) kids.next();
2124:                        iterateTableColumnFacets(context, col, phaseId);
2125:                    }
2126:                } else {
2127:                    // Get facet keys.
2128:                    Iterator facets = component.getFacets().keySet().iterator();
2129:                    while (facets.hasNext()) {
2130:                        // Get facet.
2131:                        UIComponent facet = (UIComponent) component.getFacets()
2132:                                .get(facets.next());
2133:                        if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
2134:                            facet.processDecodes(context);
2135:                        } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
2136:                            facet.processValidators(context);
2137:                        } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) {
2138:                            facet.processUpdates(context);
2139:                        } else {
2140:                            log("iterateTableColumnFacets", //NOI18N
2141:                                    "Cannot iterate over TableColumn facets, Invalid phase ID"); //NOI18N
2142:                            throw new IllegalArgumentException();
2143:                        }
2144:                    }
2145:                }
2146:            }
2147:
2148:            /**
2149:             * Helper method to iterate over nested TableColumn children.
2150:             *
2151:             * @param context FacesContext for the current request.
2152:             * @param component The TableColumn component to be rendered.
2153:             * @param phaseId PhaseId of the phase we are currently running.
2154:             */
2155:            private void iterateTableColumnChildren(FacesContext context,
2156:                    UIComponent component, PhaseId phaseId) {
2157:                if (component == null) {
2158:                    log("iterateTableColumnChildren", //NOI18N
2159:                            "Cannot iterate over TableColumn children, UIComponent is null"); //NOI18N
2160:                    return;
2161:                }
2162:
2163:                // Do not process nested TableColumn components so facets will not be 
2164:                // decoded for each row of the table.
2165:                if (component instanceof  TableColumn) {
2166:                    Iterator kids = component.getChildren().iterator();
2167:                    if (kids.hasNext()) {
2168:                        while (kids.hasNext()) {
2169:                            UIComponent kid = (UIComponent) kids.next();
2170:                            iterateTableColumnChildren(context, kid, phaseId);
2171:                        }
2172:                    }
2173:                } else {
2174:                    if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
2175:                        component.processDecodes(context);
2176:                    } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
2177:                        component.processValidators(context);
2178:                    } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) {
2179:                        component.processUpdates(context);
2180:                    } else {
2181:                        log("iterateTableColumnChildren", //NOI18N
2182:                                "Cannot iterate over TableColumn children, Invalid phase ID"); //NOI18N
2183:                        throw new IllegalArgumentException();
2184:                    }
2185:                }
2186:            }
2187:
2188:            /**
2189:             * Helper method to get flag indicating that we need to keep the saved 
2190:             * per-child state information. This will be the case if any of the
2191:             * following are true:
2192:             *
2193:             * <ul>
2194:             * <li>Any of the saved state corresponds to components that have messages
2195:             *     that must be displayed.</li>
2196:             * <li>This TableRowGroup instance is nested inside of another TableRowGroup
2197:             *     instance.</li>
2198:             * </ul>
2199:             *
2200:             * @param context FacesContext for the current request.
2201:             * @return true if state should be saved, else false.
2202:             */
2203:            private boolean keepSaved(FacesContext context) {
2204:                Iterator clientIds = saved.keySet().iterator();
2205:                while (clientIds.hasNext()) {
2206:                    String clientId = (String) clientIds.next();
2207:
2208:                    // Fix for immediate property -- see bugtraq #6269737.
2209:                    SavedState state = (SavedState) saved.get(clientId);
2210:                    if (state != null && state.getSubmittedValue() != null) {
2211:                        return (true);
2212:                    }
2213:                }
2214:                //<RAVE>
2215:                //bug 6377769 -- check all messages for an error, not just the messages on EditableValueHolders within the TableRowGroup
2216:                Iterator messages = context.getMessages();
2217:                while (messages.hasNext()) {
2218:                    FacesMessage message = (FacesMessage) messages.next();
2219:                    if (message.getSeverity().compareTo(
2220:                            FacesMessage.SEVERITY_ERROR) >= 0) {
2221:                        return (true);
2222:                    }
2223:                }
2224:                //</RAVE>
2225:                return (isNestedWithinTableRowGroup());
2226:            }
2227:
2228:            /**
2229:             * Log fine messages.
2230:             */
2231:            private void log(String method, String message) {
2232:                // Get class.
2233:                Class clazz = this .getClass();
2234:                if (LogUtil.fineEnabled(clazz)) {
2235:                    // Log method name and message.
2236:                    LogUtil.fine(clazz, clazz.getName() + "." + method + ": "
2237:                            + message); //NOI18N
2238:                }
2239:            }
2240:
2241:            /**
2242:             * Helper method to restore state information for all descendant components,
2243:             * as described for setRowKey().
2244:             */
2245:            private void restoreDescendantState() {
2246:                FacesContext context = getFacesContext();
2247:                Iterator kids = getTableColumnChildren();
2248:                while (kids.hasNext()) {
2249:                    TableColumn kid = (TableColumn) kids.next();
2250:                    if (!kid.isRendered()) {
2251:                        continue;
2252:                    }
2253:                    restoreDescendantState(kid, context);
2254:                }
2255:            }
2256:
2257:            /**
2258:             * Helper method to restore state information for the specified component
2259:             * and its descendants.
2260:             *
2261:             * @param component Component for which to restore state information.
2262:             * @param context FacesContext for the current request.
2263:             */
2264:            private void restoreDescendantState(UIComponent component,
2265:                    FacesContext context) {
2266:                // Reset the client identifier for this component
2267:                String id = component.getId();
2268:                component.setId(id); // Forces client id to be reset
2269:
2270:                // Restore state for this component (if it is a EditableValueHolder)
2271:                if (component instanceof  EditableValueHolder) {
2272:                    EditableValueHolder input = (EditableValueHolder) component;
2273:                    String clientId = component.getClientId(context);
2274:                    SavedState state = (SavedState) saved.get(clientId);
2275:                    if (state == null) {
2276:                        state = new SavedState();
2277:                    }
2278:                    input.setValue(state.getValue());
2279:                    input.setValid(state.isValid());
2280:                    input.setSubmittedValue(state.getSubmittedValue());
2281:                    // This *must* be set after the call to setValue(), since
2282:                    // calling setValue() always resets "localValueSet" to true.
2283:                    input.setLocalValueSet(state.isLocalValueSet());
2284:
2285:                    ConversionUtilities.restoreRenderedValueState(context,
2286:                            component);
2287:                }
2288:
2289:                // Restore state for children of this component
2290:                Iterator kids = component.getChildren().iterator();
2291:                while (kids.hasNext()) {
2292:                    restoreDescendantState((UIComponent) kids.next(), context);
2293:                }
2294:            }
2295:
2296:            /**
2297:             * Helper method to save state information for all descendant components, as
2298:             * described for setRowKey().
2299:             */
2300:            private void saveDescendantState() {
2301:                FacesContext context = getFacesContext();
2302:                Iterator kids = getTableColumnChildren();
2303:                while (kids.hasNext()) {
2304:                    TableColumn kid = (TableColumn) kids.next();
2305:                    if (!kid.isRendered()) {
2306:                        log("saveDescendantState", //NOI18N
2307:                                "Cannot save descendant state, TableColumn not rendered"); //NOI18N
2308:                        continue;
2309:                    }
2310:                    saveDescendantState(kid, context);
2311:                }
2312:            }
2313:
2314:            /**
2315:             * Helper method to save state information for the specified component and
2316:             * its descendants.
2317:             *
2318:             * @param component Component for which to save state information.
2319:             * @param context FacesContext for the current request.
2320:             */
2321:            private void saveDescendantState(UIComponent component,
2322:                    FacesContext context) {
2323:
2324:                // Save state for this component (if it is a EditableValueHolder)
2325:                if (component instanceof  EditableValueHolder) {
2326:                    EditableValueHolder input = (EditableValueHolder) component;
2327:                    String clientId = component.getClientId(context);
2328:                    SavedState state = (SavedState) saved.get(clientId);
2329:                    if (state == null) {
2330:                        state = new SavedState();
2331:                        saved.put(clientId, state);
2332:                    }
2333:                    state.setValue(input.getLocalValue());
2334:                    state.setValid(input.isValid());
2335:                    state.setSubmittedValue(input.getSubmittedValue());
2336:                    state.setLocalValueSet(input.isLocalValueSet());
2337:
2338:                    ConversionUtilities.saveRenderedValueState(context,
2339:                            component);
2340:                }
2341:
2342:                // Note: Don't bother logging messages here -- too many messages.
2343:                // For example, staticText is not an EditableValueHolder.
2344:
2345:                // Save state for children of this component
2346:                Iterator kids = component.getChildren().iterator();
2347:                while (kids.hasNext()) {
2348:                    saveDescendantState((UIComponent) kids.next(), context);
2349:                }
2350:            }
2351:
2352:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2353:            // Inner classes
2354:            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2355:
2356:            /**
2357:             * Object used to cache properties in the request.
2358:             */
2359:            private class Properties {
2360:                // The TableRowDataProvider associated with this component, lazily
2361:                // instantiated if requested. This object is not part of the saved and
2362:                // restored state of the component.
2363:                private TableRowDataProvider provider = null;
2364:
2365:                // Array containing currently filtered RowKey objects.
2366:                private RowKey[] filteredRowKeys = null;
2367:
2368:                // Array containing currently sorted RowKey objects. This sort will be 
2369:                // cached and used to iterate over children during the decode, validate,
2370:                // and update phases.
2371:                private RowKey[] sortedRowKeys = null;
2372:
2373:                // A List of TableColumn children found for this component.
2374:                private List tableColumnChildren = null;
2375:
2376:                // The number of columns to be rendered.
2377:                private int columnCount = -1;
2378:
2379:                /** Default constructor. */
2380:                public Properties() {
2381:                }
2382:
2383:                /**
2384:                 * Get the number of columns found for this component that have a 
2385:                 * rendered property of true.
2386:                 *
2387:                 * @return The number of rendered columns.
2388:                 */
2389:                public int getColumnCount() {
2390:                    return columnCount;
2391:                }
2392:
2393:                /**
2394:                 * Set the number of columns found for this component that have a
2395:                 * rendered property of true.
2396:                 *
2397:                 * @param columnCount The number of rendered columns.
2398:                 */
2399:                public void setColumnCount(int columnCount) {
2400:                    this .columnCount = columnCount;
2401:                }
2402:
2403:                /**
2404:                 * Get an array containing filtered RowKey objects.
2405:                 *
2406:                 * @return An array containing filtered RowKey objects.
2407:                 */
2408:                public RowKey[] getFilteredRowKeys() {
2409:                    return filteredRowKeys;
2410:                }
2411:
2412:                /**
2413:                 * Set an array containing filtered RowKey objects.
2414:                 *
2415:                 * @param filteredRowKeys An array containing filtered RowKey objects.
2416:                 */
2417:                public void setFilteredRowKeys(RowKey[] filteredRowKeys) {
2418:                    this .filteredRowKeys = filteredRowKeys;
2419:                }
2420:
2421:                /**
2422:                 * Get an array containing sorted RowKey objects.
2423:                 *
2424:                 * @return An array containing sorted RowKey objects.
2425:                 */
2426:                public RowKey[] getSortedRowKeys() {
2427:                    return sortedRowKeys;
2428:                }
2429:
2430:                /**
2431:                 * Set an array containing sorted RowKey objects.
2432:                 *
2433:                 * @param sortedRowKeys An array containing sorted RowKey objects.
2434:                 */
2435:                public void setSortedRowKeys(RowKey[] sortedRowKeys) {
2436:                    this .sortedRowKeys = sortedRowKeys;
2437:                }
2438:
2439:                /**
2440:                 * Get the TableColumn children found for this component.
2441:                 *
2442:                 * @return The TableColumn children.
2443:                 */
2444:                public List getTableColumnChildren() {
2445:                    return tableColumnChildren;
2446:                }
2447:
2448:                /**
2449:                 * Set the TableColumn children found for this component.
2450:                 *
2451:                 * @param tableColumnChildren The TableColumn children.
2452:                 */
2453:                public void setTableColumnChildren(List tableColumnChildren) {
2454:                    this .tableColumnChildren = tableColumnChildren;
2455:                }
2456:
2457:                /**
2458:                 * Get the TableRowDataProvider object representing the data objects
2459:                 * that we will iterate over in this component's rendering.
2460:                 *
2461:                 * @return The TableRowDataProvider object.
2462:                 */
2463:                public TableRowDataProvider getTableRowDataProvider() {
2464:                    return provider;
2465:                }
2466:
2467:                /**
2468:                 * Set the TableRowDataProvider object representing the data objects
2469:                 * that we will iterate over in this component's rendering.
2470:                 *
2471:                 * @return The TableRowDataProvider object.
2472:                 */
2473:                public void setTableRowDataProvider(
2474:                        TableRowDataProvider provider) {
2475:                    this .provider = provider;
2476:                }
2477:            }
2478:        }
2479:
2480:        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2481:        // Private classes
2482:        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2483:
2484:        // Private class to represent saved state information.
2485:        class SavedState implements  Serializable {
2486:            private Object submittedValue;
2487:            private boolean valid = true;
2488:            private Object value;
2489:            private boolean localValueSet;
2490:
2491:            public Object getSubmittedValue() {
2492:                return (this .submittedValue);
2493:            }
2494:
2495:            public void setSubmittedValue(Object submittedValue) {
2496:                this .submittedValue = submittedValue;
2497:            }
2498:
2499:            public boolean isValid() {
2500:                return (this .valid);
2501:            }
2502:
2503:            public void setValid(boolean valid) {
2504:                this .valid = valid;
2505:            }
2506:
2507:            public Object getValue() {
2508:                return (this .value);
2509:            }
2510:
2511:            public void setValue(Object value) {
2512:                this .value = value;
2513:            }
2514:
2515:            public boolean isLocalValueSet() {
2516:                return (this .localValueSet);
2517:            }
2518:
2519:            public void setLocalValueSet(boolean localValueSet) {
2520:                this .localValueSet = localValueSet;
2521:            }
2522:
2523:            public String toString() {
2524:                return ("submittedValue: " + submittedValue + " value: "
2525:                        + value + //NOI18N
2526:                        " localValueSet: " + localValueSet); //NOI18N
2527:            }
2528:        }
2529:
2530:        // Private class to wrap an event with a RowKey.
2531:        class WrapperEvent extends FacesEvent {
2532:            private FacesEvent event = null;
2533:            private RowKey rowKey = null;
2534:
2535:            public WrapperEvent(UIComponent component, FacesEvent event,
2536:                    RowKey rowKey) {
2537:                super (component);
2538:                this .event = event;
2539:                this .rowKey = rowKey;
2540:            }
2541:
2542:            public FacesEvent getFacesEvent() {
2543:                return (this .event);
2544:            }
2545:
2546:            public RowKey getRowKey() {
2547:                return (this .rowKey);
2548:            }
2549:
2550:            public PhaseId getPhaseId() {
2551:                return (this .event.getPhaseId());
2552:            }
2553:
2554:            public void setPhaseId(PhaseId phaseId) {
2555:                this .event.setPhaseId(phaseId);
2556:            }
2557:
2558:            public boolean isAppropriateListener(FacesListener listener) {
2559:                return (false);
2560:            }
2561:
2562:            public void processListener(FacesListener listener) {
2563:                throw new IllegalStateException();
2564:            }
2565:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.