summaryrefslogtreecommitdiffstats
path: root/documentation/components/components-table.asciidoc
diff options
context:
space:
mode:
authorIlia Motornyi <elmot@vaadin.com>2015-12-03 14:59:05 +0000
committerVaadin Code Review <review@vaadin.com>2015-12-03 14:59:12 +0000
commit2af72ba9636bec70046394c41744f89ce4572e35 (patch)
treeccb3dc2d2239585f8c3f79eb5f131ff61ca9ce86 /documentation/components/components-table.asciidoc
parent8aa5fabe89f2967e966a64842a608eceaf80d08f (diff)
downloadvaadin-framework-2af72ba9636bec70046394c41744f89ce4572e35.tar.gz
vaadin-framework-2af72ba9636bec70046394c41744f89ce4572e35.zip
Revert "Merge branch 'documentation'"7.6.0.beta2
This reverts commit f6874bde3d945c8b2d1b5c17ab50e2d0f1f8ff00. Change-Id: I67ee1c30ba3e3bcc3c43a1dd2e73a822791514bf
Diffstat (limited to 'documentation/components/components-table.asciidoc')
-rw-r--r--documentation/components/components-table.asciidoc1164
1 files changed, 0 insertions, 1164 deletions
diff --git a/documentation/components/components-table.asciidoc b/documentation/components/components-table.asciidoc
deleted file mode 100644
index 7ef31e29fb..0000000000
--- a/documentation/components/components-table.asciidoc
+++ /dev/null
@@ -1,1164 +0,0 @@
----
-title: Table
-order: 21
-layout: page
----
-
-[[components.table]]
-= [classname]#Table#
-
-((("[classname]#Table#", id="term.components.table", range="startofrange")))
-
-
-The [classname]#Table# component is intended for presenting tabular data
-organized in rows and columns. The [classname]#Table# is one of the most
-versatile components in Vaadin. Table cells can include text or arbitrary UI
-components. You can easily implement editing of the table data, for example
-clicking on a cell could change it to a text field for editing.
-
-The data contained in a [classname]#Table# is managed using the Data Model of
-Vaadin (see
-<<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding
-Components to Data">>), through the [classname]#Container# interface of the
-[classname]#Table#. This makes it possible to bind a table directly to a data
-source, such as a database query. Only the visible part of the table is loaded
-into the browser and moving the visible window with the scrollbar loads content
-from the server. While the data is being loaded, a tooltip will be displayed
-that shows the current range and total number of items in the table. The rows of
-the table are __items__ in the container and the columns are __properties__.
-Each table row (item) is identified with an __item identifier__ (IID), and each
-column (property) with a __property identifier__ (PID).
-
-When creating a table, you first need to define columns with
-[methodname]#addContainerProperty()#. This method comes in two flavors. The
-simpler one takes the property ID of the column and uses it also as the caption
-of the column. The more complex one allows differing PID and header for the
-column. This may make, for example, internationalization of table headers
-easier, because if a PID is internationalized, the internationalization has to
-be used everywhere where the PID is used. The complex form of the method also
-allows defining an icon for the column from a resource. The "default value"
-parameter is used when new properties (columns) are added to the table, to fill
-in the missing values. (This default has no meaning in the usual case, such as
-below, where we add items after defining the properties.)
-
-
-[source, java]
-----
-Table table = new Table("The Brightest Stars");
-
-// Define two columns for the built-in container
-table.addContainerProperty("Name", String.class, null);
-table.addContainerProperty("Mag", Float.class, null);
-
-// Add a row the hard way
-Object newItemId = table.addItem();
-Item row1 = table.getItem(newItemId);
-row1.getItemProperty("Name").setValue("Sirius");
-row1.getItemProperty("Mag").setValue(-1.46f);
-
-// Add a few other rows using shorthand addItem()
-table.addItem(new Object[]{"Canopus", -0.72f}, 2);
-table.addItem(new Object[]{"Arcturus", -0.04f}, 3);
-table.addItem(new Object[]{"Alpha Centauri", -0.01f}, 4);
-
-// Show exactly the currently contained rows (items)
-table.setPageLength(table.size());
-----
-
-In this example, we used an increasing [classname]#Integer# object as the Item
-Identifier, given as the second parameter to [methodname]#addItem()#. The actual
-rows are given simply as object arrays, in the same order in which the
-properties were added. The objects must be of the correct class, as defined in
-the [methodname]#addContainerProperty()# calls.
-
-.Basic Table Example
-image::img/table-example1.png[]
-
-Scalability of the [classname]#Table# is largely dictated by the container. The
-default [classname]#IndexedContainer# is relatively heavy and can cause
-scalability problems, for example, when updating the values. Use of an optimized
-application-specific container is recommended. Table does not have a limit for
-the number of items and is just as fast with hundreds of thousands of items as
-with just a few. With the current implementation of scrolling, there is a limit
-of around 500 000 rows, depending on the browser and the pixel height of rows.
-
-Common selection component features are described in
-<<dummy/../../../framework/components/components-selection#components.selection,"Selection
-Components">>.
-
-[[components.table.selecting]]
-== Selecting Items in a Table
-
-The [classname]#Table# allows selecting one or more items by clicking them with
-the mouse. When the user selects an item, the IID of the item will be set as the
-property of the table and a [classname]#ValueChangeEvent# is triggered. To
-enable selection, you need to set the table __selectable__. You will also need
-to set it as __immediate__ in most cases, as we do below, because without it,
-the change in the property will not be communicated immediately to the server.
-
-The following example shows how to enable the selection of items in a
-[classname]#Table# and how to handle [classname]#ValueChangeEvent# events that
-are caused by changes in selection. You need to handle the event with the
-[methodname]#valueChange()# method of the
-[classname]#Property.ValueChangeListener# interface.
-
-
-[source, java]
-----
-// Allow selecting items from the table.
-table.setSelectable(true);
-
-// Send changes in selection immediately to server.
-table.setImmediate(true);
-
-// Shows feedback from selection.
-final Label current = new Label("Selected: -");
-
-// Handle selection change.
-table.addValueChangeListener(new Property.ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- current.setValue("Selected: " + table.getValue());
- }
-});
-----
-
-.Table Selection Example
-image::img/table-example2.png[]
-
-If the user clicks on an already selected item, the selection will deselected
-and the table property will have [parameter]#null# value. You can disable this
-behaviour by setting [methodname]#setNullSelectionAllowed(false)# for the table.
-
-The selection is the value of the table's property, so you can get it with
-[methodname]#getValue()#. You can get it also from a reference to the table
-itself. In single selection mode, the value is the item identifier of the
-selected item or [parameter]#null# if no item is selected. In multiple selection
-mode (see below), the value is a [classname]#Set# of item identifiers. Notice
-that the set is unmodifiable, so you can not simply change it to change the
-selection.
-
-=== Multiple Selection Mode
-
-A table can also be in __multiselect__ mode, where a user can select multiple
-items by clicking them with left mouse button while holding the Ctrl key (or
-Meta key) pressed. If Ctrl is not held, clicking an item will select it and
-other selected items are deselected. The user can select a range by selecting an
-item, holding the Shift key pressed, and clicking another item, in which case
-all the items between the two are also selected. Multiple ranges can be selected
-by first selecting a range, then selecting an item while holding Ctrl, and then
-selecting another item with both Ctrl and Shift pressed.
-
-The multiselect mode is enabled with the [methodname]#setMultiSelect()# method
-of the [classname]#AbstractSelect# superclass of [classname]#Table#. Setting
-table in multiselect mode does not implicitly set it as __selectable__, so it
-must be set separately.
-
-The [methodname]#setMultiSelectMode()# property affects the control of multiple
-selection: [parameter]#MultiSelectMode.DEFAULT# is the default behaviour, which
-requires holding the Ctrl (or Meta) key pressed while selecting items, while in
-[parameter]#MultiSelectMode.SIMPLE# holding the Ctrl key is not needed. In the
-simple mode, items can only be deselected by clicking them.
-
-
-
-[[components.table.features]]
-== Table Features
-
-=== Page Length and Scrollbar
-
-The default style for [classname]#Table# provides a table with a scrollbar. The
-scrollbar is located at the right side of the table and becomes visible when the
-number of items in the table exceeds the page length, that is, the number of
-visible items. You can set the page length with [methodname]#setPageLength()#.
-
-Setting the page length to zero makes all the rows in a table visible, no matter
-how many rows there are. Notice that this also effectively disables buffering,
-as all the entire table is loaded to the browser at once. Using such tables to
-generate reports does not scale up very well, as there is some inevitable
-overhead in rendering a table with Ajax. For very large reports, generating HTML
-directly is a more scalable solution.
-
-
-[[components.table.features.resizing]]
-=== Resizing Columns
-
-You can set the width of a column programmatically from the server-side with
-[methodname]#setColumnWidth()#. The column is identified by the property ID and
-the width is given in pixels.
-
-The user can resize table columns by dragging the resize handle between two
-columns. Resizing a table column causes a [classname]#ColumnResizeEvent#, which
-you can handle with a [classname]#Table.ColumnResizeListener#. The table must be
-set in immediate mode if you want to receive the resize events immediately,
-which is typical.
-
-
-[source, java]
-----
-table.addColumnResizeListener(new Table.ColumnResizeListener(){
- public void columnResize(ColumnResizeEvent event) {
- // Get the new width of the resized column
- int width = event.getCurrentWidth();
-
- // Get the property ID of the resized column
- String column = (String) event.getPropertyId();
-
- // Do something with the information
- table.setColumnFooter(column, String.valueOf(width) + "px");
- }
-});
-
-// Must be immediate to send the resize events immediately
-table.setImmediate(true);
-----
-
-See <<figure.component.table.columnresize>> for a result after the columns of a
-table has been resized.
-
-[[figure.component.table.columnresize]]
-.Resizing Columns
-image::img/table-column-resize.png[]
-
-
-[[components.table.features.reordering]]
-=== Reordering Columns
-
-If [methodname]#setColumnReorderingAllowed(true)# is set, the user can reorder
-table columns by dragging them with the mouse from the column header,
-
-
-[[components.table.features.collapsing]]
-=== Collapsing Columns
-
-When [methodname]#setColumnCollapsingAllowed(true)# is set, the right side of
-the table header shows a drop-down list that allows selecting which columns are
-shown. Collapsing columns is different than hiding columns with
-[methodname]#setVisibleColumns()#, which hides the columns completely so that
-they can not be made visible (uncollapsed) from the user interface.
-
-You can collapse columns programmatically with
-[methodname]#setColumnCollapsed()#. Collapsing must be enabled before collapsing
-columns with the method or it will throw an [classname]#IllegalAccessException#.
-
-
-[source, java]
-----
-// Allow the user to collapse and uncollapse columns
-table.setColumnCollapsingAllowed(true);
-
-// Collapse this column programmatically
-try {
- table.setColumnCollapsed("born", true);
-} catch (IllegalAccessException e) {
- // Can't occur - collapsing was allowed above
- System.err.println("Something horrible occurred");
-}
-
-// Give enough width for the table to accommodate the
-// initially collapsed column later
-table.setWidth("250px");
-----
-
-See <<figure.component.table.columncollapsing>>.
-
-[[figure.component.table.columncollapsing]]
-.Collapsing Columns
-image::img/table-column-collapsing.png[]
-
-If the table has undefined width, it minimizes its width to fit the width of the
-visible columns. If some columns are initially collapsed, the width of the table
-may not be enough to accomodate them later, which will result in an ugly
-horizontal scrollbar. You should consider giving the table enough width to
-accomodate columns uncollapsed by the user.
-
-
-[[components.table.features.components]]
-=== Components Inside a Table
-
-The cells of a [classname]#Table# can contain any user interface components, not
-just strings. If the rows are higher than the row height defined in the default
-theme, you have to define the proper row height in a custom theme.
-
-When handling events for components inside a [classname]#Table#, such as for the
-[classname]#Button# in the example below, you usually need to know the item the
-component belongs to. Components do not themselves know about the table or the
-specific item in which a component is contained. Therefore, the handling method
-must use some other means for finding out the Item ID of the item. There are a
-few possibilities. Usually the easiest way is to use the [methodname]#setData()#
-method to attach an arbitrary object to a component. You can subclass the
-component and include the identity information there. You can also simply search
-the entire table for the item with the component, although that solution may not
-be so scalable.
-
-The example below includes table rows with a [classname]#Label# in HTML content
-mode, a multiline [classname]#TextField#, a [classname]#CheckBox#, and a
-[classname]#Button# that shows as a link.
-
-
-[source, java]
-----
-// Create a table and add a style to allow setting the row height in theme.
-final Table table = new Table();
-table.addStyleName("components-inside");
-
-/* Define the names and data types of columns.
- * The "default value" parameter is meaningless here. */
-table.addContainerProperty("Sum", Label.class, null);
-table.addContainerProperty("Is Transferred", CheckBox.class, null);
-table.addContainerProperty("Comments", TextField.class, null);
-table.addContainerProperty("Details", Button.class, null);
-
-/* Add a few items in the table. */
-for (int i=0; i<100; i++) {
- // Create the fields for the current table row
- Label sumField = new Label(String.format(
- "Sum is <b>$%04.2f</b><br/><i>(VAT incl.)</i>",
- new Object[] {new Double(Math.random()*1000)}),
- ContentMode.HTML);
- CheckBox transferredField = new CheckBox("is transferred");
-
- // Multiline text field. This required modifying the
- // height of the table row.
- TextField commentsField = new TextField();
- commentsField.setRows(3);
-
- // The Table item identifier for the row.
- Integer itemId = new Integer(i);
-
- // Create a button and handle its click. A Button does not
- // know the item it is contained in, so we have to store the
- // item ID as user-defined data.
- Button detailsField = new Button("show details");
- detailsField.setData(itemId);
- detailsField.addClickListener(new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- // Get the item identifier from the user-defined data.
- Integer iid = (Integer)event.getButton().getData();
- Notification.show("Link " +
- iid.intValue() + " clicked.");
- }
- });
- detailsField.addStyleName("link");
-
- // Create the table row.
- table.addItem(new Object[] {sumField, transferredField,
- commentsField, detailsField},
- itemId);
-}
-
-// Show just three rows because they are so high.
-table.setPageLength(3);
-----
-See the http://demo.vaadin.com/book-examples-vaadin7/book#component.table.components.components2[on-line example, window="_blank"].
-
-The row height has to be set higher than the default with a style rule such as
-the following:
-
-
-[source, css]
-----
-/* Table rows contain three-row TextField components. */
-.v-table-components-inside .v-table-cell-content {
- height: 54px;
-}
-----
-See the http://demo.vaadin.com/book-examples-vaadin7/book#component.table.components.components2[on-line example, window="_blank"].
-
-The table will look as shown in <<figure.components.table.components-inside>>.
-
-[[figure.components.table.components-inside]]
-.Components in a Table
-image::img/table-components.png[]
-
-
-[[components.table.features.iterating]]
-=== Iterating Over a Table
-
-As the items in a [classname]#Table# are not indexed, iterating over the items
-has to be done using an iterator. The [methodname]#getItemIds()# method of the
-[classname]#Container# interface of [classname]#Table# returns a
-[classname]#Collection# of item identifiers over which you can iterate using an
-[classname]#Iterator#. For an example about iterating over a [classname]#Table#,
-please see
-<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container,"Collecting
-Items in Containers">>. Notice that you may not modify the [classname]#Table#
-during iteration, that is, add or remove items. Changing the data is allowed.
-
-
-[[components.table.features.filtering]]
-=== Filtering Table Contents
-
-A table can be filtered if its container data source implements the
-[classname]#Filterable# interface, as the default [classname]#IndexedContainer#
-does. See
-<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container.filtered,"Filterable
-Containers">>. ((("Container",
-"Filterable")))
-
-
-
-[[components.table.editing]]
-== Editing the Values in a Table
-
-Normally, a [classname]#Table# simply displays the items and their fields as
-text. If you want to allow the user to edit the values, you can either put them
-inside components as we did earlier or simply call
-[methodname]#setEditable(true)#, in which case the cells are automatically
-turned into editable fields.
-
-Let us begin with a regular table with a some columns with usual Java types,
-namely a [classname]#Date#, [classname]#Boolean#, and a [classname]#String#.
-
-
-[source, java]
-----
-// Create a table. It is by default not editable.
-Table table = new Table();
-
-// Define the names and data types of columns.
-table.addContainerProperty("Date", Date.class, null);
-table.addContainerProperty("Work", Boolean.class, null);
-table.addContainerProperty("Comments", String.class, null);
-
-...
-----
-
-You could put the table in editable mode right away. We continue the example by
-adding a check box to switch the table between normal and editable modes:
-
-
-[source, java]
-----
-CheckBox editable = new CheckBox("Editable", true);
-editable.addValueChangeListener(valueChange -> // Java 8
- table.setEditable((Boolean) editable.getValue()));
-----
-
-Now, when you check to checkbox, the components in the table turn into editable
-fields, as shown in <<figure.component.table.editable>>.
-
-[[figure.component.table.editable]]
-.A Table in Normal and Editable Mode
-image::img/table-editable3.png[]
-
-[[components.table.editing.fieldfactories]]
-=== Field Factories
-
-The field components that allow editing the values of particular types in a
-table are defined in a field factory that implements the
-[classname]#TableFieldFactory# interface. The default implementation is
-[classname]#DefaultFieldFactory#, which offers the following crude mappings:
-
-.Type to Field Mappings in [classname]#DefaultFieldFactory#
-[options="header"]
-|===============
-|Property Type|Mapped to Field Class
-|[classname]#Date#|A[classname]#DateField#.
-|[classname]#Boolean#|A[classname]#CheckBox#.
-|[classname]#Item#|A[classname]#Form#(deprecated in Vaadin 7). The fields of the form are automatically created from the item's properties using a[classname]#FormFieldFactory#. The normal use for this property type is inside a[classname]#Form#and is less useful inside a[classname]#Table#.
-|__other__|A[classname]#TextField#. The text field manages conversions from the basic types, if possible.
-
-|===============
-
-
-
-Field factories are covered with more detail in
-<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding,"Creating
-Forms by Binding Fields to Items">>. You could just implement the
-[classname]#TableFieldFactory# interface, but we recommend that you extend the
-[classname]#DefaultFieldFactory# according to your needs. In the default
-implementation, the mappings are defined in the
-[methodname]#createFieldByPropertyType()# method (you might want to look at the
-source code) both for tables and forms.
-
-
-ifdef::web[]
-[[components.table.editing.navigation]]
-=== Navigation in Editable Mode
-
-In the editable mode, the editor fields can have focus. Pressing Tab moves the
-focus to next column or, at the last column, to the first column of the next
-item. Respectively, pressing ShiftTab moves the focus backward. If the focus is
-in the last column of the last visible item, the pressing Tab moves the focus
-outside the table. Moving backward from the first column of the first item moves
-the focus to the table itself. Some updates to the table, such as changing the
-headers or footers or regenerating a column, can move the focus from an editor
-component to the table itself.
-
-The default behaviour may be undesirable in many cases. For example, the focus
-also goes through any read-only editor fields and can move out of the table
-inappropriately. You can provide better navigation is to use event handler for
-shortcut keys such as Tab, Arrow Up, Arrow Down, and Enter.
-
-
-[source, java]
-----
-// Keyboard navigation
-class KbdHandler implements Handler {
- Action tab_next = new ShortcutAction("Tab",
- ShortcutAction.KeyCode.TAB, null);
- Action tab_prev = new ShortcutAction("Shift+Tab",
- ShortcutAction.KeyCode.TAB,
- new int[] {ShortcutAction.ModifierKey.SHIFT});
- Action cur_down = new ShortcutAction("Down",
- ShortcutAction.KeyCode.ARROW_DOWN, null);
- Action cur_up = new ShortcutAction("Up",
- ShortcutAction.KeyCode.ARROW_UP, null);
- Action enter = new ShortcutAction("Enter",
- ShortcutAction.KeyCode.ENTER, null);
- public Action[] getActions(Object target, Object sender) {
- return new Action[] {tab_next, tab_prev, cur_down,
- cur_up, enter};
- }
-
- public void handleAction(Action action, Object sender,
- Object target) {
- if (target instanceof TextField) {
- // Move according to keypress
- int itemid = (Integer) ((TextField) target).getData();
- if (action == tab_next || action == cur_down)
- itemid++;
- else if (action == tab_prev || action == cur_up)
- itemid--;
- // On enter, just stay where you were. If we did
- // not catch the enter action, the focus would be
- // moved to wrong place.
-
- if (itemid >= 0 && itemid < table.size()) {
- TextField newTF = valueFields.get(itemid);
- if (newTF != null)
- newTF.focus();
- }
- }
- }
-}
-
-// Panel that handles keyboard navigation
-Panel navigator = new Panel();
-navigator.addStyleName(Reindeer.PANEL_LIGHT);
-navigator.addComponent(table);
-navigator.addActionHandler(new KbdHandler());
-----
-
-The main issue in implementing keyboard navigation in an editable table is that
-the editor fields do not know the table they are in. To find the parent table,
-you can either look up in the component container hierarchy or simply store a
-reference to the table with [methodname]#setData()# in the field component. The
-other issue is that you can not acquire a reference to an editor field from the
-[classname]#Table# component. One solution is to use some external collection,
-such as a [classname]#HashMap#, to map item IDs to the editor fields.
-
-
-[source, java]
-----
-// Can't access the editable components from the table so
-// must store the information
-final HashMap<Integer,TextField> valueFields =
- new HashMap<Integer,TextField>();
-----
-
-The map has to be filled in a [classname]#TableFieldFactory#, such as in the
-following. You also need to set the reference to the table there and you can
-also set the initial focus there.
-
-
-[source, java]
-----
-table.setTableFieldFactory(new TableFieldFactory () {
- public Field createField(Container container, Object itemId,
- Object propertyId, Component uiContext) {
- TextField field = new TextField((String) propertyId);
-
- // User can only edit the numeric column
- if ("Source of Fear".equals(propertyId))
- field.setReadOnly(true);
- else { // The numeric column
- // The field needs to know the item it is in
- field.setData(itemId);
-
- // Remember the field
- valueFields.put((Integer) itemId, field);
-
- // Focus the first editable value
- if (((Integer)itemId) == 0)
- field.focus();
- }
- return field;
- }
-});
-----
-
-The issues are complicated by the fact that the editor fields are not generated
-for the entire table, but only for a cache window that includes the visible
-items and some items above and below it. For example, if the beginning of a big
-scrollable table is visible, the editor component for the last item does not
-exist. This issue is relevant mostly if you want to have wrap-around navigation
-that jumps from the last to first item and vice versa.
-
-endif::web[]
-
-
-[[components.table.headersfooters]]
-== Column Headers and Footers
-
-[classname]#Table# supports both column headers and footers; the headers are
-enabled by default.
-
-[[components.table.headersfooters.headers]]
-=== Headers
-
-The table header displays the column headers at the top of the table. You can
-use the column headers to reorder or resize the columns, as described earlier.
-By default, the header of a column is the property ID of the column, unless
-given explicitly with [methodname]#setColumnHeader()#.
-
-
-[source, java]
-----
-// Define the properties
-table.addContainerProperty("lastname", String.class, null);
-table.addContainerProperty("born", Integer.class, null);
-table.addContainerProperty("died", Integer.class, null);
-
-// Set nicer header names
-table.setColumnHeader("lastname", "Name");
-table.setColumnHeader("born", "Born");
-table.setColumnHeader("died", "Died");
-----
-
-The text of the column headers and the visibility of the header depends on the
-__column header mode__. The header is visible by default, but you can disable it
-with [methodname]#setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN)#.
-
-
-[[components.table.headersfooters.footers]]
-=== Footers
-
-The table footer can be useful for displaying sums or averages of values in a
-column, and so on. The footer is not visible by default; you can enable it with
-[methodname]#setFooterVisible(true)#. Unlike in the header, the column headers
-are empty by default. You can set their value with
-[methodname]#setColumnFooter()#. The columns are identified by their property
-ID.
-
-The following example shows how to calculate average of the values in a column:
-
-
-[source, java]
-----
-// Have a table with a numeric column
-Table table = new Table("Custom Table Footer");
-table.addContainerProperty("Name", String.class, null);
-table.addContainerProperty("Died At Age", Integer.class, null);
-
-// Insert some data
-Object people[][] = { {"Galileo", 77},
- {"Monnier", 83},
- {"Vaisala", 79},
- {"Oterma", 86}};
-for (int i=0; i<people.length; i++)
- table.addItem(people[i], new Integer(i));
-
-// Calculate the average of the numeric column
-double avgAge = 0;
-for (int i=0; i<people.length; i++)
- avgAge += (Integer) people[i][1];
-avgAge /= people.length;
-
-// Set the footers
-table.setFooterVisible(true);
-table.setColumnFooter("Name", "Average");
-table.setColumnFooter("Died At Age", String.valueOf(avgAge));
-
-// Adjust the table height a bit
-table.setPageLength(table.size());
-----
-
-The resulting table is shown in
-<<figure.components.table.headersfooters.footer>>.
-
-[[figure.components.table.headersfooters.footer]]
-.A Table with a Footer
-image::img/table-footer.png[]
-
-
-[[components.table.headersfooters.clicks]]
-=== Handling Mouse Clicks on Headers and Footers
-
-Normally, when the user clicks a column header, the table will be sorted by the
-column, assuming that the data source is [classname]#Sortable# and sorting is
-not disabled. In some cases, you might want some other functionality when the
-user clicks the column header, such as selecting the column in some way.
-
-Clicks in the header cause a [classname]#HeaderClickEvent#, which you can handle
-with a [classname]#Table.HeaderClickListener#. Click events on the table header
-(and footer) are, like button clicks, sent immediately to server, so there is no
-need to set [methodname]#setImmediate()#.
-
-
-[source, java]
-----
-// Handle the header clicks
-table.addHeaderClickListener(new Table.HeaderClickListener() {
- public void headerClick(HeaderClickEvent event) {
- String column = (String) event.getPropertyId();
- Notification.show("Clicked " + column +
- "with " + event.getButtonName());
- }
-});
-
-// Disable the default sorting behavior
-table.setSortDisabled(true);
-----
-
-Setting a click handler does not automatically disable the sorting behavior of
-the header; you need to disable it explicitly with
-[methodname]#setSortDisabled(true)#. Header click events are not sent when the
-user clicks the column resize handlers to drag them.
-
-The [classname]#HeaderClickEvent# object provides the identity of the clicked
-column with [methodname]#getPropertyId()#. The [methodname]#getButton()# reports
-the mouse button with which the click was made: [parameter]#BUTTON_LEFT#,
-[parameter]#BUTTON_RIGHT#, or [parameter]#BUTTON_MIDDLE#. The
-[methodname]#getButtonName()# a human-readable button name in English: "
-[parameter]#left#", " [parameter]#right#", or " [parameter]#middle#". The
-[methodname]#isShiftKey()#, [methodname]#isCtrlKey()#, etc., methods indicate if
-the Shift, Ctrl, Alt or other modifier keys were pressed during the click.
-
-Clicks in the footer cause a [classname]#FooterClickEvent#, which you can handle
-with a [classname]#Table.FooterClickListener#. Footers do not have any default
-click behavior, like the sorting in the header. Otherwise, handling clicks in
-the footer is equivalent to handling clicks in the header.
-
-
-
-[[components.table.columngenerator]]
-== Generated Table Columns
-
-A table can have generated columns which values can be calculated based on the
-values in other columns. The columns are generated with a class implementing the
-[interfacename]#Table.ColumnGenerator# interface.
-
-The [classname]#GeneratedPropertyContainer# described in
-<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container.gpc,"GeneratedPropertyContainer">>
-is another way to accomplish the same task at container level. In addition to
-generating values, you can also use the feature for formatting or styling
-columns.
-
-ifdef::web[]
-[[components.table.columngenerator.generator]]
-=== Defining a Column Generator
-
-Column generators are objects that implement the
-[classname]#Table.ColumnGenerator# interface and its
-[methodname]#generateCell()# method. The method gets the identity of the item
-and column as its parameters, in addition to the table object, and has to return
-a component. The interface is functional, so you can also define it by a lambda
-expression or a method reference in Java 8.
-
-The following example defines a generator for formatting [classname]#Double#
-valued fields according to a format string (as in
-[classname]#java.util.Formatter#).
-
-
-[source, java]
-----
-/** Formats the value in a column containing Double objects. */
-class ValueColumnGenerator implements Table.ColumnGenerator {
- String format; /* Format string for the Double values. */
-
- /**
- * Creates double value column formatter with the given
- * format string.
- */
- public ValueColumnGenerator(String format) {
- this.format = format;
- }
-
- /**
- * Generates the cell containing the Double value.
- * The column is irrelevant in this use case.
- */
- public Component generateCell(Table source, Object itemId,
- Object columnId) {
- // Get the object stored in the cell as a property
- Property prop =
- source.getItem(itemId).getItemProperty(columnId);
- if (prop.getType().equals(Double.class)) {
- Label label = new Label(String.format(format,
- new Object[] { (Double) prop.getValue() }));
-
- // Set styles for the column: one indicating that it's
- // a value and a more specific one with the column
- // name in it. This assumes that the column name
- // is proper for CSS.
- label.addStyleName("column-type-value");
- label.addStyleName("column-" + (String) columnId);
- return label;
- }
- return null;
- }
-}
-----
-
-The column generator is called for all the visible (or more accurately cached)
-items in a table. If the user scrolls the table to another position in the
-table, the columns of the new visible rows are generated dynamically.
-
-Generated column cells are automatically updated when a property value in the
-table row changes. Note that a generated cell, even if it is a field, does not
-normally have a property value bound to the table's container, so changes in
-generated columns do not trigger updates in other generated columns. It should
-also be noted that if a generated column cell depends on values in other rows,
-changes in the other rows do not trigger automatic update. You can get notified
-of such value changes by listening for them with a
-[interfacename]#ValueChangeListener# in the generated components. If you do so,
-you must remove such listeners when the generated components are detached from
-the UI or otherwise the listeners will accumulate in the container when the
-table is scrolled back and forth, causing possibly severe memory leak.
-
-endif::web[]
-
-ifdef::web[]
-[[components.table.columngenerator.adding]]
-=== Adding Generated Columns
-
-You add new generated columns to a [classname]#Table# with
-[methodname]#addGeneratedColumn()#. It takes a property ID of the generated
-column as the first parameter and the generator as the second.
-
-
-[source, java]
-----
-// Define the generated columns and their generators
-table.addGeneratedColumn("date", // Java 8:
- this::generateNonEditableCell);
-table.addGeneratedColumn("price",
- new PriceColumnGenerator());
-table.addGeneratedColumn("consumption",
- new ConsumptionColumnGenerator());
-table.addGeneratedColumn("dailycost",
- new DailyCostColumnGenerator());
-----
-
-Notice that the [methodname]#addGeneratedColumn()# always places the generated
-columns as the last column, even if you defined some other order previously. You
-will have to set the proper order with [methodname]#setVisibleColumns()#.
-
-
-[source, java]
-----
-table.setVisibleColumns("date", "quantity", "price", "total");
-----
-
-endif::web[]
-
-ifdef::web[]
-[[components.table.columngenerator.editable]]
-=== Generators in Editable Table
-
-When you set a table as [parameter]#editable#, table cells change to editable
-fields. When the user changes the values in the fields, the generated cells in
-the same row are updated automatically. However, putting a table with generated
-columns in editable mode has a few quirks. One is that the editable mode does
-not affect generated columns. You have two alternatives: either you generate the
-editing fields in the generator or, in case of formatter generators, remove the
-generators in the editable mode to allow editing the values. The following
-example uses the latter approach.
-
-
-[source, java]
-----
-// Have a check box that allows the user
-// to make the quantity and total columns editable.
-final CheckBox editable = new CheckBox(
- "Edit the input values - calculated columns are regenerated");
-
-editable.setImmediate(true);
-editable.addClickListener(new ClickListener() {
- public void buttonClick(ClickEvent event) {
- table.setEditable(editable.booleanValue());
-
- // The columns may not be generated when we want to
- // have them editable.
- if (editable.booleanValue()) {
- table.removeGeneratedColumn("quantity");
- table.removeGeneratedColumn("total");
- } else { // Not editable
- // Show the formatted values.
- table.addGeneratedColumn("quantity",
- new ValueColumnGenerator("%.2f l"));
- table.addGeneratedColumn("total",
- new ValueColumnGenerator("%.2f e"));
- }
- // The visible columns are affected by removal
- // and addition of generated columns so we have
- // to redefine them.
- table.setVisibleColumns("date", "quantity",
- "price", "total", "consumption", "dailycost");
- }
-});
-----
-
-You will also have to set the editing fields in [parameter]#immediate# mode to
-have the update occur immediately when an edit field loses the focus. You can
-set the fields in [parameter]#immediate# mode with the a custom
-[classname]#TableFieldFactory#, such as the one given below, that just extends
-the default implementation to set the mode:
-
-
-[source, java]
-----
-public class ImmediateFieldFactory extends DefaultFieldFactory {
- public Field createField(Container container,
- Object itemId,
- Object propertyId,
- Component uiContext) {
- // Let the DefaultFieldFactory create the fields...
- Field field = super.createField(container, itemId,
- propertyId, uiContext);
-
- // ...and just set them as immediate.
- ((AbstractField)field).setImmediate(true);
-
- return field;
- }
-}
-...
-table.setTableFieldFactory(new ImmediateFieldFactory());
-----
-
-If you generate the editing fields with the column generator, you avoid having
-to use such a field factory, but of course have to generate the fields for both
-normal and editable modes.
-
-<<figure.ui.table.generated>> shows a table with columns calculated (blue) and
-simply formatted (black) with column generators.
-
-[[figure.ui.table.generated]]
-.Table with Generated Columns in Normal and Editable Mode
-image::img/table-generatedcolumns1.png[]
-
-endif::web[]
-
-
-[[components.table.columnformatting]]
-== Formatting Table Columns
-
-The displayed values of properties shown in a table are normally formatted using
-the [methodname]#toString()# method of each property. Customizing the format in
-a table column can be done in several ways:
-
-* Using [classname]#ColumnGenerator# to generate a second column that is formatted. The original column needs to be set invisible. See <<components.table.columngenerator>>.
-* Using a [classname]#Converter# to convert between the property data model and its representation in the table.
-* Using a [classname]#GeneratedPropertyContainer# as a wrapper around the actual container to provide formatting.
-* Overriding the default [methodname]#formatPropertyValue()# in [classname]#Table#.
-
-As using a [classname]#PropertyFormatter# is generally much more awkward than
-overriding the [methodname]#formatPropertyValue()#, its use is not described
-here.
-
-You can override [methodname]#formatPropertyValue()# as is done in the following
-example:
-
-
-[source, java]
-----
-// Create a table that overrides the default
-// property (column) format
-final Table table = new Table("Formatted Table") {
- @Override
- protected String formatPropertyValue(Object rowId,
- Object colId, Property property) {
- // Format by property type
- if (property.getType() == Date.class) {
- SimpleDateFormat df =
- new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- return df.format((Date)property.getValue());
- }
-
- return super.formatPropertyValue(rowId, colId, property);
- }
-};
-
-// The table has some columns
-table.addContainerProperty("Time", Date.class, null);
-
-... Fill the table with data ...
-----
-
-You can also distinguish between columns by the [parameter]#colId# parameter,
-which is the property ID of the column. [classname]#DecimalFormat# is useful for
-formatting decimal values.
-
-
-[source, java]
-----
-... in formatPropertyValue() ...
-} else if ("Value".equals(pid)) {
- // Format a decimal value for a specific locale
- DecimalFormat df = new DecimalFormat("#.00",
- new DecimalFormatSymbols(locale));
- return df.format((Double) property.getValue());
-}
-...
-table.addContainerProperty("Value", Double.class, null);
-----
-
-A table with the formatted date and decimal value columns is shown in
-<<figure.components.table.columnformatting>>.
-
-[[figure.components.table.columnformatting]]
-.Formatted Table Columns
-image::img/table-columnformatting.png[]
-
-You can use CSS for further styling of table rows, columns, and individual cells
-by using a [classname]#CellStyleGenerator#. It is described in
-<<components.table.css>>.
-
-
-[[components.table.css]]
-== CSS Style Rules
-
-Styling the overall style of a [classname]#Table# can be done with the following
-CSS rules.
-
-
-[source, css]
-----
-.v-table {}
- .v-table-header-wrap {}
- .v-table-header {}
- .v-table-header-cell {}
- .v-table-resizer {} /* Column resizer handle. */
- .v-table-caption-container {}
- .v-table-body {}
- .v-table-row-spacer {}
- .v-table-table {}
- .v-table-row {}
- .v-table-cell-content {}
-----
-
-Notice that some of the widths and heights in a table are calculated dynamically
-and can not be set in CSS.
-
-ifdef::web[]
-[[components.table.css.cellstylegenerator]]
-=== Generating Cell Styles With [interfacename]#CellStyleGenerator#
-
-The [classname]#Table.CellStyleGenerator# interface allows you to set the CSS
-style for each individual cell in a table. You need to implement the
-[methodname]#getStyle()#, which gets the row (item) and column (property)
-identifiers as parameters and can return a style name for the cell. The returned
-style name will be concatenated to prefix "
-[literal]#++v-table-cell-content-++#".
-
-The [methodname]#getStyle()# is called also for each row, so that the
-[parameter]#propertyId# parameter is [literal]#++null++#. This allows setting a
-row style.
-
-Alternatively, you can use a [classname]#Table.ColumnGenerator# (see
-<<components.table.columngenerator>>) to generate the actual UI components of
-the cells and add style names to them.
-
-
-[source, java]
-----
-Table table = new Table("Table with Cell Styles");
-table.addStyleName("checkerboard");
-
-// Add some columns in the table. In this example, the property
-// IDs of the container are integers so we can determine the
-// column number easily.
-table.addContainerProperty("0", String.class, null, "", null, null);
-for (int i=0; i<8; i++)
- table.addContainerProperty(""+(i+1), String.class, null,
- String.valueOf((char) (65+i)), null, null);
-
-// Add some items in the table.
-table.addItem(new Object[]{
- "1", "R", "N", "B", "Q", "K", "B", "N", "R"}, new Integer(0));
-table.addItem(new Object[]{
- "2", "P", "P", "P", "P", "P", "P", "P", "P"}, new Integer(1));
-for (int i=2; i<6; i++)
- table.addItem(new Object[]{String.valueOf(i+1),
- "", "", "", "", "", "", "", ""}, new Integer(i));
-table.addItem(new Object[]{
- "7", "P", "P", "P", "P", "P", "P", "P", "P"}, new Integer(6));
-table.addItem(new Object[]{
- "8", "R", "N", "B", "Q", "K", "B", "N", "R"}, new Integer(7));
-table.setPageLength(8);
-
-// Set cell style generator
-table.setCellStyleGenerator(new Table.CellStyleGenerator() {
- public String getStyle(Object itemId, Object propertyId) {
- // Row style setting, not relevant in this example.
- if (propertyId == null)
- return "green"; // Will not actually be visible
-
- int row = ((Integer)itemId).intValue();
- int col = Integer.parseInt((String)propertyId);
-
- // The first column.
- if (col == 0)
- return "rowheader";
-
- // Other cells.
- if ((row+col)%2 == 0)
- return "black";
- else
- return "white";
- }
-});
-----
-
-You can then style the cells, for example, as follows:
-
-
-[source, css]
-----
-/* Center the text in header. */
-.v-table-header-cell {
- text-align: center;
-}
-
-/* Basic style for all cells. */
-.v-table-checkerboard .v-table-cell-content {
- text-align: center;
- vertical-align: middle;
- padding-top: 12px;
- width: 20px;
- height: 28px;
-}
-
-/* Style specifically for the row header cells. */
-.v-table-cell-content-rowheader {
- background: #E7EDF3
- url(../default/table/img/header-bg.png) repeat-x scroll 0 0;
-}
-
-/* Style specifically for the "white" cells. */
-.v-table-cell-content-white {
- background: white;
- color: black;
-}
-
-/* Style specifically for the "black" cells. */
-.v-table-cell-content-black {
- background: black;
- color: white;
-}
-----
-
-The table will look as shown in <<figure.components.table.cell-style>>.
-
-[[figure.components.table.cell-style]]
-.Cell Style Generator for a Table
-image::img/table-cellstylegenerator1.png[]
-
-endif::web[]
-
-
-(((range="endofrange", startref="term.components.table")))
-
-