From 2984fbe70475685209d76061d1c8b9bdcf3d9a04 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 15 Dec 2016 11:50:04 +0200 Subject: [PATCH] (Re)introduce server side sort for Grid. Fixes vaadin/framework8-issues#557 --- server/src/main/java/com/vaadin/ui/Grid.java | 178 ++++++++++++------ .../tests/server/component/grid/GridTest.java | 54 ++++++ .../components/grid/basics/GridBasics.java | 6 + .../grid/basics/GridSortingTest.java | 76 ++++++++ 4 files changed, 259 insertions(+), 55 deletions(-) diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 6136b54f42..120640bd53 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -15,7 +15,6 @@ */ package com.vaadin.ui; - import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -79,6 +78,7 @@ import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.SectionState; import com.vaadin.shared.util.SharedUtil; +import com.vaadin.ui.Grid.FooterRow; import com.vaadin.ui.components.grid.AbstractSelectionModel; import com.vaadin.ui.components.grid.EditorComponentGenerator; import com.vaadin.ui.components.grid.EditorImpl; @@ -334,6 +334,31 @@ public class Grid extends AbstractListing void columnResize(ColumnResizeEvent event); } + /** + * Generates the sort orders when rows are sorted by a column. + * + * @see Column#setSortOrderProvider + * + * @since 8.0 + * @author Vaadin Ltd + */ + @FunctionalInterface + public interface SortOrderProvider extends + SerializableFunction>> { + + /** + * Generates the sort orders when rows are sorted by a column. + * + * @param sortDirection + * desired sort direction + * + * @return sort information + */ + @Override + public Stream> apply(SortDirection sortDirection); + + } + /** * An event that is fired when the columns are reordered. */ @@ -738,44 +763,14 @@ public class Grid extends AbstractListing public void sort(String[] columnIds, SortDirection[] directions, boolean isUserOriginated) { assert columnIds.length == directions.length : "Column and sort direction counts don't match."; - sortOrder.clear(); - if (columnIds.length == 0) { - // Grid is not sorted anymore. - getDataCommunicator() - .setBackEndSorting(Collections.emptyList()); - getDataCommunicator().setInMemorySorting(null); - return; - } + List>> list = new ArrayList<>( + directions.length); for (int i = 0; i < columnIds.length; ++i) { Column column = columnKeys.get(columnIds[i]); - sortOrder.add(new SortOrder<>(column, directions[i])); - } - - // Set sort orders - // In-memory comparator - BinaryOperator> operator = (comparator1, - comparator2) -> SerializableComparator.asInstance( - (Comparator & Serializable) comparator1 - .thenComparing(comparator2)); - SerializableComparator comparator = sortOrder.stream() - .map(order -> order.getSorted() - .getComparator(order.getDirection())) - .reduce((x, y) -> 0, operator); - getDataCommunicator().setInMemorySorting(comparator); - - // Back-end sort properties - List> sortProperties = new ArrayList<>(); - sortOrder.stream() - .map(order -> order.getSorted() - .getSortOrder(order.getDirection())) - .forEach(s -> s.forEach(sortProperties::add)); - getDataCommunicator().setBackEndSorting(sortProperties); - - // Close grid editor if it's open. - if (getEditor().isOpen()) { - getEditor().cancel(); + list.add(new SortOrder<>(column, directions[i])); } + setSortOrder(list, isUserOriginated); } @Override @@ -2499,8 +2494,7 @@ public class Grid extends AbstractListing * * @return the new column */ - public Column addColumn( - ValueProvider valueProvider) { + public Column addColumn(ValueProvider valueProvider) { return addColumn(getGeneratedIdentifier(), t -> String.valueOf(valueProvider.apply(t)), new TextRenderer()); @@ -3406,6 +3400,61 @@ public class Grid extends AbstractListing return getSelectionModel().addSelectionListener(listener); } + /** + * Sort this Grid in ascending order by a specified column. + * + * @param column + * a column to sort against + * + */ + public void sort(Column column) { + sort(column, SortDirection.ASCENDING); + } + + /** + * Sort this Grid in user-specified {@link SortOrder} by a column. + * + * @param column + * a column to sort against + * @param direction + * a sort order value (ascending/descending) + * + */ + public void sort(Column column, SortDirection direction) { + setSortOrder( + Collections.singletonList(new SortOrder<>(column, direction))); + } + + /** + * Clear the current sort order, and re-sort the grid. + */ + public void clearSortOrder() { + sortOrder.clear(); + sort(false); + } + + /** + * Sets the sort order to use. + * + * @param order + * a sort order list. + * + * @throws IllegalArgumentException + * if order is null + */ + public void setSortOrder(List>> order) { + setSortOrder(order, false); + } + + /** + * Get the current sort order list. + * + * @return a sort order list + */ + public List>> getSortOrder() { + return Collections.unmodifiableList(sortOrder); + } + @Override protected GridState getState() { return getState(true); @@ -3685,25 +3734,44 @@ public class Grid extends AbstractListing return result; } - /** - * Generates the sort orders when rows are sorted by a column. - * @see Column#setSortOrderProvider - * - * @since 8.0 - * @author Vaadin Ltd - */ - @FunctionalInterface - public interface SortOrderProvider extends SerializableFunction>> { + private void setSortOrder(List>> order, + boolean userOriginated) { + Objects.requireNonNull(order, "Sort order list cannot be null"); + sortOrder.clear(); + if (order.isEmpty()) { + // Grid is not sorted anymore. + getDataCommunicator().setBackEndSorting(Collections.emptyList()); + getDataCommunicator().setInMemorySorting(null); + return; + } - /** - * Generates the sort orders when rows are sorted by a column. - * - * @param sortDirection desired sort direction - * - * @return sort information - */ - @Override - public Stream> apply(SortDirection sortDirection); + sortOrder.addAll(order); + sort(userOriginated); + } + + private void sort(boolean userOriginated) { + // Set sort orders + // In-memory comparator + BinaryOperator> operator = (comparator1, + comparator2) -> SerializableComparator + .asInstance((Comparator & Serializable) comparator1 + .thenComparing(comparator2)); + SerializableComparator comparator = sortOrder.stream().map( + order -> order.getSorted().getComparator(order.getDirection())) + .reduce((x, y) -> 0, operator); + getDataCommunicator().setInMemorySorting(comparator); + + // Back-end sort properties + List> sortProperties = new ArrayList<>(); + sortOrder.stream().map( + order -> order.getSorted().getSortOrder(order.getDirection())) + .forEach(s -> s.forEach(sortProperties::add)); + getDataCommunicator().setBackEndSorting(sortProperties); + // Close grid editor if it's open. + if (getEditor().isOpen()) { + getEditor().cancel(); + } } + } diff --git a/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java b/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java index 56e8ad29f3..6955a99e91 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java @@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import org.easymock.Capture; @@ -13,8 +15,11 @@ import org.junit.Test; import com.vaadin.data.ValueProvider; import com.vaadin.event.selection.SelectionEvent; +import com.vaadin.server.data.SortOrder; +import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.Column; import com.vaadin.ui.Grid.SelectionMode; import com.vaadin.ui.renderers.NumberRenderer; @@ -177,4 +182,53 @@ public class GridTest { grid.addSelectionListener( event -> Assert.fail("never ever happens (tm)")); } + + @Test + public void sortByColumn_sortOrderIsAscendingOneColumn() { + Column column = grid.getColumns().get(1); + grid.sort(column); + + SortOrder> sortOrder = grid.getSortOrder().get(0); + Assert.assertEquals(column, sortOrder.getSorted()); + Assert.assertEquals(SortDirection.ASCENDING, sortOrder.getDirection()); + } + + @Test + public void sortByColumnDesc_sortOrderIsDescendingOneColumn() { + Column column = grid.getColumns().get(1); + grid.sort(column, SortDirection.DESCENDING); + + SortOrder> sortOrder = grid.getSortOrder().get(0); + Assert.assertEquals(column, sortOrder.getSorted()); + Assert.assertEquals(SortDirection.DESCENDING, sortOrder.getDirection()); + } + + @Test + public void setSortOrder() { + Column column1 = grid.getColumns().get(1); + Column column2 = grid.getColumns().get(2); + List>> order = Arrays.asList( + new SortOrder<>(column2, SortDirection.DESCENDING), + new SortOrder<>(column1, SortDirection.ASCENDING)); + grid.setSortOrder(order); + + List>> sortOrder = grid.getSortOrder(); + Assert.assertEquals(column2, sortOrder.get(0).getSorted()); + Assert.assertEquals(SortDirection.DESCENDING, + sortOrder.get(0).getDirection()); + + Assert.assertEquals(column1, sortOrder.get(1).getSorted()); + Assert.assertEquals(SortDirection.ASCENDING, + sortOrder.get(1).getDirection()); + } + + @Test + public void clearSortOrder() { + Column column = grid.getColumns().get(1); + grid.sort(column); + + grid.clearSortOrder(); + + assertEquals(0, grid.getSortOrder().size()); + } } diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index ed82395c88..c074bd4d14 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -21,6 +21,7 @@ import com.vaadin.event.selection.MultiSelectionEvent; import com.vaadin.event.selection.SingleSelectionEvent; import com.vaadin.server.VaadinRequest; import com.vaadin.shared.Registration; +import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Button; @@ -338,7 +339,12 @@ public class GridBasics extends AbstractTestUIWithLog { .setCheckable(true); columnMenu.addItem("Remove", selectedItem -> grid.removeColumn(col)); + + columnMenu.addItem("Sort ASC", item -> grid.sort(col)); + columnMenu.addItem("Sort DESC", + item -> grid.sort(col, SortDirection.DESCENDING)); } + columnsMenu.addItem("Clear sort", item -> grid.clearSortOrder()); } private void createSizeMenu(MenuItem sizeMenu) { diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridSortingTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridSortingTest.java index 9b97f8def4..c172f53f3b 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridSortingTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridSortingTest.java @@ -2,6 +2,7 @@ package com.vaadin.tests.components.grid.basics; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -57,4 +58,79 @@ public class GridSortingTest extends GridBasicsTest { getGridElement().getCell(i++, 3).getText()); } } + + @Test + public void serverSideOrderByColumn0() { + selectMenuPath("Component", "Columns", "Column 0", "Sort ASC"); + + Comparator comparator = Comparator.naturalOrder(); + + int i = 0; + for (String coord : getTestData().map(DataObject::getCoordinates) + .sorted(comparator).limit(5).collect(Collectors.toList())) { + Assert.assertEquals( + "Grid was not sorted as expected, row number mismatch", + coord, getGridElement().getCell(i++, 0).getText()); + } + // self-verification + Assert.assertTrue(i > 0); + + selectMenuPath("Component", "Columns", "Column 0", "Sort DESC"); + + i = 0; + for (String coord : getTestData().map(DataObject::getCoordinates) + .sorted(comparator.reversed()).limit(5) + .collect(Collectors.toList())) { + Assert.assertEquals( + "Grid was not sorted as expected, row number mismatch", + coord, getGridElement().getCell(i++, 0).getText()); + } + } + + @Test + public void serverSideOrderByDate() { + selectMenuPath("Component", "Columns", "Date", "Sort ASC"); + + Comparator comparator = Comparator.naturalOrder(); + + int i = 0; + for (Date date : getTestData().map(DataObject::getDate) + .sorted(comparator).limit(5).collect(Collectors.toList())) { + Assert.assertEquals( + "Grid was not sorted as expected, row number mismatch", + date.toString(), + getGridElement().getCell(i++, 4).getText()); + } + // self-verification + Assert.assertTrue(i > 0); + + selectMenuPath("Component", "Columns", "Date", "Sort DESC"); + + i = 0; + for (Date date : getTestData().map(DataObject::getDate) + .sorted(comparator.reversed()).limit(5) + .collect(Collectors.toList())) { + Assert.assertEquals( + "Grid was not sorted as expected, row number mismatch", + date.toString(), + getGridElement().getCell(i++, 4).getText()); + } + } + + @Test + public void serverSideClearOrder() { + selectMenuPath("Component", "Columns", "Column 0", "Sort ASC"); + selectMenuPath("Component", "Columns", "Clear sort"); + + int i = 0; + for (String coord : getTestData().map(DataObject::getCoordinates) + .limit(5).collect(Collectors.toList())) { + Assert.assertEquals( + "Grid was not sorted as expected, row number mismatch", + coord, getGridElement().getCell(i++, 0).getText()); + } + // self-verification + Assert.assertTrue(i > 0); + } + } -- 2.39.5