| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
| <!-- $Id$ --> |
| <html> |
| <head> |
| <title>contrib:FormTable</title> |
| <link rel="stylesheet" type="text/css" href="Tapestry.css" title="style"> |
| <STYLE type=text/css> |
| .example TD { TEXT-ALIGN: center } |
| .code { FONT-FAMILY: Courier } |
| .examples A { color: black } |
| </STYLE> |
| </head> |
| |
| <body> |
| <table border="0" cellpadding="0" cellspacing="0" width="100%"> |
| <tr><!-- Previous component in alphabetical order. --> |
| <td align="left"><A href="contrib.FormConditional.html"><IMG alt="contrib:FormConditional" src="common-images/prev.png"></a></td> |
| <td align="middle"><A href="index.html"><IMG alt="Component Index" src="common-images/home.png" ></a></td><!-- Next component in alphabetical order. --> |
| <td align="right"><A href="contrib.InspectorButton.html"><IMG alt="contrib:InspectorButton" src="common-images/next.png"></a></td> |
| <tr> |
| <tr> |
| <td colspan="3"><hr></td> |
| </tr> |
| <tr> |
| <td colspan="3"> |
| <table border="0" cellpadding="4" cellspacing="4" width="100%"> |
| |
| <tr valign="top"> |
| <td> |
| <table> |
| <tr> |
| <td><font size="+2"><b>contrib:FormTable</b></font></td> |
| </tr> |
| <tr> |
| <td> |
| <A href="../api/org/apache/tapestry/contrib/table/components/FormTable.html">org.apache.tapestry.contrib.table.components.FormTable</a> |
| </td> |
| </tr> |
| </table> |
| </td> |
| <td> |
| <table align="right" valign="middle" bgcolor="#c0c0c0" cellpadding="8"> |
| <tr> |
| <td>Visual Component</td> |
| </tr> |
| </table> |
| </td> |
| </tr> |
| |
| <tr valign="center"> |
| <td colspan="2"> </td> |
| </tr> |
| |
| <tr> |
| <td colspan="2"> |
| <b>Description</b> |
| <br> |
| A version of the <A HREF="contrib.Table.html"><CODE>Table</CODE></A> component |
| designed for use in a form. Like Table, this component allows you to present a sortable and pagable table |
| simply and easily. It also stores the items it dispays in hidden fields in the form, |
| so that they are identical during the rewind cycle when the form is submitted, |
| and generates links that submit the form, so that any other form information is preserved. |
| <p> |
| The differences between FormTable and Table are the following: |
| <ul> |
| <li> It uses TableFormRows instead of TableRows |
| which stores the rendered items in hidden form fields |
| <li> It uses TableFormPages instead of TablePages |
| which generates links that submit the form besides changing the page |
| <li> If the columns are defined using a string in the <code>columns</code> parameter, |
| it ensures that the headers of the generated columns contain links that also submit the form. |
| </ul> |
| <p> |
| The FormTable component allows you to manipulate its appearance by allowing you |
| to define the 'class' attributes of its internal elements. If you want to change |
| the structure of the table, however, you can instead build your own using the |
| lower level components |
| <A HREF="contrib.TableView.html"><CODE>TableView</CODE></A>, |
| <A HREF="contrib.TablePages.html"><CODE>TablePages</CODE></A>, |
| <A HREF="contrib.TableFormPages.html"><CODE>TableFormPages</CODE></A>, |
| <A HREF="contrib.TableColumns.html"><CODE>TableColumns</CODE></A>, |
| <A HREF="contrib.TableRows.html"><CODE>TableRows</CODE></A>, |
| <A HREF="contrib.TableFormRows.html"><CODE>TableFormRows</CODE></A>, |
| and |
| <A HREF="contrib.TableValues.html"><CODE>TableValues</CODE></A>. |
| <p> |
| The FormTable component delegates the handling of the table model and related |
| activities to the <A HREF="contrib.TableView.html"><CODE>TableView</CODE></A>, |
| and more detailed information about the process can be found in the |
| documentation of that class. |
| </td> |
| </tr> |
| |
| <tr> |
| <td colspan="2"> |
| <b>Providing the data</b> |
| |
| <p> |
| There are many ways to provide the component with the data it has to render, |
| but here are the three major ones: |
| |
| <ol> |
| <li> The data is passed to the <code>source</code> parameter in the form of an array, |
| a collection, or an iterator, and the table columns are defined using the |
| <code>columns</code> parameter (see further for details). |
| Both of these parameters will be evaluated at every request by default, |
| so changes in the data or the table columns will be displayed immediately. |
| <p> |
| This is the easiest and most straightforward approach. It has one performance limitation, |
| however - if the table is sorting the data according to a given column, |
| the sorting will be performed at every request. |
| The next methods provide ways to resolve this possible performance issue. |
| <p></p> |
| |
| <li> The data is passed to the <code>source</code> parameter via an object that |
| implements the <A HREF="../api/org/apache/tapestry/contrib/table/model/IBasicTableModel.html"><CODE>IBasicTableModel</CODE></A> |
| interface. Through that interface you are given the sorting column (if any) and |
| the numbers of the items that will be displayed on the current page. |
| You then need to provide the component with the corresponding data. |
| <p> |
| This method allows you to perform the sorting in the database and load only the data |
| that will be displayed on the current page |
| (e.g. by using the ORDER BY, LIMIT, and OFFSET clauses in SQL) |
| and hence it could be far more efficient. |
| <p></p> |
| |
| <li> All of the information (data, columns, state) is packaged in an |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableModel.html"><CODE>ITableModel</CODE></A> |
| and is passed to the <code>tableModel</code> parameter. |
| <p> |
| This approach allows greatest flexibility, but is recommended only for advanced users of the Table components. |
| |
| </ol> |
| |
| <p></p> |
| </td> |
| </tr> |
| |
| |
| <tr> |
| <td colspan="2"> |
| <b>Defining the columns</b> |
| |
| <p> |
| If you define the table columns using the <code>columns</code> parameter, you can either |
| provide a list of <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableColumn.html"><code>ITableColumn</code></A> |
| objects, each defining a column in the table, or you can define the columns using |
| a string that describes each column. |
| <p> |
| The string describing the columns must be formatted in the following way: |
| <ul> |
| <li>The column definitions in the string are separated by commas |
| <p> |
| <li>Each column definition must be of one of the following types:<p> |
| <dl> |
| <dd>id</dd> |
| <dd>id:expression</dd> |
| <dd>id:description:expression</dd> |
| </dl> |
| <br> |
| Here the <b>id</b> defines the identification of the column, the <b>expression</b> is an |
| OGNL expression that extracts the column value from the row object, and <b>description</b> |
| is the title of the column if it is not defined otherwise. |
| <p> |
| Each column definition may be prefixed by the <b>!</b> character, |
| which identifies the column as non-sortable. |
| <p> |
| If defined, a Block with a name that is starts with the column id and |
| ends with <i>ColumnValue</i> will be used to render the column values. |
| Similarly, a Block with a name that starts with the column id and |
| ends with <i>ColumnHeader</i> will be used to render the column headers. |
| <p> |
| Finally, the title of the column will be taken from translation strings of the component |
| by using the column id as a key. |
| <p> |
| Please see the <SPAN class=code>LocaleSelection</SPAN> component for examples. |
| <p> |
| <li>A column definition may also be of the type |
| <p> |
| <dl> |
| <dd>=expression</dd> |
| </dl> |
| <br> |
| in which case it identifies an OGNL expression that returns an |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableColumn.html"><code>ITableColumn</code></A> |
| object defining the column. |
| <p> |
| <li>The full description string may be prefixed by the <b>*</b> character, |
| which means that the table is to be rendered within a form, and the |
| column headers must submit the form if they are clickable (i.e. if the column is sortable). |
| </ul> |
| <p> |
| Here is an example of the use of a description string to define columns: |
| <pre> |
| columns="locale:toString(), =currencyColumn, verbosity:Verbosity:currentRowVerbosity, !delete" |
| </pre> |
| |
| <p></p> |
| </td> |
| </tr> |
| |
| |
| |
| <tr> |
| <td colspan="2"> |
| <b>See Also</b> |
| <br> |
| <A href="contrib.TableColumns.html">TableColumns</a>, |
| <A href="contrib.TablePages.html">TablePages</a>, |
| <A href="contrib.TableRows.html">TableRows</a>, |
| <A href="contrib.TableValues.html">TableValues</a>, |
| <A href="contrib.TableView.html">TableView</a> |
| </td> |
| </tr> |
| |
| <tr> |
| <td colspan="2"> |
| <b>Parameters</b> |
| <br> |
| <table border="1" cellpadding="4" cellspacing="4" class="parameters"> |
| <tr> |
| <th>Name</th> |
| <th>Type</th> |
| <th>Direction</th> |
| <th>Required</th> |
| <th>Default</th> |
| <th>Description</th> |
| </tr> |
| |
| <tr> |
| <td>source</td> |
| <td><code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html">Object</A>[]</code><br> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html">Collection</A></code><br> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Iterator.html">Iterator</A></code><br> |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/IBasicTableModel.html"><CODE>IBasicTableModel</CODE></A> |
| </td> |
| <td>in</td> |
| <td rowspan="3">You must provide either both <code>source</code> and <code>columns</code> parameters |
| or the <code>tableModel</code> parameter</td> |
| <td> </td> |
| <td align="left"> |
| The data to be displayed by the component. This parameter must be used |
| in combination with the <code>columns</code> parameter. |
| The parameter must be an array of values, a collection, an iterator, |
| or an object implementing the IBasicTableModel interface. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>columns</td> |
| <td> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html">String</A></code><br> |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableColumnModel.html"><code>ITableColumnModel</code></A><br> |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableColumn.html"><code>ITableColumn[]</code></A><br> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/util/List.html">List</A></code><br> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Iterator.html">Iterator</A></code> |
| </td> |
| <td>in</td> |
| <td> </td> |
| <td align="left"> |
| The table columns to be displayed. |
| The parameter must be an array, a list, or an Iterator of ITableColumn objects, |
| an ITableColumnModel, or a String describing the columns (see documentation). |
| </td> |
| </tr> |
| |
| <tr> |
| <td>tableModel</td> |
| <td><A HREF="../api/org/apache/tapestry/contrib/table/model/ITableModel.html"><CODE>ITableModel</CODE></A></td> |
| <td>in</td> |
| <td> </td> |
| <td align="left">The <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableModel.html"><CODE>ITableModel</CODE></A> to be used to render the table. |
| The model contains all of the information needed to render the table and gives greatest flexibility, |
| but it may be harder to implement than simply using the <code>source</code> and <code>columns</code> parameters. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>tableSessionStateManager</td> |
| <td><A HREF="../api/org/apache/tapestry/contrib/table/model/ITableSessionStateManager.html"><CODE>ITableSessionStateManager</CODE></A></td> |
| <td>in</td> |
| <td>no</td> |
| <td>A custom session state manager that reloads the data at each request if it is provided |
| via the <code>source</code> and <code>columns</code> parameters or stores all |
| of it in the session if it is provided via the <code>tableModel</code> parameter</td> |
| <td align="left">This is the session state manager that will control what part of the |
| table model will be saved in the session state. |
| It is then used to recreate the table model by |
| using what was saved in the session. |
| <p> You can use one of the stock implementations of |
| <A HREF="../api/org/apache/tapestry/contrib/table/model/ITableSessionStateManager.html"><CODE>ITableSessionStateManager</CODE></A> |
| to determine the session state behaviour, or you can define your own. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>tableSessionStoreManager</td> |
| <td><A HREF="../api/org/apache/tapestry/contrib/table/model/ITableSessionStoreManager.html"><CODE>ITableSessionStoreManager</CODE></A></td> |
| <td>in</td> |
| <td>no</td> |
| <td>null</td> |
| <td align="left">Determines how the session state (returned by the session state manager) |
| will be saved in the session. If this parameter is null, then the state |
| will be saved as a persistent property. If it is not null, then the methods |
| of the interface will be used to save and load the state. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>convertor</td> |
| <td><A HREF="../api/org/apache/tapestry/contrib/table/model/IPrimaryKeyConvertor.html"><CODE>IPrimaryKeyConvertor</CODE></A></td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">An interface defining how the items iterated upon by this component |
| will be stored in the form as Hidden values. |
| This interface allows only the primary key of the items to be stored, rather than |
| the whole item.</td> |
| </tr> |
| |
| <tr> |
| <td>row</td> |
| <td>Object</td> |
| <td>out</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The value object of the current row being rendered.</td> |
| </tr> |
| |
| <tr> |
| <td>column</td> |
| <td><A HREF="../api/org/apache/tapestry/contrib/table/model/ITableColumn.html"><CODE>ITableColumn</CODE></A></td> |
| <td>out</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The object representing the current column being rendered.</td> |
| </tr> |
| |
| <tr> |
| <td>pageSize</td> |
| <td> |
| <code>int</code> |
| </td> |
| <td>in</td> |
| <td>no</td> |
| <td>10</td> |
| <td align="left"> |
| The number of records displayed per page. |
| <p> |
| This parameter is only used with the <code>source</code> and <code>columns</code> parameters. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>initialSortColumn</td> |
| <td> |
| <code><A HREF="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html">String</A></code> |
| </td> |
| <td>in</td> |
| <td>no</td> |
| <td>null</td> |
| <td align="left"> |
| The id of the column to initially sort the table by. |
| A value of <code>null</code> indicates no sorting. |
| <p> |
| This parameter is only used with the <code>source</code> and <code>columns</code> parameters. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>initialSortOrder</td> |
| <td> |
| <code>boolean</code> |
| </td> |
| <td>in</td> |
| <td>no</td> |
| <td>false</td> |
| <td align="left"> |
| The order of the initial sorting. |
| Set this parameter to <code>false</code> to sort in an ascending order |
| and to <code>true</code> to sort in a descending one. |
| <p> |
| This parameter is only used with the <code>source</code> and <code>columns</code> parameters. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>pagesDisplayed</td> |
| <td>int</td> |
| <td>in</td> |
| <td>no</td> |
| <td>7</td> |
| <td align="left">Determines the maximum number of pages to be displayed in the page list |
| when the table has more than one page. |
| <p>For example, if the table has 20 pages, and 10 is the current page, |
| pages from 7 to 13 in the page list will be shown if this parameter has |
| a value of 7. |
| </td> |
| </tr> |
| |
| <tr> |
| <td>arrowUpAsset</td> |
| <td><A HREF="../api/org/apache/tapestry/IAsset.html"><CODE>IAsset</CODE></A></td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The image to use to describe a column sorted in an ascending order.</td> |
| </tr> |
| |
| <tr> |
| <td>arrowDownAsset</td> |
| <td><A HREF="../api/org/apache/tapestry/IAsset.html"><CODE>IAsset</CODE></A></td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The image to use to describe a column sorted in a descending order.</td> |
| </tr> |
| |
| <tr> |
| <td>pagesClass</td> |
| <td>String</td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The CSS class of the table pages.</td> |
| </tr> |
| |
| <tr> |
| <td>columnsClass</td> |
| <td>String</td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The CSS class of the table columns.</td> |
| </tr> |
| |
| <tr> |
| <td>rowsClass</td> |
| <td>String</td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The CSS class of the table rows.</td> |
| </tr> |
| |
| <tr> |
| <td>valuesClass</td> |
| <td>String</td> |
| <td>in</td> |
| <td>no</td> |
| <td> </td> |
| <td align="left">The CSS class of the table values.</td> |
| </tr> |
| |
| </table> |
| <P> |
| Body: <STRONG>ignored</STRONG><BR> |
| Informal parameters: <STRONG>allowed</STRONG><br> |
| Reserved parameters: none |
| </P> |
| </td> |
| </tr> |
| |
| |
| |
| |
| <tr> |
| <td colspan="2"> |
| <b>Examples</b> |
| <p> |
| |
| You can find examples in the Tutorial |
| as part of the Workbench application under the "Table" tab. |
| <P>That page consists of two components -- the <SPAN |
| class=code>LocaleList</SPAN> component and the <SPAN |
| class=code>LocaleSelection</SPAN> component. </P> |
| <P>The <SPAN class=code>LocaleList</SPAN> component allows you to view all |
| Locales in a table (similar to the example above), as well as to choose Locales |
| from the table and add them to your "selection". </P> |
| <P>The <SPAN class=code>LocaleSelection</SPAN> component displays the selected |
| Locales and provides additional information about them. It also allows Locales |
| to be removed from the selection. </P> |
| <P>Even though the two components utilizing the Table are placed on a single |
| page, they can operate without any interference from each other with no effort |
| at all on part of the developer -- each table can be sorted independently, for |
| example. This is a good illustration of the power of Tapestry's component |
| approach. </P> |
| <p></p> |
| </td> |
| </tr> |
| |
| |
| <tr> |
| <td colspan="2"> |
| <hr> |
| <H2>Table Internals Guide</H2> |
| This section is for advanced uses of the Table components only. |
| <P> |
| There are two important elements that comprise the Table |
| functionality -- the table model and the table components. |
| <P>The <STRONG>table model</STRONG> classes and interfaces provide the Table |
| with the ability to display and manipulate data from various different sources. |
| Using them in various combinations and customizing them allows the developer to |
| modify the behaviour of the table according to his needs. </P> |
| <P>The <STRONG>table components</STRONG> are responsible for displaying the data |
| provided by the table model, and working with them allows the developer to |
| radically change the appearance of the table if necessary. </P> |
| |
| <H3>1. The Model </H3> |
| <P>This section will discuss the table model and how it can be used and modified |
| to satisfy the needs of the developer. The next section will then concentrate on |
| how the table components can be used to customize the appearance of the table as |
| much as possible. </P> |
| |
| <H4>1.1. The Table Model Family of Classes </H4>Even though using a table model |
| can be very simple, as shown in the first example, behind the curtains it may |
| consist of many different interfaces and classes that work together to allow you |
| to modify different aspects of the table data representation and manipulation |
| without a lot of effort. |
| <P>Below you can see a UML Class diagram of the interfaces and classes in the |
| Table Model family. The rest of this section will discuss how they can be used |
| and modified as needed. </P> |
| <P><IMG alt="Table Model Class Diagram" |
| src="images/tableModel.gif"> </P> |
| <H4>1.2. The Table Model </H4>The table model provides the information needed by |
| the view to render the table. For example, the Table component may use its <SPAN |
| class=code>tableModel</SPAN> parameter to determine what to display. |
| <P>The Tapestry components access the table model via the relatively simple |
| <B><SPAN class=code>ITableModel</SPAN></B> interface, which is the facade of the |
| table model hierarchy. A variety of implementations of this interface can be |
| created to target different cases. </P> |
| <P>The contrib library currently defines only one rudimentary implementation |
| that can be used in the majority of situations -- the <B><SPAN |
| class=code>SimpleTableModel</SPAN></B>. While versatile, however, this |
| implementation may not be suitable for all cases, and hence you may create your |
| own whenever necessary. </P> |
| <P>Using the <SPAN class=code>SimpleTableModel</SPAN> is very easy -- you just |
| need to provide it with the data to be displayed and the columns that the table |
| will have: </P><PRE> Object[] data = ...; |
| ITableColumn[] columns = ...; |
| ITableModel model = new SimpleTableModel(data, columns); |
| </PRE> |
| <P>This model can then be passed to the Table component, and it will display the |
| data using the given columns. <BR></P> |
| <H4>1.3. The Data Model </H4>The <SPAN class=code>SimpleTableModel</SPAN> can |
| also obtain its data via the <SPAN class=code>ITableDataModel</SPAN> interface. |
| This allows the source of data to be abstracted. |
| <P>The contrib library provides two standard implementations of this interface. |
| The <SPAN class=code>SimpleListTableDataModel</SPAN> and the <SPAN |
| class=code>SimpleSetTableDataModel</SPAN>. As the names indicate, the former |
| provides the table data from Lists and arrays, while the latter provides the |
| data from Sets and other unordered Collections. Using the data models is very |
| simple as well: </P><PRE> ArrayList data = ...; |
| ITableDataModel dataModel = new SimpleListTableDataModel(data); |
| ITableModel model = new SimpleTableModel(dataModel, ...); |
| </PRE> |
| <P>An example of using <SPAN class=code>SimpleSetTableDataModel</SPAN> can be |
| found in the <SPAN class=code>LocaleSelection</SPAN> component in the Workbench. |
| The storage of the selected locales there is implemented precisely using that |
| table data model.</P> |
| <H4>1.4. The Column Model </H4> |
| <P>A column in the table model is defined using the <STRONG><SPAN |
| class=code>ITableColumn</SPAN></STRONG> interface. It provides the information |
| needed to identify the column (the column name), to render the column (the |
| columnRender that renders the heading, and the valueRenderer that renders each |
| cell), and to sort the column (whether the column is sortable and what <SPAN |
| class=code>Comparator</SPAN> should be used for sorting the table). </P> |
| <P>The basic implementation of <SPAN class=code>ITableColumn</SPAN> provided is |
| <STRONG><SPAN class=code>SimpleTableColumn</SPAN></STRONG>. It takes care of all |
| mundane tasks, such as supplying a renderer for the column header, and allows |
| you to define a column by only providing its name and a way to extract the |
| column data from the row object by overriding the <SPAN |
| class=code>getColumnValue()</SPAN> method. This is demonstrated by the example |
| below that also configures the column to be sortable: </P><PRE> // Create a new sortable column with name and title "Full Name" |
| ITableColumn fullNameColumn = new SimpleTableColumn("Full Name", true) { |
| public Object getColumnValue(Object value) { |
| PersonInfo info = (PersonInfo) value; |
| return info.getLastName() + ", " + info.getFirstName(); |
| } |
| }; |
| </PRE> |
| <P>Other methods can be overridden as well to provide additional features, such |
| as custom rendering, as it will be shown in the next section. </P> |
| <P>The above can be achieved in a simpler, but not as flexible manner by using |
| <SPAN class=code><STRONG>ExpressionTableColumn</STRONG></SPAN>. It inherits |
| <SPAN class=code>SimpleTableColumn</SPAN>, and allows you to create columns |
| whose data is obtained via OGNL: </P><PRE> // Create a new sortable column with name and title "Occupation" |
| ITableColumn occupationColumn = new ExpressionTableColumn("Occupation", "occupation", true); |
| |
| // Create a new sortable column with name and title "Full Name" |
| ITableColumn fullNameColumn = new ExpressionTableColumn("Full Name", "lastName + \", \" + firstName", true); |
| </PRE> |
| <P>The table columns are supplied to the table model using a <SPAN |
| class=code>List</SPAN> -like container defined by the <SPAN |
| class=code><STRONG>ITableColumnModel</STRONG></SPAN> interface. The generic |
| implementation provided for this interface is<STRONG> <SPAN |
| class=code>SimpleTableColumnModel</SPAN></STRONG>, which contains an array of |
| <SPAN class=code>ITableColumn</SPAN> objects of any type. </P> |
| <P>One more specific implementation available is the<STRONG> <SPAN |
| class=code>ExpressionTableColumnModel</SPAN> </STRONG>, which contains<SPAN |
| class=code>ExpressionTableColumn</SPAN> objects. It allows you to define the |
| columns of your table quickly and easily, by providing a name and an OGNL |
| expression for each one in a <SPAN class=code>String</SPAN> array: </P><PRE> // Generate a simple sorting column model that uses OGNL to get the column data |
| ITableColumnModel objColumnModel = |
| new ExpressionTableColumnModel(new String[] { |
| "Locale", "toString()", |
| "Language", "language", |
| "Country", "country", |
| "Variant", "variant", |
| "ISO Language", "ISO3Language", |
| "ISO Country", "ISO3Country" |
| }, true); |
| </PRE> |
| <H4>1.5. The Table State </H4> |
| <P>The state of the table model consists of any data that is not related to the |
| contents of the table, but instead carries information about its presentation. |
| The standard table model supports two states -- the paging state (how many rows |
| per page; which page we are on) and the sorting state (which column we are |
| sorting on; in an ascending or a descending order). </P> |
| <P>The paging state is defined by the <STRONG><SPAN |
| class=code>ITablePagingState</SPAN></STRONG> interface and is implemented in its |
| simplest form by <STRONG><SPAN |
| class=code>SimpleTablePagingState</SPAN></STRONG>. Similarly, the sorting state |
| is defined by<STRONG> <SPAN class=code>ITableSortingState</SPAN> </STRONG>and is |
| implemented by<STRONG> <SPAN class=code>SimpleTableSortingState</SPAN></STRONG>. |
| </P> |
| <P>The states are typically accessed and modified by the components presenting |
| the table (e.g. the TablePages component can change the current page based on |
| the user selection). The user can also modify them, which is often necessary at |
| initialization: </P><PRE> ITableModel model = new SimpleTableModel(data, columns); |
| |
| // Set page size to 15 elements and go to page 8 |
| model.getPagingState().setPageSize(15); |
| model.getPagingState().setCurrentPage(8); |
| |
| // Sort by column 'price' in an ascending order |
| model.getSortingState().setSortColumn("price", ITableSortingState.SORT_ASCENDING); |
| </PRE> |
| <P>The <SPAN class=code>SimpleTableModel</SPAN> class keeps the two states |
| together in the<STRONG> <SPAN class=code>SimpleTableState</SPAN> |
| </STRONG>object, which can be passed via the constructor and obtained at any |
| time using the <SPAN class=code>getState()</SPAN> method. This is often useful |
| when storing the state by itself is necessary (see below). </P> |
| <H4>1.6. The Session State Manager </H4> |
| <P>In Web interfaces, unlike client-side GUIs, the information about the state |
| of the presentation must be kept in the session object between requests. What |
| has to be kept and what can be thrown away and recreated during the next request |
| differs in each case, however. The policy of what to do typically involves a |
| tradeoff between memory and CPU power, and hence it depends very much on the |
| specific situation. </P> |
| <P>The<STRONG> <SPAN class=code>ITableSessionStateManager</SPAN> |
| </STRONG>interface is used to define precisely this policy. It defines what part |
| of the table model has to be saved in the session and can recreate the table |
| model using the saved information when the next request comes. </P> |
| <P>The <SPAN class=code>Table</SPAN> and the <SPAN class=code>TableView</SPAN> |
| components have a <SPAN class=code>tableSessionStateManager</SPAN> binding that |
| allows such a manager to be supplied. When the table model is needed at the |
| beginning of a new request, the component use the following procedure to obtain |
| it: </P> |
| <OL> |
| <LI>Load the session state (it will be null initially) |
| <LI>Invoke <SPAN class=code>recreateTableModel(sessionState)</SPAN> on the |
| Session State Manager to try to recrate the table model |
| <LI>If <SPAN class=code>recreateTableMode()</SPAN> returns null, use the <SPAN |
| class=code>tableModel</SPAN> binding to obtain the table model </LI></OL> |
| <P>Immediately before rendering, the opposite procedure takes place: </P> |
| <OL> |
| <LI>Invoke <SPAN class=code>getSessionState(tableModel)</SPAN> on the Session |
| State Manager to extract the part of the model to be saved |
| <LI>Save the session state </LI></OL> |
| <P>Three standard implementations of the <SPAN |
| class=code>ITableSessionStateManager</SPAN> interface are provided that address |
| the common cases that can be implemented without custom code. Each of them |
| implements a different policy for extracting session state from the model and |
| hence is suitable for some specific situations: </P> |
| <TABLE border=1 cellPadding=5 cellSpacing=0 width="100%"> |
| <TBODY> |
| <TR> |
| <TH>Session State Manager </TH> |
| <TH>Description </TH></TR> |
| <TR> |
| <TD vAlign=center> |
| <P align=center><STRONG><SPAN |
| class=code>FullTableSessionStateManager</SPAN> </STRONG></P></TD> |
| <TD> |
| <P><STRONG>Saves the entire table model in the session. This is the |
| default manager.</STRONG> </P> |
| <P>This manager is the simplest to use as it brings to a minimum the need |
| for additional coding. It has a number of disadvantages, however. First, |
| everything in the table model must be <SPAN class=code>Serializable</SPAN> |
| since it is stored in the session and may be serialized at one point or |
| another. Second, depending on the table data, its memory consumption per |
| session could be quite significant. </P> |
| <P>For those reasons, it is probably not a good idea to use this manager |
| if you are displaying large amounts of data, if you have a lot of users, |
| or if the application needs to be clustered. On the other hand, it is |
| perfect for quick and dirty work. </P></TD></TR> |
| <TR> |
| <TD vAlign=center> |
| <P align=center><STRONG><SPAN |
| class=code>SimpleTableSessionStateManager</SPAN> </STRONG></P></TD> |
| <TD> |
| <P><STRONG>Saves only the table model state and assumes that the data and |
| column models are constant.</STRONG> </P> |
| <P>This manager is designed to work with the <SPAN |
| class=code>SimpleTableModel</SPAN> . It stores only the model state |
| (paging and sorting), and recreates the model using the data and column |
| models that must be supplied via its constructor. As a result, the session |
| memory consumption is low, but the CPU utilization may be high, since the |
| data must be resorted at each request. This manager is best used when the |
| data that needs to be displayed is constant. </P> |
| <P>An example of the use of the manager can be seen in the <SPAN |
| class=code>LocaleList</SPAN> component in the Workbench. That component |
| displays all locales available to the JVM -- information that does not |
| change and is too much to be stored in the session. </P></TD></TR> |
| <TR> |
| <TD vAlign=center> |
| <P align=center><STRONG><SPAN |
| class=code>NullTableSessionStateManager</SPAN> </STRONG></P></TD> |
| <TD> |
| <P><STRONG>Saves nothing at all and forces the component to always load |
| the table model from the <SPAN class=code>tableModel</SPAN> |
| binding.</STRONG> </P> |
| <P>This manager is typically used when the storing and creation of the |
| table model needs to be delegated to the parent component. |
| </P></TD></TR></TBODY></TABLE> |
| <P>One approach that is a good compromise between memory consumption and CPU |
| load is to store in the session only the state and the IDs of the objects in the |
| table. In this way CPU is not loaded, since re-sorting is no longer necessary, |
| and the memory consumption is not excessive, since the IDs tend not to take a |
| lot of space. Implementing this approach, however, requires a custom manager, |
| and possibly a custom <SPAN class=code>TableModel</SPAN> to limit the data |
| loaded from the database only to the elements that will be displayed on the |
| current page.</P> |
| <H4>1.7. The Session Store Manager </H4> |
| <P>While the Session State Manager determines <EM>what</EM> to store in the |
| session, the Session Store Manager determines <EM>how</EM> to store data in the |
| session. Normally the information that needs to be saved is stored using the |
| Tapestry persistent property mechanism. If a Session Store Manager is provided, |
| however, it is asked to take care of storing and loading of that information. |
| </P> |
| <P>This is typically necessary in two specific cases: </P> |
| <OL> |
| <LI>When the same table needs to be displayed on multiple pages. In that case |
| the persistent property method will not work as desired, and the table state |
| must be saved in the <SPAN class=code>Visit</SPAN> instead. |
| <LI>When the table is a part of a <SPAN class=code>Block</SPAN>, and the <SPAN |
| class=code>Block</SPAN> is used on more than one page. In that case the tables |
| displayed may be different, but a persistent page property will save their |
| states at the same location. Hence a custom Session Store Manager is |
| necessary. </LI></OL> |
| <P></P> |
| <P>The Session Store Managers implement the <STRONG><SPAN |
| class=code>ITableSessionStoreManager</SPAN></STRONG> interface. There are no |
| default implementations of this interface -- the developer must supply his own. |
| </P> |
| <P> </P> |
| <P></P> |
| <H3>2. Changing appearance </H3> |
| <P>While the table model defines what data should be displayed in the table, it |
| does not define how that data would look. The appearance is an important element |
| of the web applications, however, and so the table components provide a number |
| of ways to the developer to customize their looks. </P> |
| <H4>2.1. Setting styles </H4> |
| <P>The simplest way to modify how the table looks is by using CSS. The <SPAN |
| class=code>Table</SPAN> component provides a number of bindings allowing you to |
| set the CSS class of all major elements of the table. Please have a look at |
| <SPAN class=code>Table</SPAN>'s JavaDoc for details. </P> |
| <P>One interesting use of this approach is to define an <SPAN |
| class=code>evenOdd</SPAN> bean of type <SPAN |
| class=code>org.apache.tapestry.bean.EvenOdd</SPAN> and bind the rowsClass parameter |
| of table to <SPAN class=code>"beans.evenOdd.next"</SPAN>. In this way odd rows |
| in the table will receive the class "odd", and even rows will receive the class |
| "even", which allows for different formatting of neighbouring rows. </P> |
| <H4>2.2. Changing layout </H4> |
| <P>The <SPAN class=code>Table</SPAN> component is very easy to use, but it may |
| become a "straight jacket" if a different layout of the table is required. In |
| such a case, instead of <SPAN class=code>Table</SPAN>, the developer could use |
| the lower level table components described below: </P> |
| <TABLE border=1 cellPadding=5 cellSpacing=0> |
| <TBODY> |
| <TR> |
| <TH>Component</TH> |
| <TH>Wrapped by</TH> |
| <TH>Description</TH></TR> |
| <TR> |
| <TD align=middle><STRONG><SPAN class=code>TableView</SPAN></STRONG></TD> |
| <TD> </TD> |
| <TD>Wraps the whole table structure and manages the table model</TD></TR> |
| <TR> |
| <TD align=middle><STRONG><SPAN class=code>TablePages</SPAN></STRONG></TD> |
| <TD align=middle><SPAN class=code>TableView</SPAN></TD> |
| <TD>Displays the page navigation interface</TD></TR> |
| <TR> |
| <TD align=middle><STRONG><SPAN class=code>TableColumns</SPAN></STRONG></TD> |
| <TD align=middle><SPAN class=code>TableView</SPAN></TD> |
| <TD>Generates the column headers</TD></TR> |
| <TR> |
| <TD align=middle><STRONG><SPAN class=code>TableRows</SPAN></STRONG></TD> |
| <TD align=middle><SPAN class=code>TableView</SPAN></TD> |
| <TD>Enumerates all rows on the current page</TD></TR> |
| <TR> |
| <TD align=middle><STRONG><SPAN class=code>TableValues</SPAN></STRONG></TD> |
| <TD align=middle><SPAN class=code>TableRows</SPAN></TD> |
| <TD>Renders the values for each column of the current |
| row</TD></TR></TBODY></TABLE> |
| <P> The <SPAN class=code>Table</SPAN> component itself is based on those |
| components. Here is its template: </P><PRE> <span jwcid="tableView"> |
| <span jwcid="condPages"><span jwcid="tablePages"/></span> |
| <tr><span jwcid="tableColumns"/></tr> |
| <tr jwcid="tableRows"><td jwcid="tableValues"/></tr> |
| </span> |
| </PRE> |
| <P>You can use those components in a similar way to create a layout that you |
| want. You can change the location of the page navigation section, add other |
| columns in the table manually, or insert custom formatting. You can even build |
| your own components to replace some of the standard ones.</P> |
| <P>A good example of this approach is the <SPAN class=code>LocaleList</SPAN> |
| component in the Workbench. It modifies the layout slightly and adds a separate |
| column in the table that is not defined the table model.</P> |
| <H4>2.3. Changing renderers </H4> |
| <P>Another way to change the appearance of the table is by using the <SPAN |
| class=code>ITableColumn</SPAN> ability to provide custom renderers for both |
| column headers and values. By default, <SPAN class=code>SimpleTableColumn</SPAN> |
| uses <SPAN class=code>RenderString</SPAN> to display values and the <SPAN |
| class=code>SimpleTableColumnComponent</SPAN> to render the headers. That |
| component makes the header a link if the column is sortable, handles clicks on |
| it, and displays an indicator if the column is currently used for sorting. </P> |
| <P>If is quite possible to use custom components to render the values or the |
| headers in a different way. This is the approach taken by the <SPAN |
| class=code>LocaleSelection</SPAN> component in the Workbench. It uses Block |
| sections in its template to render some columns differently (see the demo). </P> |
| <P>While using this mechanism is not hard at all, there are a number of common |
| pitfalls that the developer must avoid. If you would like to go that route, |
| please see how the <SPAN class=code>SimpleTableColumnComponent</SPAN> and the |
| <SPAN class=code>LocaleSelection</SPAN> component are implemented and read the |
| JavaDocs of <SPAN class=code>org.apache.tapestry.components.BlockRenderer</SPAN> and |
| <SPAN class=code>org.apache.tapestry.ComponentAddress</SPAN> beforehand.</P> |
| <P> </P> |
| |
| </td></tr></table> |
| </td></tr> |
| <tr> |
| <td colspan="3"><hr></td> |
| </tr> |
| <tr><!-- Previous component in alphabetical order. --> |
| <td align="left"><A href="contrib.FormConditional.html"><IMG alt="contrib:FormConditional" src="common-images/prev.png"></a></td> |
| <td align="middle"><A href="index.html"><IMG alt="Component Index" src="common-images/home.png" ></a></td><!-- Next component in alphabetical order. --> |
| <td align="right"><A href="contrib.InspectorButton.html"><IMG alt="contrib:InspectorButton" src="common-images/next.png"></a></td> |
| </tr> |
| </table> |
| |
| </body> |
| </html> |