String[] paramValue = request.getParameterValues(getId() + ".selected"); String[] selectedRows = removeEmptyStrings(paramValue); List<Integer> oldSelections = getSelectedRows(); List<Integer> newSelections; boolean singleSelect = SelectMode.SINGLE.equals(getSelectMode()); if (getDataModel().getRowCount() == 0) { newSelections = new ArrayList<>(); selectedRows = new String[0]; } else if (getPaginationMode() == PaginationMode.NONE || getPaginationMode() == PaginationMode.CLIENT || oldSelections == null) { newSelections = new ArrayList<>(selectedRows.length); int startRow = getCurrentPageStartRow(); int endRow = getCurrentPageEndRow(); newSelections.removeAll(getRowIds(startRow, endRow)); setSelectedRows(newSelections); Action selectionChangeAction = getSelectionChangeAction();
@Override public void execute(final ActionEvent event) { table.updateBeanValue(); table.getRepeater().reset(); } });
/** * Creates and configures the table to be used by the example. The table is configured with global rather than user * data. Although this is not a realistic scenario, it will suffice for this example. * * @return a new configured table. */ private WDataTable createTable() { WDataTable tbl = new WDataTable(); tbl.addColumn(new WTableColumn("First name", new WTextField())); tbl.addColumn(new WTableColumn("Last name", new WTextField())); tbl.addColumn(new WTableColumn("DOB", new WDateField())); tbl.setExpandMode(ExpandMode.CLIENT); TableTreeNode root = createTree(); tbl.setDataModel(new ExampleTreeTableModel(root)); return tbl; }
/** * @return the list of selected row indices, will not be null. */ public List<Integer> getSelectedRows() { return getComponentModel().getSelectedRows(); }
/** * Sort the table data by the specified column. * * @param sortCol the column to sort * @param sortAsc true if sort ascending, otherwise sort descending */ public void sort(final int sortCol, final boolean sortAsc) { int[] rowIndexMappings = getDataModel().sort(sortCol, sortAsc); getOrCreateComponentModel().rowIndexMapping = rowIndexMappings; setSort(sortCol, sortAsc); if (rowIndexMappings == null) { // There's no way to correlate the previously selected row indices // with the new order of rows, so we need to clear out the selection. setSelectedRows(null); setExpandedRows(null); } }
@Test public void testMultipleHandleSelectionSortedDataRequest() { WDataTable table = new WDataTable(); table.setSelectMode(WDataTable.SelectMode.MULTIPLE); table.setPaginationMode(PaginationMode.DYNAMIC); table.setRowsPerPage(3); table.setDataModel(model); table.setLocked(true); setActiveContext(createUIContext()); table.setBean(list); request.setParameter(table.getId() + "-h", "x"); request.setParameter(table.getId() + ".selected", new String[]{"1"}); table.handleRequest(request); Assert.assertEquals("Incorrect selection after handleRequest", Arrays.asList( new Integer[]{1}), table.getSelectedRows()); table.sort(0, false); request.setParameter(table.getId() + "-h", "x"); request.setParameter(table.getId() + ".selected", new String[]{"8"}); table.handleRequest(request); Assert.assertEquals("Incorrect selection after handleRequest", Arrays.asList( new Integer[]{1, 8}), table.getSelectedRows());
WDataTable table = new WDataTable(); table.setSelectMode(WDataTable.SelectMode.SINGLE); table.setDataModel(model); table.addColumn(new WTableColumn("dummy", WText.class)); table.setLocked(true); setActiveContext(createUIContext()); request.setParameter(table.getId() + "-h", "x"); request.setParameter(table.getId() + ".sort", "0"); table.handleRequest(request); Assert.assertTrue("Incorrect selection after handleRequest", table.isSorted()); Assert.assertEquals("Incorrect sort column after handleRequest", 0, table. getSortColumnIndex()); Assert.assertTrue("Incorrect sort direction after handleRequest", table.isSortAscending()); List rowIndices = table.getRepeater().getBeanList(); Assert.assertEquals("Incorrect sort", Arrays.asList(new Integer[]{0, 2, 1}), rowIndices); Assert.assertFalse("Incorrect default sort after handleRequest", table.isSorted()); request.setParameter(table.getId() + "-h", "x"); request.setParameter(table.getId() + ".sort", "0"); request.setParameter(table.getId() + ".sortDesc", "true"); table.handleRequest(request); rowIndices = table.getRepeater().getBeanList();
@Test public void testSortTable() { SimpleTableDataModel model = new SimpleTableDataModel(new String[][]{{"1"}, {"3"}, {"2"}}); model.setComparator(0, SimpleTableDataModel.COMPARABLE_COMPARATOR); WDataTable table = new WDataTable(); table.setSelectMode(WDataTable.SelectMode.SINGLE); table.setDataModel(model); table.addColumn(new WTableColumn("dummy", WText.class)); table.setLocked(true); setActiveContext(createUIContext()); // Sort table manually table.sort(0, true); Assert.assertTrue("Incorrect selection after sort method", table.isSorted()); Assert. assertEquals("Incorrect sort column after sort method", 0, table. getSortColumnIndex()); Assert.assertTrue("Incorrect sort direction after sort method", table.isSortAscending()); List<?> rowIndices = table.getRepeater().getBeanList(); Assert.assertEquals("Incorrect sort", Arrays.asList(new Integer[]{0, 2, 1}), rowIndices); }
@Test public void testDoPaintMissingAttributes() throws IOException, SAXException, XpathException { WDataTable component = new WDataTable(); component.addColumn(new WTableColumn(COL1_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL2_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL3_HEADING_TEST, WTextField.class)); component.setDataModel(createTableModel()); component.setVisible(true); component.setStripingType(WDataTable.StripingType.NONE); component.setSeparatorType(WDataTable.SeparatorType.NONE); assertXpathNotExists("//ui:table/@caption", component); assertXpathEvaluatesTo("table", "//ui:table/@type", component); assertXpathNotExists("//ui:table/@striping", component); assertXpathNotExists("//ui:table/@separators", component); }
XmlStringBuilder xml = renderContext.getWriter(); WDataTable table = renderer.getTable(); TableDataModel dataModel = table.getDataModel(); UIContext uic = UIContextHolder.getCurrent(); final int numCols = table.getColumnCount(); int[] columnOrder = table.getColumnOrder(); int rowIndex = getRowIndex(table, (SubUIContext) uic); boolean unselectable = table.getSelectMode() != SelectMode.NONE && !dataModel.isSelectable(rowIndex); xml.appendAttribute("rowIndex", rowIndex); xml.appendOptionalAttribute("unselectable", unselectable, "true"); xml.appendOptionalAttribute("selected", table.getSelectedRows().contains(rowIndex), "true"); xml.appendOptionalAttribute("filterValues", getFilterValues(dataModel, rowIndex)); if (table.getExpandMode() != WDataTable.ExpandMode.NONE && dataModel instanceof TreeTableDataModel) { TableTreeNode node = ((TreeTableDataModel) dataModel).getNodeAtLine(rowIndex); boolean expandable = !node.isLeaf() && !node.isExpanded(); if (table.isShowRowHeaders()) { xml.appendTag("ui:th"); renderer.getRowHeader().paint(renderContext); WTableColumn col = table.getColumn(colIndex); if (table.getExpandMode() != WDataTable.ExpandMode.NONE && dataModel instanceof TreeTableDataModel) { TreeTableDataModel treeModel = (TreeTableDataModel) dataModel; TableTreeNode node = treeModel.getNodeAtLine(rowIndex);
@Test public void testXssEscaping() throws IOException, SAXException, XpathException { WDataTable table = new WDataTable(); table.addColumn(new WTableColumn(getMaliciousContent(), WText.class)); table.addColumn(new WTableColumn(getMaliciousContent(), WText.class)); table.addColumn(new WTableColumn(getMaliciousContent(), WText.class)); table.setNoDataMessage(getMaliciousAttribute("ui:table")); UIContext uic = createUIContext(); assertSafeContent(table); WButton button = new WButton("dummy"); table.addAction(button); table.addActionConstraint(button, new ActionConstraint(0, 1, false, getMaliciousAttribute( "ui:action"))); assertSafeContent(table); TableDataModel tableModel = createTableModel(); table.setDataModel(tableModel); uic.clearScratchMap(); // clear out cached data from previous renders assertSafeContent(table); table.setCaption(getMaliciousAttribute("ui:table")); assertSafeContent(table); table.setSummary(getMaliciousAttribute("ui:table")); assertSafeContent(table); table.setSelectGroup(getMaliciousAttribute("ui:rowselection")); assertSafeContent(table); table.setActiveFilters(Arrays.asList(new String[]{getMaliciousAttribute("ui:table")})); }
/** * Retrieves the starting row index for the current page. Will always return zero for tables which are not * paginated. * * @return the starting row index for the current page. */ private int getCurrentPageStartRow() { int startRow = 0; if (getPaginationMode() != PaginationMode.NONE) { int rowsPerPage = getRowsPerPage(); TableDataModel model = getDataModel(); if (model instanceof TreeTableDataModel) { // For tree tables, pagination only occurs on first-level nodes (ie. those // underneath the root node), however they might not be consecutively // numbered. Therefore, the start and end row indices need to be adjusted. TreeTableDataModel treeModel = (TreeTableDataModel) model; TreeNode root = treeModel.getNodeAtLine(0).getRoot(); int startNode = getCurrentPage() * rowsPerPage; startRow = ((TableTreeNode) root.getChildAt(startNode)).getRowIndex() - 1; // -1 as the root is not included in the table } else { startRow = getCurrentPage() * rowsPerPage; } } return startRow; }
/** * @return a hierarchic table */ private WDataTable createHierarchicDataTable() { WDataTable table = new WDataTable(); table.setType(WDataTable.Type.HIERARCHIC); table.addColumn(new WTableColumn("Column1", WText.class)); table.addColumn(new WTableColumn("Column2", WText.class)); table.addColumn(new WTableColumn("Column3", WText.class)); table.setRowsPerPage(DEFAULT_ROWS_PER_PAGE); table.setSummary("Hierarchic table summary"); table.setCaption("Hierarchic table caption"); TableTreeNode root = createHierarchicTree(); table.setDataModel(new ExampleTreeTableModel(root)); return table; }
@Test public void testDoPaintSelectModeSingle() throws IOException, SAXException, XpathException { WDataTable component = new WDataTable(); component.addColumn(new WTableColumn(COL1_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL2_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL3_HEADING_TEST, WTextField.class)); TableDataModel tableModel = createTableModel(); component.setDataModel(tableModel); component.setVisible(true); component.setSelectMode(WDataTable.SelectMode.SINGLE); assertXpathExists("//ui:table/ui:rowselection", component); }
@Test public void testDoPaintTableActions() throws IOException, SAXException, XpathException { WDataTable component = new WDataTable(); component.addColumn(new WTableColumn(COL1_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL2_HEADING_TEST, WTextField.class)); component.addColumn(new WTableColumn(COL3_HEADING_TEST, WTextField.class)); TableDataModel tableModel = createTableModel(); component.setDataModel(tableModel); component.setVisible(true); component.addAction(new WButton(TEST_ACTION_ONE)); component.addAction(new WButton(TEST_ACTION_TWO)); assertXpathExists("//ui:table/ui:actions", component); assertXpathEvaluatesTo(TEST_ACTION_ONE, "//ui:table/ui:actions/ui:action[1]/html:button", component); assertXpathEvaluatesTo(TEST_ACTION_TWO, "//ui:table/ui:actions/ui:action[2]/html:button", component); }
@Test public void testSingleHandleSelectionRequest() { WDataTable table = new WDataTable(); table.setSelectMode(WDataTable.SelectMode.SINGLE); table.setDataModel(new SimpleTableDataModel(new String[100][1])); table.setLocked(true); setActiveContext(createUIContext()); MockRequest request = new MockRequest(); request.setParameter(table.getId() + "-h", "x"); request.setParameter(table.getId() + ".selected", new String[]{"5", "6", "7"}); table.handleRequest(request); Assert.assertEquals("Should only have selected the first item after handleRequest", Arrays. asList(new Integer[]{5}), table.getSelectedRows()); resetContext(); Assert.assertTrue("Incorrect default selection after handleRequest", table.getSelectedRows().isEmpty()); }
WNamingContext context = new WNamingContext("TEST"); WDataTable table = new WDataTable(); table.setDataModel(new SimpleTableDataModel(new String[][]{{"1"}, {"3"}, {"2"}})); WComponent repeated = new WBeanComponent(); table.addColumn(new WTableColumn("dummy", repeated)); Assert.assertEquals("Incorrect default id for table", prefix + "0", table.getId()); String tableId = table.getId(); getRepeater().getId()); table.getRepeater() .getRepeatRoot().getId()); String rowPrefix = table.getRepeater().getRepeatRoot().getId(); for (UIContext uic : table.getRepeater().getRowContexts()) {
String[] paramValue = request.getParameterValues(getId() + ".expanded"); String[] expandedRows = removeEmptyStrings(paramValue); List<Integer> oldExpansions = getExpandedRows(); List<Integer> expansions; TableDataModel model = getDataModel(); setExpandedRows(new ArrayList<Integer>()); return; } else if (getPaginationMode() == PaginationMode.NONE || getPaginationMode() == PaginationMode.CLIENT || oldExpansions == null) { expansions = new ArrayList<>(expandedRows.length); int startRow = getCurrentPageStartRow(); int endRow = getCurrentPageEndRow(); expansions.removeAll(getRowIds(startRow, endRow)); setExpandedRows(expansions);
xml.appendAttribute("id", component.getId()); xml.appendOptionalAttribute("track", component.isTracking(), "true"); xml.appendOptionalAttribute("hidden", table.isHidden(), "true"); xml.appendOptionalAttribute("caption", table.getCaption()); switch (table.getType()) { case TABLE: xml.appendAttribute("type", "table"); break; default: throw new SystemException("Unknown table type: " + table.getType()); switch (table.getStripingType()) { case ROWS: xml.appendAttribute("striping", "rows"); break; default: throw new SystemException("Unknown striping type: " + table.getStripingType()); switch (table.getSeparatorType()) { case HORIZONTAL: xml.appendAttribute("separators", "horizontal"); break; default: throw new SystemException("Unknown separator type: " + table.getSeparatorType());
/** * Paints the column headings for the given table. * * @param table the table to paint the headings for. * @param renderContext the RenderContext to paint to. */ private void paintColumnHeadings(final WDataTable table, final WebXmlRenderContext renderContext) { XmlStringBuilder xml = renderContext.getWriter(); int[] columnOrder = table.getColumnOrder(); TableDataModel model = table.getDataModel(); final int columnCount = table.getColumnCount(); xml.appendTagOpen("ui:thead"); xml.appendOptionalAttribute("hidden", !table.isShowColumnHeaders(), "true"); xml.appendClose(); if (table.isShowRowHeaders()) { paintColumnHeading(table.getRowHeaderColumn(), false, renderContext); } for (int i = 0; i < columnCount; i++) { int colIndex = columnOrder == null ? i : columnOrder[i]; WTableColumn col = table.getColumn(colIndex); if (col.isVisible()) { boolean sortable = model.isSortable(colIndex); paintColumnHeading(col, sortable, renderContext); } } xml.appendEndTag("ui:thead"); }