| 1472 | | <para> |
| 1473 | | The default scrollable style supports most of the table features. User |
| 1474 | | can resize the columns by dragging their borders, change the sorting |
| 1475 | | by clicking on the column headers, collapse the columns if |
| 1476 | | <parameter>columnCollapsingAllowed</parameter> is |
| 1477 | | <parameter>true</parameter>, and reorder them if |
| 1478 | | <parameter>columnReorderingAllowed</parameter> is |
| 1479 | | <parameter>true</parameter>. You can set the column width of |
| 1480 | | individual columns with <methodname>setColumnWidth()</methodname>. |
| 1481 | | </para> |
| | 1479 | <para> |
| | 1480 | The default scrollable style supports most of the table features. User |
| | 1481 | can resize the columns by dragging their borders, change the sorting |
| | 1482 | by clicking on the column headers, collapse the columns if |
| | 1483 | <parameter>columnCollapsingAllowed</parameter> is |
| | 1484 | <parameter>true</parameter>, and reorder them if |
| | 1485 | <parameter>columnReorderingAllowed</parameter> is |
| | 1486 | <parameter>true</parameter>. You can set the column width of |
| | 1487 | individual columns with <methodname>setColumnWidth()</methodname>. |
| | 1488 | </para> |
| | 1489 | </section> |
| 1492 | | <programlisting><![CDATA[import com.itmill.toolkit.ui.*; |
| 1493 | | |
| 1494 | | /* This example demonstrates use of a UI component, |
| 1495 | | * namely a checkbox (Button), in a table column. */ |
| 1496 | | public class TableExample3 extends CustomComponent { |
| 1497 | | /* Create the table with a caption. */ |
| 1498 | | Table table = new Table("This is a Table"); |
| 1499 | | |
| 1500 | | /* A layout needed for the example. */ |
| 1501 | | OrderedLayout layout = new OrderedLayout(OrderedLayout.ORIENTATION_VERTICAL); |
| 1502 | | Label status = new Label("-"); |
| | 1501 | <para> |
| | 1502 | When handling events for components inside a |
| | 1503 | <classname>Table</classname>, such as for the |
| | 1504 | <classname>Button</classname> in the example below, you usually need |
| | 1505 | to know the item the component belongs to. Components do not |
| | 1506 | themselves know about the table or the specific item in which a |
| | 1507 | component is contained. Therefore, the handling method must use some |
| | 1508 | other means for finding out the Item ID of the item. There are a few |
| | 1509 | possibilities. Usually the easiest way is to use the |
| | 1510 | <methodname>setData()</methodname> method to attach an arbitrary |
| | 1511 | object to a component. You can subclass the component and include the |
| | 1512 | identity information there. You can also simply search the entire |
| | 1513 | table for the item with the component, although that solution may not |
| | 1514 | be so scalable. |
| | 1515 | </para> |
| | 1516 | |
| | 1517 | <para> |
| | 1518 | The example below includes table rows with a |
| | 1519 | <classname>Label</classname> in XHTML formatting mode, a multiline |
| | 1520 | <classname>TextField</classname>, a <classname>CheckBox</classname>, |
| | 1521 | and a <classname>Button</classname> that shows as a link. |
| | 1522 | </para> |
| | 1523 | |
| | 1524 | <programlisting><![CDATA[// Create a table and add a style to allow setting the row height in theme. |
| | 1525 | final Table table = new Table(); |
| | 1526 | table.addStyleName("components-inside"); |
| | 1527 | |
| | 1528 | /* Define the names and data types of columns. |
| | 1529 | * The "default value" parameter is meaningless here. */ |
| | 1530 | table.addContainerProperty("Sum", Label.class, null); |
| | 1531 | table.addContainerProperty("Is Transferred", CheckBox.class, null); |
| | 1532 | table.addContainerProperty("Comments", TextField.class, null); |
| | 1533 | table.addContainerProperty("Details", Button.class, null); |
| | 1534 | |
| | 1535 | /* Add a few items in the table. */ |
| | 1536 | for (int i=0; i<100; i++) { |
| | 1537 | // Create the fields for the current table row |
| | 1538 | Label sumField = new Label(String.format("Sum is <b>$%04.2f</b><br/><i>(VAT incl.)</i>", |
| | 1539 | new Object[] {new Double(Math.random()*1000)}), |
| | 1540 | Label.CONTENT_XHTML); |
| | 1541 | CheckBox transferredField = new CheckBox("is transferred"); |
| 1504 | | TableExample3 () { |
| 1505 | | setCompositionRoot (layout); |
| 1506 | | layout.addComponent(table); |
| 1507 | | |
| 1508 | | /* Define the names, data types, and default values of columns. */ |
| 1509 | | table.addContainerProperty("First Name", String.class, "(no first name)"); |
| 1510 | | table.addContainerProperty("Last Name", String.class, "(no last name)"); |
| 1511 | | table.addContainerProperty("Year", Integer.class, null); |
| 1512 | | |
| 1513 | | /* Add a column containing Button components. |
| 1514 | | * Use differing PID (ismember) and column header ("Member"). */ |
| 1515 | | table.addContainerProperty("ismember", Button.class, null, "Member", null, null); |
| 1516 | | |
| 1517 | | /* We use these entries to generate random items in a table. */ |
| 1518 | | final String[] firstnames = new String[]{"Donald", "Patty", "Sally", "Douglas"}; |
| 1519 | | final String[] lastnames = new String[]{"Smith", "Jones", "Adams", "Knuth"}; |
| 1520 | | |
| 1521 | | /* Add some items in the table and assign them an Item ID (IID). */ |
| 1522 | | for (int i=0; i<500; i++) { |
| 1523 | | /* Create a button and bind it to a button click listener method. */ |
| 1524 | | Button button = new Button("", this, "checkboxClick"); |
| 1525 | | |
| 1526 | | /* Set the button to be a two-state checkbox. */ |
| 1527 | | button.setSwitchMode(true); |
| 1528 | | |
| 1529 | | /* Add a randomly generated item to the Table. */ |
| 1530 | | table.addItem(new Object[] { |
| 1531 | | firstnames[(int) (Math.random() * (firstnames.length-0.01))], |
| 1532 | | lastnames [(int) (Math.random() * (lastnames.length-0.01))], |
| 1533 | | (int) (1900+Math.random() * 100), |
| 1534 | | button}, |
| 1535 | | i); |
| 1536 | | } |
| 1537 | | |
| 1538 | | layout.addComponent(status); |
| 1539 | | } |
| 1540 | | |
| 1541 | | public void checkboxClick(Button.ClickEvent event) { |
| 1542 | | /* Notice that the event or the button does not know which item |
| 1543 | | * the Button is in. */ |
| 1544 | | status.setValue("A button was clicked. New value:" + event.getButton().getValue()); |
| 1545 | | } |
| | 1543 | // Multiline text field. This required modifying the height of the |
| | 1544 | // table row. |
| | 1545 | TextField commentsField = new TextField(); |
| | 1546 | commentsField.setRows(3); |
| | 1547 | |
| | 1548 | // The Table item identifier for the row. |
| | 1549 | Integer itemId = new Integer(i); |
| | 1550 | |
| | 1551 | // Create a button and handle its click. A Button does not know |
| | 1552 | // the item it is contained in, so we have to store the item |
| | 1553 | // ID as user-defined data. |
| | 1554 | Button detailsField = new Button("show details"); |
| | 1555 | detailsField.setData(itemId); |
| | 1556 | detailsField.addListener(new Button.ClickListener() { |
| | 1557 | public void buttonClick(ClickEvent event) { |
| | 1558 | // Get the item identifier from the user-defined data. |
| | 1559 | Integer itemId = (Integer)event.getButton().getData(); |
| | 1560 | getWindow().showNotification("Link "+itemId.intValue()+" clicked."); |
| | 1561 | } |
| | 1562 | }); |
| | 1563 | detailsField.addStyleName("link"); |
| | 1564 | |
| | 1565 | // Create the table row. |
| | 1566 | table.addItem(new Object[] {sumField, transferredField, |
| | 1567 | commentsField, detailsField}, |
| | 1568 | itemId); |
| | 1569 | } |
| | 1570 | |
| | 1571 | /* Show just three rows because they are so high. */ |
| | 1572 | table.setPageLength(3);]]></programlisting> |
| | 1573 | |
| | 1574 | <para> |
| | 1575 | The row height has to be set higher than the default with a style rule |
| | 1576 | such as the following: |
| | 1577 | </para> |
| | 1578 | |
| | 1579 | <programlisting><![CDATA[/* Table rows contain three-row TextField components. */ |
| | 1580 | .i-table-components-inside .i-table-cell-content { |
| | 1581 | height: 54px; |
| | 1596 | </section> |
| | 1597 | |
| | 1598 | <section> |
| | 1599 | <title>Editing the Values of a Table</title> |
| | 1600 | |
| | 1601 | <para> |
| | 1602 | Normally, a <classname>Table</classname> simply displays the items and |
| | 1603 | their fields as text. If you want to allow the user to edit the |
| | 1604 | values, you can either put them inside components as we did above, or |
| | 1605 | you can simply call <methodname>setEditable(true)</methodname> and the |
| | 1606 | cells are automatically turned into editable fields. |
| | 1607 | </para> |
| | 1608 | |
| | 1609 | <para> |
| | 1610 | Let us begin with a regular table with a some columns with usual Java |
| | 1611 | types, namely a <classname>Date</classname>, |
| | 1612 | <classname>Boolean</classname>, and a <classname>String</classname>. |
| | 1613 | </para> |
| | 1614 | |
| | 1615 | <programlisting><![CDATA[// Create a table. It is by default not editable. |
| | 1616 | final Table table = new Table(); |
| | 1617 | |
| | 1618 | // Define the names and data types of columns. |
| | 1619 | table.addContainerProperty("Date", Date.class, null); |
| | 1620 | table.addContainerProperty("Work", Boolean.class, null); |
| | 1621 | table.addContainerProperty("Comments", String.class, null); |
| | 1622 | |
| | 1623 | // Add a few items in the table. |
| | 1624 | for (int i=0; i<100; i++) { |
| | 1625 | Calendar calendar = new GregorianCalendar(2008,0,1); |
| | 1626 | calendar.add(Calendar.DAY_OF_YEAR, i); |
| | 1627 | |
| | 1628 | // Create the table row. |
| | 1629 | table.addItem(new Object[] {calendar.getTime(), |
| | 1630 | new Boolean(false), |
| | 1631 | ""}, |
| | 1632 | new Integer(i)); // Item identifier |
| | 1633 | } |
| | 1634 | |
| | 1635 | table.setPageLength(8); |
| | 1636 | layout.addComponent(table);]]></programlisting> |
| | 1637 | |
| | 1638 | <para> |
| | 1639 | You could put the table in editable mode right away if you need |
| | 1640 | to. We'll continue the example by adding a mechanism to switch the |
| | 1641 | <classname>Table</classname> from and to the editable mode. |
| | 1642 | </para> |
| | 1643 | |
| | 1644 | <programlisting><![CDATA[final CheckBox switchEditable = new CheckBox("Editable"); |
| | 1645 | switchEditable.addListener(new Property.ValueChangeListener() { |
| | 1646 | public void valueChange(ValueChangeEvent event) { |
| | 1647 | table.setEditable(((Boolean)event.getProperty().getValue()).booleanValue()); |
| | 1648 | } |
| | 1649 | }); |
| | 1650 | switchEditable.setImmediate(true); |
| | 1651 | layout.addComponent(switchEditable);]]></programlisting> |
| | 1652 | |
| | 1653 | <para> |
| | 1654 | Now, when you check to checkbox, the components in the table turn into |
| | 1655 | editable fields, as shown in <xref |
| | 1656 | linkend="figure.component.table.editable"/> below. |
| | 1657 | </para> |
| | 1658 | |
| | 1659 | <figure xml:id="figure.component.table.editable"> |
| | 1660 | <title>A Table in Normal and Editable Mode</title> |
| | 1661 | <mediaobject> |
| | 1662 | <imageobject role="html"> |
| | 1663 | <imagedata align="center" fileref="img/components/table-editable1+2.png"/> |
| | 1664 | </imageobject> |
| | 1665 | <imageobject role="fo"> |
| | 1666 | <imagedata scale="45" align="center" fileref="img/components/table-editable1+2.png"/> |
| | 1667 | </imageobject> |
| | 1668 | </mediaobject> |
| | 1669 | </figure> |
| | 1670 | |
| | 1671 | <para> |
| | 1672 | The field components that allow editing the values of particular types |
| | 1673 | are defined in a <classname>FieldFactory</classname>. The default |
| | 1674 | implementation is <classname>BaseFieldFactory</classname>, which |
| | 1675 | offers the following crude mappings: |
| | 1676 | </para> |
| | 1677 | |
| | 1678 | <table> |
| | 1679 | <title>Type to Field Mappings in <classname>BaseFieldFactory</classname></title> |
| | 1680 | <tgroup cols="2" align="left"> |
| | 1681 | <thead> |
| | 1682 | <row valign="top"> |
| | 1683 | <entry>Property Type</entry> |
| | 1684 | <entry>Mapped to Field Class</entry> |
| | 1685 | </row> |
| | 1686 | </thead> |
| | 1687 | <tbody> |
| | 1688 | <row valign="top"> |
| | 1689 | <entry><classname>Date</classname></entry> |
| | 1690 | <entry>A <classname>DateField</classname>. </entry> |
| | 1691 | </row> |
| | 1692 | <row valign="top"> |
| | 1693 | <entry><classname>Boolean</classname></entry> |
| | 1694 | <entry>A <classname>CheckBox</classname>.</entry> |
| | 1695 | </row> |
| | 1696 | <row valign="top"> |
| | 1697 | <entry><classname>Item</classname></entry> |
| | 1698 | |
| | 1699 | <entry>A <classname>Form</classname>. The fields of the |
| | 1700 | form are automatically created from the item's properties |
| | 1701 | using the default field factory, that is, |
| | 1702 | <classname>BaseFieldFactory</classname>. The normal use |
| | 1703 | for this property type is inside a |
| | 1704 | <classname>Form</classname> and is less useful inside a |
| | 1705 | <classname>Table</classname>.</entry> |
| | 1706 | </row> |
| | 1707 | <row valign="top"> |
| | 1708 | <entry><emphasis>others</emphasis></entry> |
| | 1709 | |
| | 1710 | <entry>A <classname>TextField</classname>. The text field |
| | 1711 | manages conversions from the basic types, if |
| | 1712 | possible.</entry> |
| | 1713 | </row> |
| | 1714 | </tbody> |
| | 1715 | </tgroup> |
| | 1716 | </table> |
| | 1717 | |
| | 1718 | <para> |
| | 1719 | Field factories are covered with more detail in <xref |
| | 1720 | linkend="section.component.form.fieldfactory"/>. In the default |
| | 1721 | <classname>BaseFieldFactory</classname> (you might want to look the |
| | 1722 | source code), the mappings are defined in |
| | 1723 | <methodname>createField(<classname>Class</classname> type, |
| | 1724 | <classname>Component</classname> uiContext)</methodname> method, but |
| | 1725 | you can implement any other of the abstract |
| | 1726 | <classname>FieldFactory</classname> methods, depending on your needs. |
| | 1727 | </para> |
| | 1728 | |