diff options
author | Ilia Motornyi <elmot@vaadin.com> | 2015-12-03 14:59:05 +0000 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-12-03 14:59:12 +0000 |
commit | 2af72ba9636bec70046394c41744f89ce4572e35 (patch) | |
tree | ccb3dc2d2239585f8c3f79eb5f131ff61ca9ce86 /documentation/components/components-grid.asciidoc | |
parent | 8aa5fabe89f2967e966a64842a608eceaf80d08f (diff) | |
download | vaadin-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-grid.asciidoc')
-rw-r--r-- | documentation/components/components-grid.asciidoc | 1361 |
1 files changed, 0 insertions, 1361 deletions
diff --git a/documentation/components/components-grid.asciidoc b/documentation/components/components-grid.asciidoc deleted file mode 100644 index a323dc28bb..0000000000 --- a/documentation/components/components-grid.asciidoc +++ /dev/null @@ -1,1361 +0,0 @@ ---- -title: Grid -order: 24 -layout: page ---- - -[[components.grid]] -= [classname]#Grid# - -((("[classname]#Grid#"))) -[classname]#Grid# is many things, and perhaps the most versatile and powerful -component in Vaadin. Like [classname]#Table#, it allows presenting and editing -tabular data, but escapes many of [classname]#Table#'s limitations. Efficient -lazy loading of data while scrolling greatly improves performance. Grid is -scalable, mobile friendly, and extensible. - -[[components.grid.overview]] -== Overview - -[classname]#Grid# is for displaying and editing tabular data laid out in rows -and columns. At the top, a __header__ can be shown, and a __footer__ at the -bottom. In addition to plain text, the header and footer can contain HTML and -components. Having components in the header allows implementing filtering -easily. The grid data can be sorted by clicking on a column header; -shift-clicking a column header enables secondary sorting criteria. - -[[figure.components.grid.features]] -.A [classname]#Grid# Component -image::img/grid-features.png[] - -The data area can be scrolled both vertically and horizontally. The leftmost -columns can be frozen, so that they are never scrolled out of the view. The data -is loaded lazily from the server, so that only the visible data is loaded. The -smart lazy loading functionality gives excellent user experience even with low -bandwidth, such as mobile devices. - -The grid data can be edited with a row-based editor after double-clicking a row. -The fields are generated with a field factory, or set explicitly, and bound to -data with a field group. - -Grid is fully themeable with CSS and style names can be set for all grid -elements. For data rows and cells, the styles can be generated with a row or -cell style generator. - -Finally, [classname]#Grid# is designed to be extensible and used just as well -for client-side development - its GWT API is nearly identical to the server-side -API, including data binding. - -[[components.grid.overview.table]] -=== Differences to Table - -In addition to core features listed above, [classname]#Grid# has the following -API-level and functional differences to Table: - -* Grid is not a [interfacename]#Container# itself, even though it can be bound to a container data source. Consequently, columns are defined differently, and so forth. -* Rows can be added with [methodname]#addRow()# shorthand (during initialization) instead of [methodname]#addItem()#. -* Use [methodname]#setHeightByRows()# and [methodname]#setHeightMode()# instead of [methodname]#setPageLength()# to set the height in number of rows. -* Grid does not extend [classname]#AbstractSelect# and is not a field, but has its own selection API. [methodname]#addSelectionListener()# is called to define a [interfacename]#SelectionListener#. The listener also receives a collection of deselected items. -* Grid does not support having all cells in editable mode, it only supports row-based editing, with a row mini-editor that allows saving or discarding the changes. -* Grid has no generated columns. Instead, the container data source can be wrapped around a [classname]#GeneratedPropertyContainer#. -* No column icons; you can implement them in a column with an [classname]#ImageRenderer#. -* Components can not be shown in Grid cells; instead the much more efficient renderers can be used for the most common cases, and row editor for editing values. -* No support for drag and drop currently. -* No support for column resizing by dragging from column header boundaries. -* Focusing with [methodname]#focus()# is currently not supported. - -In addition, Grid has the following visual changes: - -* Multiple selection is indicated with check boxes in addition to highlighting. -* Grid does not show the row loading indicator like Table does. - - - -[[components.grid.data]] -== Binding to Data - -[classname]#Grid# is normally used by binding it to a container data source, -described in -<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container,"Collecting -Items in Containers">>. The container must implement -[interfacename]#Container.Indexed# interface. By default, it is bound to an -[classname]#IndexedContainer#; Grid offers some shorthand methods to operate on -the default container, as described later. - -You can set the container in the constructor or with -[methodname]#setContainerDataSource()#. - -For example, if you have a collection of beans, you could wrap them in a Vaadin -[classname]#BeanItemContainer#, and bind to a [classname]#Grid# as follows - - -[source, java] ----- -// Have some data -Collection<Person> people = Lists.newArrayList( - new Person("Nicolaus Copernicus", 1543), - new Person("Galileo Galilei", 1564), - new Person("Johannes Kepler", 1571)); - -// Have a container of some type to contain the data -BeanItemContainer<Person> container = - new BeanItemContainer<Person>(Person.class, people); - -// Create a grid bound to the container -Grid grid = new Grid(container); -grid.setColumnOrder("name", "born"); -layout.addComponent(grid); ----- - -[[components.grid.basic.manual]] -=== Default Data Source and Shorthands - -Sometimes, when you have just a few fixed items that you want to display, you -can define the grid columns and add data rows manually. [classname]#Grid# is by -default bound to a [classname]#IndexedContainer#. You can define new columns -(container properties) with [methodname]#addColumn()# and then add rows (items) -with [methodname]#addRow()#. The types in the row data must match the defined -column types. - -For example: - - -[source, java] ----- -// Create a grid -Grid grid = new Grid(); - -// Define some columns -grid.addColumn("name", String.class); -grid.addColumn("born", Integer.class); - -// Add some data rows -grid.addRow("Nicolaus Copernicus", 1543); -grid.addRow("Galileo Galilei", 1564); -grid.addRow("Johannes Kepler", 1571); - -layout.addComponent(grid); ----- - -Or, if you have the data in an array: - - -[source, java] ----- -// Have some data -Object[][] people = { {"Nicolaus Copernicus", 1543}, - {"Galileo Galilei", 1564}, - {"Johannes Kepler", 1571}}; -for (Object[] person: people) - grid.addRow(person); ----- - -Note that you can not use [methodname]#addRow()# to add items if the container -is read-only or has read-only columns, such as generated columns. - - - -[[components.grid.selection]] -== Handling Selection Changes - -Selection in [classname]#Grid# is handled a bit differently from other selection -components, as it is not an [classname]#AbstractSelect#. Grid supports both -single and multiple selection, defined by the __selection mode__. Selection -events can be handled with a [interfacename]#SelectionListener#. - -[[components.grid.selection.mode]] -=== Selection Mode - -A [classname]#Grid# can be set to be in [literal]#++SINGLE++# (default), -[literal]#++MULTI++#, or [literal]#++NONE++# selection mode, defined in the -[classname]#Grid.SelectionMode# enum. - - -[source, java] ----- -// Use single-selection mode (default) -grid.setSelectionMode(SelectionMode.SINGLE); ----- - -Empty (null) selection is allowed in multi-selection mode, but not in single -selection. - -The selection is handled with a different selection model object in each -respective selection mode: [classname]#SingleSelectionModel#, -[classname]#MultiSelectionModel#, and [classname]#NoSelectionModel# (in which -selection is always empty). - - -[source, java] ----- -// Pre-select an item -SingleSelectionModel selection = - (SingleSelectionModel) grid.getSelectionModel(); -selection.select( // Select 3rd item - grid.getContainerDataSource().getIdByIndex(2)); ----- - - -[[components.grid.selection.single]] -=== Handling Selection - -Changes in the selection can be handled with a -[interfacename]#SelectionListener#. You need to implement the -[methodname]#select()# method, which gets a [classname]#SelectionEvent# as -parameter. In addition to selection, you can handle clicks on rows or cells with -a [interfacename]#ItemClickListener#. - -You can get the new selection from the selection event with -[methodname]#getSelected()#, which returns a set of item IDs, or more simply -from the grid or the selection model with [methodname]#getSelectedRow()#, which -returns the single selected item ID. - -For example: - - -[source, java] ----- -grid.addSelectionListener(selectionEvent -> { // Java 8 - // Get selection from the selection model - Object selected = ((SingleSelectionModel) - grid.getSelectionModel()).getSelectedRow(); - - if (selected != null) - Notification.show("Selected " + - grid.getContainerDataSource().getItem(selected) - .getItemProperty("name")); - else - Notification.show("Nothing selected"); -}); ----- - -The current selection can be obtained from the [classname]#Grid# object by -[methodname]#getSelectedRow()# or [methodname]#getSelectedRows()#, which return -one (in single-selection mode) or all (in multi-selection mode) selected items. - - -[WARNING] -==== -Note that changes to the item set of the container data source are not -automatically reflected in the selection model and may cause the selection model -to refer to stale item IDs. This always occurs, for example, when you delete the -selected item or items. So, if you modify the item set of the container, you -should synchronize or reset the selection with the container, such as by calling -[methodname]#reset()# on the selection model. - -==== - - - - -[[components.grid.selection.multi]] -=== Multiple Selection - -In the multiple selection mode, a user can select multiple items by clicking on -the checkboxes in the leftmost column. - -[[figure.components.grid.selection.multi]] -.Multiple Selection in [classname]#Grid# -image::img/grid-selection-multi.png[] - -The selection is managed through the [classname]#MultiSelectionMode# class. The -currently selected rows can be set with [methodname]#setSelected()# by a -collection of item IDs, or you can use [methodname]#select()# to add items to -the selection. - - -[source, java] ----- -// Grid in multi-selection mode -Grid grid = new Grid(exampleDataSource()); -grid.setSelectionMode(SelectionMode.MULTI); - -// Pre-select some items -MultiSelectionModel selection = - (MultiSelectionModel) grid.getSelectionModel(); -selection.setSelected( // Items 2-4 - grid.getContainerDataSource().getItemIds(2, 3)); - ----- - -The current selection can be read with [methodname]#getSelectedRows()#; either -in the [classname]#MultiSelectionMode# object or in the [classname]#Grid#. - - -[source, java] ----- -// Allow deleting the selected items -Button delSelected = new Button("Delete Selected", e -> { - // Delete all selected data items - for (Object itemId: selection.getSelectedRows()) - grid.getContainerDataSource().removeItem(itemId); - - // Otherwise out of sync with container - grid.getSelectionModel().reset(); - - // Disable after deleting - e.getButton().setEnabled(false); -}); -delSelected.setEnabled(grid.getSelectedRows().size() > 0); ----- - -Changes in the selection can be handled with a -[interfacename]#SelectionListener#. The selection event object provides -[methodname]#getAdded()# and [methodname]#getRemove()# to allow determining the -differences in the selection change. When [classname]#Grid# is in immediate -mode, the difference is one item, but in non-immediate mode can be more. - - -[source, java] ----- -// Handle selection changes -grid.addSelectionListener(selection -> { // Java 8 - Notification.show(selection.getAdded().size() + - " items added, " + - selection.getRemoved().size() + - " removed."); - - // Allow deleting only if there's any selected - deleteSelected.setEnabled( - grid.getSelectedRows().size() > 0); -}); ----- - - -[[components.grid.selection.clicks]] -=== Focus and Clicks - -In addition to selecting rows, you can focus individual cells. The focus can be -moved with arrow keys and, if editing is enabled, pressing Enter opens the -editor. Pressing Tab or ShiftTab moves the focus to another component, as usual. - -With mouse, you can focus a cell by clicking on it. The clicks can be handled -with an [interfacename]#ItemClickListener#. The [classname]#ItemClickEvent# -object contains various information, most importantly the ID of the clicked row -and column. - - -[source, java] ----- -grid.addItemClickListener(event -> // Java 8 - Notification.show("Value: " + - container.getContainerProperty(event.getItemId(), - event.getPropertyId()).getValue().toString())); ----- - -The clicked grid cell is also automatically focused. - -The focus indication is themed so that the focused cell has a visible focus -indicator style by default, while the row doesn't. You can enable row focus, as -well as disable cell focus, in a custom theme. See <<components.grid.css>>. - - - -[[components.grid.columns]] -== Configuring Columns - -Columns are normally defined in the container data source. The -[methodname]#addColumn()# method can be used to add columns to a container that -supports it, such as the default [classname]#IndexedContainer#. - -Column configuration is defined in [classname]#Grid.Column# objects, which can -be obtained from the grid with [methodname]#getColumn()# by the column -(property) ID. - - -[source, java] ----- -Grid.Column bornColumn = grid.getColumn("born"); -bornColumn.setHeaderCaption("Born"); ----- - -In the following, we describe the basic column configuration. - -[[components.grid.columns.order]] -=== Column Order - -You can set the order of columns with [methodname]#setColumnOrder()# for the -grid. Columns that are not given for the method are placed after the specified -columns in their natural order. - - -[source, java] ----- -grid.setColumnOrder("firstname", "lastname", "born", - "birthplace", "died"); ----- - -Note that the method can not be used to hide columns. You can hide columns with -the [methodname]#removeColumn()#, as described later, or by hiding them in a -[classname]#GeneratedPropertyContainer#. - - -[[components.grid.columns.removing]] -=== Hiding Columns - -Columns can be hidden by removing them with [methodname]#removeColumn()#. You -can remove all columns with [methodname]#removeAllColumn()#. The removed columns -are only removed from the grid, not from the container data source. - -To restore a previously removed column, you can call [methodname]#addColumn()# -with the property ID. Instead of actually adding another column to the data -source, it merely restores the previously removed one. However, column settings -such as header or editor are not restored, but must be redone. - -You can also hide columns at container-level. At least -[classname]#GeneratedpropertyContainer# allows doing so, as described in -<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container.gpc,"GeneratedPropertyContainer">>. - - -[[components.grid.columns.captions]] -=== Column Captions - -Column captions are displayed in the grid header. The default captions are -generated automatically from the property ID. You can set the header caption -explicitly through the column object with [methodname]#setHeaderCaption()#. - - -[source, java] ----- -Grid.Column bornColumn = grid.getColumn("born"); -bornColumn.setHeaderCaption("Born"); ----- - -This is equivalent to setting it with [methodname]#setText()# for the header -cell; the [classname]#HeaderCell# also allows setting the caption in HTML or as -a component, as well as styling it, as described later in -<<components.grid.headerfooter>>. - - -[[components.grid.columns.width]] -=== Column Widths - -Columns have by default undefined width, which causes automatic sizing based on -the widths of the displayed data. You can set column widths explicitly by pixel -value with [methodname]#setWidth()#, or relatively using expand ratios with -[methodname]#setExpandRatio()#. - -When using expand ratios, the columns with a non-zero expand ratio use the extra -space remaining from other columns, in proportion to the defined ratios. - -You can specify minimum and maximum widths for the expanding columns with -[methodname]#setMinimumWidth()# and [methodname]#setMaximumWidth()#, -respectively. - - -[[components.grid.columns.frozen]] -=== Frozen Columns - -You can set the number of columns to be frozen with -[methodname]#setFrozenColumnCount()#, so that they are not scrolled off when -scrolling horizontally. - - -[source, java] ----- -grid.setFrozenColumnCount(2); ----- - -Setting the count to [parameter]#0# disables frozen data columns; setting it to -[parameter]#-1# also disables the selection column in multi-selection mode. - - - -[[components.grid.generatedcolumns]] -== Generating Columns - -Columns with values computed from other columns or in some other way can be -generated with a container or data model that generates the property values. The -[classname]#GeneratedPropertyContainer# can be used for this purpose. It wraps -around any indexed container to extend its properties with read-only generated -properties. The generated properties can have same IDs as the original ones, -thereby replacing them with formatted or converted values. See -<<dummy/../../../framework/datamodel/datamodel-container#datamodel.container.gpc,"GeneratedPropertyContainer">> -for a detailed description of using it. - -Generated columns are read-only, so you can not add grid rows with -[methodname]#addRow()#. In editable mode, editor fields are not generated for -generated columns. - -Note that, while [classname]#GeneratedPropertyContainer# implements -[interfacename]#Container.Sortable#, the wrapped container might not, and also -sorting on the generated properties requires special handling. In such cases, -generated properties or the entire container might not actually be sortable. - - -[[components.grid.renderer]] -== Column Renderers - -A __renderer__ is a feature that draws the client-side representation of a data -value. This allows having images, HTML, and buttons in grid cells. - -[[figure.components.grid.renderer]] -.Column Renderers: Image, Date, HTML, and Button -image::img/grid-renderers.png[] - -Renderers implement the [interfacename]#Renderer# interface. You set the column -renderer in the [classname]#Grid.Column# object as follows: - - -[source, java] ----- -grid.addColumn("born", Integer.class); -... -Grid.Column bornColumn = grid.getColumn("born"); -bornColumn.setRenderer(new NumberRenderer("born in %d AD")); ----- - -Renderers require a specific data type for the column. To convert to a property -type to a type required by a renderer, you can pass an optional -[interfacename]#Converter# to [methodname]#setRenderer()#, as described later in -this section. A converter can also be used to (pre)format the property values. -The converter is run on the server-side, before sending the values to the -client-side to be rendered with the renderer. - -The following renderers are available, as defined in the server-side -[package]#com.vaadin.ui.renderer# package: - -[classname]#ButtonRenderer#:: Renders the data value as the caption of a button. A -[interfacename]#RendererClickListener# can be given to handle the button clicks. - -ifdef::web[] -Typically, a button renderer is used to display buttons for operating on a data -item, such as edit, view, delete, etc. It is not meaningful to store the button -captions in the data source, rather you want to generate them, and they are -usually all identical. - - -+ -[source, java] ----- -BeanItemContainer<Person> people = - new BeanItemContainer<>(Person.class); - -people.addBean(new Person("Nicolaus Copernicus", 1473)); -people.addBean(new Person("Galileo Galilei", 1564)); -people.addBean(new Person("Johannes Kepler", 1571)); - -// Generate button caption column -GeneratedPropertyContainer gpc = - new GeneratedPropertyContainer(people); -gpc.addGeneratedProperty("delete", - new PropertyValueGenerator<String>() { - - @Override - public String getValue(Item item, Object itemId, - Object propertyId) { - return "Delete"; // The caption - } - - @Override - public Class<String> getType() { - return String.class; - } -}); - -// Create a grid -Grid grid = new Grid(gpc); - -// Render a button that deletes the data row (item) -grid.getColumn("delete") - .setRenderer(new ButtonRenderer(e -> // Java 8 - grid.getContainerDataSource() - .removeItem(e.getItemId()))); ----- -endif::web[] -[classname]#ImageRenderer#:: Renders the cell as an image. The column type must be a -[interfacename]#Resource#, as described in -<<dummy/../../../framework/application/application-resources#application.resources,"Images -and Other Resources">>; only [classname]#ThemeResource# and -[classname]#ExternalResource# are currently supported for images in -[classname]#Grid#. - -ifdef::web[] - -[source, java] ----- -grid.addColumn("picture", Resource.class) - .setRenderer(new ImageRenderer()); -... -// Add some data rows -grid.addRow(new ThemeResource("img/copernicus-128px.jpg"), - "Nicolaus Copernicus", 1543); -grid.addRow(new ThemeResource("img/galileo-128px.jpg"), - "Galileo Galilei", 1564); ----- - -+ -Instead of creating the resource objects explicitly, as was done above, you -could generate them dynamically from file name strings using a -[interfacename]#Converter# for the column. - - -+ -[source, java] ----- -// Define some columns -grid.addColumn("picture", String.class); // Filename -grid.addColumn("name", String.class); - -// Set the image renderer -grid.getColumn("picture").setRenderer(new ImageRenderer(), - new Converter<Resource, String>() { - @Override - public String convertToModel(Resource value, - Class<? extends String> targetType, Locale l) - throws Converter.ConversionException { - return "not needed"; - } - - @Override - public Resource convertToPresentation(String value, - Class<? extends Resource> targetType, Locale l) - throws Converter.ConversionException { - return new ThemeResource("img/" + value); - } - - @Override - public Class<String> getModelType() { - return String.class; - } - - @Override - public Class<Resource> getPresentationType() { - return Resource.class; - } -}); - -// Add some data rows -grid.addRow("copernicus-128px.jpg", "Nicolaus Copernicus"); -grid.addRow("galileo-128px.jpg", "Galileo Galilei"); -grid.addRow("kepler-128px.jpg", "Johannes Kepler"); ----- -+ -You also need to define the row heights so that the images fit there. You can -set it in the theme for all data cells or for the column containing the images. - -+ -For the latter way, first define a CSS style name for grid and the column: - - -+ -[source, java] ----- -grid.setStyleName("gridwithpics128px"); -grid.setCellStyleGenerator(cell -> - "picture".equals(cell.getPropertyId())? - "imagecol" : null); ----- -ifdef::web[] -+ -Then, define the style in CSS (Sass): -endif::web[] - - -+ -[source, css] ----- -.gridwithpics128px .imagecol { - height: 128px; - background: black; - text-align: center; -} ----- -endif::web[] -[classname]#DateRenderer#:: Formats a column with a [classname]#Date# type using string formatter. The -format string is same as for [methodname]#String.format()# in Java API. The date -is passed in the parameter index 1, which can be omitted if there is only one -format specifier, such as " [literal]#++%tF++#". - -ifdef::web[] - -[source, java] ----- -Grid.Column bornColumn = grid.getColumn("born"); -bornColumn.setRenderer( - new DateRenderer("%1$tB %1$te, %1$tY", - Locale.ENGLISH)); ----- - -+ -Optionally, a locale can be given. Otherwise, the default locale (in the -component tree) is used. - -endif::web[] -[classname]#HTMLRenderer#:: Renders the cell as HTML. This allows formatting cell content, as well as using -HTML features such as hyperlinks. - -ifdef::web[] -First, set the renderer in the [classname]#Grid.Column# object: - - -+ -[source, java] ----- -grid.addColumn("link", String.class) - .setRenderer(new HtmlRenderer()); ----- -ifdef::web[] -+ -Then, in the grid data, give the cell content: -endif::web[] - - -+ -[source, java] ----- -grid.addRow("Nicolaus Copernicus", 1543, - "<a href='http://en.wikipedia.org/wiki/" + - "Nicolaus_Copernicus' target='_top'>info</a>"); ----- -+ -You could also use a [interfacename]#PropertyFormatter# or a generated column to -generate the HTML for the links. - -endif::web[] -[classname]#NumberRenderer#:: Formats column values with a numeric type extending [classname]#Number#: -[classname]#Integer#, [classname]#Double#, etc. The format can be specified -either by the subclasses of [classname]#java.text.NumberFormat#, namely -[classname]#DecimalFormat# and [classname]#ChoiceFormat#, or by -[methodname]#String.format()#. - -ifdef::web[] -For example: - - -+ -[source, java] ----- -// Define some columns -grid.addColumn("name", String.class); -grid.addColumn("born", Integer.class); -grid.addColumn("sletters", Integer.class); -grid.addColumn("rating", Double.class); - -// Use decimal format -grid.getColumn("born").setRenderer(new NumberRenderer( - new DecimalFormat("in #### AD"))); - -// Use textual formatting on numeric ranges -grid.getColumn("sletters").setRenderer(new NumberRenderer( - new ChoiceFormat("0#none|1#one|2#multiple"))); - -// Use String.format() formatting -grid.getColumn("rating").setRenderer(new NumberRenderer( - "%02.4f", Locale.ENGLISH)); - -// Add some data rows -grid.addRow("Nicolaus Copernicus", 1473, 2, 0.4); -grid.addRow("Galileo Galilei", 1564, 0, 4.2); -grid.addRow("Johannes Kepler", 1571, 1, 2.3); ----- -endif::web[] -[classname]#ProgressBarRenderer#:: Renders a progress bar in a column with a [classname]#Double# type. The value -must be between 0.0 and 1.0. - -ifdef::web[] -For example: - - -+ -[source, java] ----- -// Define some columns -grid.addColumn("name", String.class); -grid.addColumn("rating", Double.class) - .setRenderer(new ProgressBarRenderer()); - -// Add some data rows -grid.addRow("Nicolaus Copernicus", 0.1); -grid.addRow("Galileo Galilei", 0.42); -grid.addRow("Johannes Kepler", 1.0); ----- -endif::web[] -[classname]#TextRenderer#:: Displays plain text as is. Any HTML markup is quoted. - - - -[[components.grid.renderer.custom]] -=== Custom Renderers - -Renderers are component extensions that require a client-side counterpart. See -<<dummy/../../../framework/clientsidewidgets/clientsidewidgets-grid#clientsidewidgets.grid.renderers,"Renderers">> -for information on implementing custom renderers. - - -[[components.grid.renderer.converter]] -=== Converting for Rendering - -Optionally, you can give a [interfacename]#Converter# in the -[methodname]#setRenderer()#, or define it for the column, to convert the data -value to an intermediary representation that is rendered by the renderer. For -example, when using an [classname]#ImageRenderer#, you could the image file name -in the data column, which the converter would convert to a resource, which would -then be rendered by the renderer. - -In the following example, we use a converter to format URL paths to complete -HTML hyperlinks with [classname]#HTMLRenderer#: - - -[source, java] ----- -// Have a column for hyperlink paths to Wikipedia -grid.addColumn("link", String.class); - -Grid.Column linkColumn = grid.getColumn("link"); -linkColumn.setRenderer(new HtmlRenderer(), - new Converter<String,String>(){ - @Override - public String convertToModel(String value, - Class<? extends String> targetType, Locale locale) - throws Converter.ConversionException { - return "not implemented"; - } - - @Override - public String convertToPresentation(String value, - Class<? extends String> targetType, Locale locale) - throws Converter.ConversionException { - return "<a href='http://en.wikipedia.org/wiki/" + - value + "' target='_blank'>more info</a>"; - } - - @Override - public Class<String> getModelType() { - return String.class; - } - - @Override - public Class<String> getPresentationType() { - return String.class; - } -}); - -// Data with a hyperlink path in the third column -grid.addRow("Nicolaus Copernicus", 1473, - "Nicolaus_Copernicus"); -... ----- - -A [classname]#GeneratedPropertyContainer# could be used for much the same -purpose. - - - -[[components.grid.headerfooter]] -== Header and Footer - -A grid by default has a header, which displays column names, and can have a -footer. Both can have multiple rows and neighbouring header row cells can be -joined to feature column groups. - -[[components.grid.headerfooter.adding]] -=== Adding and Removing Header and Footer Rows - -A new header row is added with [methodname]#prependHeaderRow()#, which adds it -at the top of the header, [methodname]#appendHeaderRow()#, which adds it at the -bottom of the header, or with [methodname]#addHeaderRowAt()#, which inserts it -at the specified 0-base index. All of the methods return a -[classname]#HeaderRow# object, which you can use to work on the header further. - - -[source, java] ----- -// Group headers by joining the cells -HeaderRow groupingHeader = grid.prependHeaderRow(); -... - -// Create a header row to hold column filters -HeaderRow filterRow = grid.appendHeaderRow(); -... ----- - -Similarly, you can add footer rows with [methodname]#appendFooterRow()#, -[methodname]#prependFooterRow()#, and [methodname]#addFooterRowAt()#. - - -[[components.grid.headerfooter.joining]] -=== Joining Header and Footer Cells - -You can join two or more header or footer cells with the [methodname]#join()# -method. For header cells, the intention is usually to create column grouping, -while for footer cells, you typically calculate sums or averates. - - -[source, java] ----- -// Group headers by joining the cells -HeaderRow groupingHeader = grid.prependHeaderRow(); -HeaderCell namesCell = groupingHeader.join( - groupingHeader.getCell("firstname"), - groupingHeader.getCell("lastname")); -HeaderCell yearsCell = groupingHeader.join( - groupingHeader.getCell("born"), - groupingHeader.getCell("died"), - groupingHeader.getCell("lived")); ----- - - -[[components.grid.headerfooter.content]] -=== Text and HTML Content - -You can set the header caption with [methodname]#setText()#, in which case any -HTML formatting characters are quoted to ensure security. - - -[source, java] ----- -HeaderRow mainHeader = grid.getDefaultHeaderRow(); -mainHeader.getCell("firstname").setText("First Name"); -mainHeader.getCell("lastname").setText("Last Name"); -mainHeader.getCell("born").setText("Born In"); -mainHeader.getCell("died").setText("Died In"); -mainHeader.getCell("lived").setText("Lived For"); ----- - -To use raw HTML in the captions, you can use [methodname]#setHTML()#. - - -[source, java] ----- -namesCell.setHtml("<b>Names</b>"); -yearsCell.setHtml("<b>Years</b>"); ----- - - -[[components.grid.headerfooter.components]] -=== Components in Header or Footer - -You can set a component in a header or footer cell with -[methodname]#setComponent()#. Often, this feature is used to allow filtering, as -described in <<components.grid.filtering>>, which also gives an example of the -use. - - - -[[components.grid.filtering]] -== Filtering - -The ability to include components in the grid header can be used to create -filters for the grid data. Filtering is done in the container data source, so -the container must be of type that implements -[interfacename]#Container.Filterable#. - -[[figure.components.grid.filtering]] -.Filtering Grid -image::img/grid-filtering.png[] - -The filtering illustrated in <<figure.components.grid.filtering>> can be created -as follows: - - -[source, java] ----- -// Have a filterable container -IndexedContainer container = exampleDataSource(); - -// Create a grid bound to it -Grid grid = new Grid(container); -grid.setSelectionMode(SelectionMode.NONE); -grid.setWidth("500px"); -grid.setHeight("300px"); - -// Create a header row to hold column filters -HeaderRow filterRow = grid.appendHeaderRow(); - -// Set up a filter for all columns -for (Object pid: grid.getContainerDataSource() - .getContainerPropertyIds()) { - HeaderCell cell = filterRow.getCell(pid); - - // Have an input field to use for filter - TextField filterField = new TextField(); - filterField.setColumns(8); - - // Update filter When the filter input is changed - filterField.addTextChangeListener(change -> { - // Can't modify filters so need to replace - container.removeContainerFilters(pid); - - // (Re)create the filter if necessary - if (! change.getText().isEmpty()) - container.addContainerFilter( - new SimpleStringFilter(pid, - change.getText(), true, false)); - }); - cell.setComponent(filterField); -} ----- - - -[[components.grid.sorting]] -== Sorting - -A user can sort the data in a grid on a column by clicking the column header. -Clicking another time on the current sort column reverses the sort direction. -Clicking on other column headers while keeping the Shift key pressed adds a -secondary or more sort criteria. - -[[figure.components.grid.sorting]] -.Sorting Grid on Multiple Columns -image::img/grid-sorting.png[] - -Defining sort criteria programmatically can be done with the various -alternatives of the [methodname]#sort()# method. You can sort on a specific -column with [methodname]#sort(Object propertyId)#, which defaults to ascending -sorting order, or [methodname]#sort(Object propertyId, SortDirection -direction)#, which allows specifying the sort direction. - - -[source, java] ----- -grid.sort("name", SortDirection.DESCENDING); ----- - -To sort on multiple columns, you need to use the fluid sort API with -[methodname]#sort(Sort)#, which allows chaining sorting rules. Sorting rules are -created with the static [methodname]#by()# method, which defines the primary -sort column, and [methodname]#then()#, which can be used to specify any -secondary sort columns. They default to ascending sort order, but the sort -direction can be given with an optional parameter. - - -[source, java] ----- -// Sort first by city and then by name -grid.sort(Sort.by("city", SortDirection.ASCENDING) - .then("name", SortDirection.DESCENDING)); ----- - -The container data source must support sorting. At least, it must implement -[interfacename]#Container.Sortable#. Note that when using -[classname]#GeneratedPropertyContainer#, as described in -<<components.grid.generatedcolumns>>, even though the container implements the -interface, the wrapped container must also support it. Also, the generated -properties are not normally sortable, but require special handling to enable -sorting. - - -[[components.grid.editing]] -== Editing - -Grid supports line-based editing, where double-clicking a row opens the row -editor. In the editor, the input fields can be edited, as well as navigated with -Tab and ShiftTab keys. The editor has a [guibutton]#Save# button that commits -the data item to the container data source and closes the editor. If validation -fails, an error is displayed and the user can correct the inputs. A -[guibutton]#Cancel# button discards the changes and exits the editor. - -To enable editing, you need to call [methodname]#setEditorEnabled(true)# for the -grid. - - -[source, java] ----- -Grid grid = new Grid(GridExample.exampleDataSource()); -grid.setEditorEnabled(true); ----- - -A row under editing is illustrated in <<figure.components.grid.editing>>. - -[[figure.components.grid.editing]] -.Editing a Grid Row -image::img/grid-editor-basic.png[] - -The editor fields are by default generated with a [interfacename]#FieldFactory# -and bound to the container data source with a [classname]#FieldGroup#, which -also handles tasks such as validation, as explained later. - -To disable editing in a particular column, you can call -[methodname]#setEditable()# in the [classname]#Column# object with -[parameter]#false# parameter. - -[[components.grid.editing.editorfields]] -=== Customizing Editor Fields - -Te editor fields are normally created by the field factory of the editor's field -group, which creates the fields according to the data types of their respective -columns. To customize the editor fields of specific properties, such as to style -them or to set up validation, you can provide them with -[methodname]#setEditorField()# in the respective columns. - -In the following example, we configure a field with validation and styling: - - -[source, java] ----- -TextField nameEditor = new TextField(); - -// Custom CSS style -nameEditor.addStyleName("nameeditor"); - -// Custom validation -nameEditor.addValidator(new RegexpValidator( - "^\\p{Alpha}+ \\p{Alpha}+$", - "Need first and last name")); - -grid.getColumn("name").setEditorField(nameEditor); ----- - -Setting an editor field to [parameter]#null# deletes the currently existing -editor field, whether it was automatically generated or set explicitly with the -setter. It will be regenerated with the factory the next time it is needed. - - -ifdef::web[] -[[components.grid.editing.captions]] -=== Customizing Editor Buttons - -The editor has two buttons: [guibutton]#Save# and [guibutton]#Cancel#. You can -set their captions with [methodname]#setEditorSaveCaption()# and -[methodname]#setEditorCancelCaption()#, respectively. - -In the following example, we demonstrate one way to translate the captions: - - -[source, java] ----- -// Captions are stored in a resource bundle -ResourceBundle bundle = ResourceBundle.getBundle( - MyAppCaptions.class.getName(), - Locale.forLanguageTag("fi")); // Finnish - -// Localize the editor button captions -grid.setEditorSaveCaption( - bundle.getString(MyAppCaptions.SaveKey)); -grid.setEditorCancelCaption( - bundle.getString(MyAppCaptions.CancelKey)); ----- - -endif::web[] - -[[components.grid.editing.fieldgroup]] -=== Binding to Data with a Field Group - -Data binding to the item under editing is handled with a -[classname]#FieldGroup#, which you need to set with -[methodname]#setEditorFieldGroup#. This is mostly useful when using -special-purpose field groups, such as [classname]#BeanFieldGroup# to enable bean -validation. - -For example, assuming that we want to enable bean validation for a bean such as -the following: - - -[source, java] ----- -public class Person implements Serializable { - @NotNull - @Size(min=2, max=10) - private String name; - - @Min(1) - @Max(130) - private int age; - ...] ----- - -We can now use a [classname]#BeanFieldGroup# in the [classname]#Grid# as -follows: - - -[source, java] ----- -Grid grid = new Grid(exampleBeanDataSource()); -grid.setColumnOrder("name", "age"); -grid.setEditorEnabled(true); - -// Enable bean validation for the data -grid.setEditorFieldGroup( - new BeanFieldGroup<Person>(Person.class)); - -// Have some extra validation in a field -TextField nameEditor = new TextField(); -nameEditor.addValidator(new RegexpValidator( - "^\\p{Alpha}+ \\p{Alpha}+$", - "Need first and last name")); -grid.setEditorField("name", nameEditor); ----- - -To use bean validation as in the example above, you need to include an -implementation of the Bean Validation API in the classpath, as described in -<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.beanvalidation,"Bean -Validation">>. - - -ifdef::web[] -[[components.grid.editing.validation]] -=== Handling Validation Errors - -The input fields are validated when the save button is clicked. The default -error handler displays error indicators in the invalid fields, as well as the -first error in the editor. - -[[figure.components.grid.errors]] -.Editing a Grid Row -image::img/grid-editor-errors.png[] - -You can modify the error handling by implementing a custom -[interfacename]#EditorErrorHandler# or by extending the -[classname]#DefaultEditorErrorHandler#. - -endif::web[] - -[[components.grid.editing.fieldfactory]] -=== Editor Field Factory - -The fields are generated by the [classname]#FieldFactory# of the field group; -you can also set it with [methodname]#setEditorFieldFactory()#. Alternatively, -you can create the editor fields explicitly with [methodname]#setEditorField()#. - - - -[[components.grid.scrolling]] -== Programmatic Scrolling - -You can scroll to first item with [methodname]#scrollToStart()#, to end with -[methodname]#scrollToEnd()#, or to a specific row with [methodname]#scrollTo()#. - - -[[components.grid.stylegeneration]] -== Generating Row or Cell Styles - -You can style entire rows with a [interfacename]#RowStyleGenerator# or -individual cells with a [interfacename]#CellStyleGenerator#. - -[[components.grid.stylegeneration.row]] -=== Generating Row Styles - -You set a [interfacename]#RowStyleGenerator# to a grid with -[methodname]#setRowStyleGenerator()#. The [methodname]#getStyle()# method gets a -[classname]#RowReference#, which contains various information about the row and -a reference to the grid, and should return a style name or [parameter]#null# if -no style is generated. - -For example, to add a style names to rows having certain values in one column, -you can style them as follows: - - -[source, java] ----- -grid.setRowStyleGenerator(rowRef -> {// Java 8 - if (! ((Boolean) rowRef.getItem() - .getItemProperty("alive") - .getValue()).booleanValue()) - return "grayed"; - else - return null; -}); ----- - -You could then style the rows with CSS as follows: - - -[source, css] ----- -.v-grid-row.grayed { - color: gray; -} ----- - - -[[components.grid.stylegeneration.cell]] -=== Generating Cell Styles - -You set a [interfacename]#CellStyleGenerator# to a grid with -[methodname]#setCellStyleGenerator()#. The [methodname]#getStyle()# method gets -a [classname]#CellReference#, which contains various information about the cell -and a reference to the grid, and should return a style name or [parameter]#null# -if no style is generated. - -For example, to add a style name to a specific column, you can match on the -property ID of the column as follows: - - -[source, java] ----- -grid.setCellStyleGenerator(cellRef -> // Java 8 - "born".equals(cellRef.getPropertyId())? - "rightalign" : null); ----- - -You could then style the cells with a CSS rule as follows: - - -[source, css] ----- -.v-grid-cell.rightalign { - text-align: right; -} ----- - - - -[[components.grid.css]] -== Styling with CSS - - -[source, css] ----- -.v-grid { - .v-grid-scroller, .v-grid-scroller-horizontal { } - .v-grid-tablewrapper { - .v-grid-header { - .v-grid-row { - .v-grid-cell, .frozen, .v-grid-cell-focused { } - } - } - .v-grid-body { - .v-grid-row, - .v-grid-row-stripe, - .v-grid-row-has-data { - .v-grid-cell, .frozen, .v-grid-cell-focused { } - } - } - .v-grid-footer { - .v-grid-row { - .v-grid-cell, .frozen, .v-grid-cell-focused { } - } - } - } - .v-grid-header-deco { } - .v-grid-footer-deco { } - .v-grid-horizontal-scrollbar-deco { } - .v-grid-editor { - .v-grid-editor-cells { } - .v-grid-editor-footer { - .v-grid-editor-message { } - .v-grid-editor-buttons { - .v-grid-editor-save { } - .v-grid-editor-cancel { } - } - } - } -} ----- - -A [classname]#Grid# has an overall [literal]#++v-grid++# style. The actual grid -has three parts: a header, a body, and a footer. The scrollbar is a custom -element with [literal]#++v-grid-scroller++# style. In addition, there are some -decoration elements. - -Grid cells, whether thay are in the header, body, or footer, have a basic -[literal]#++v-grid-cell++# style. Cells in a frozen column additionally have a -[literal]#++frozen++# style. Rows have [literal]#++v-grid-row++# style, and -every other row has additionally a [literal]#++v-grid-row-stripe++# style. - -The focused row has additionally [literal]#++v-grid-row-focused++# style and -focused cell [literal]#++v-grid-cell-focused++#. By default, cell focus is -visible, with the border stylable with [parameter]#$v-grid-cell-focused-border# -parameter in Sass. Row focus has no visible styling, but can be made visible -with the [parameter]#$v-grid-row-focused-background-color# parameter or with a -custom style rule. - -In editing mode, a [literal]#++v-grid-editor++# overlay is placed on the row -under editing. In addition to the editor field cells, it has an error message -element, as well as the buttons. - - -((())) - - |