Skip to content

Commit

Permalink
(Re)introduce server side sort for Grid.
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis authored and Ilia Motornyi committed Dec 15, 2016
1 parent 56c44b9 commit 2984fbe
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 55 deletions.
178 changes: 123 additions & 55 deletions server/src/main/java/com/vaadin/ui/Grid.java
Expand Up @@ -15,7 +15,6 @@
*/
package com.vaadin.ui;


import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -79,6 +78,7 @@
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;
Expand Down Expand Up @@ -334,6 +334,31 @@ public interface ColumnResizeListener extends Serializable {
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<SortDirection, Stream<SortOrder<String>>> {

/**
* Generates the sort orders when rows are sorted by a column.
*
* @param sortDirection
* desired sort direction
*
* @return sort information
*/
@Override
public Stream<SortOrder<String>> apply(SortDirection sortDirection);

}

/**
* An event that is fired when the columns are reordered.
*/
Expand Down Expand Up @@ -738,44 +763,14 @@ private final class GridServerRpcImpl implements GridServerRpc {
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<SortOrder<Column<T, ?>>> list = new ArrayList<>(
directions.length);
for (int i = 0; i < columnIds.length; ++i) {
Column<T, ?> column = columnKeys.get(columnIds[i]);
sortOrder.add(new SortOrder<>(column, directions[i]));
}

// Set sort orders
// In-memory comparator
BinaryOperator<SerializableComparator<T>> operator = (comparator1,
comparator2) -> SerializableComparator.asInstance(
(Comparator<T> & Serializable) comparator1
.thenComparing(comparator2));
SerializableComparator<T> comparator = sortOrder.stream()
.map(order -> order.getSorted()
.getComparator(order.getDirection()))
.reduce((x, y) -> 0, operator);
getDataCommunicator().setInMemorySorting(comparator);

// Back-end sort properties
List<SortOrder<String>> 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
Expand Down Expand Up @@ -2499,8 +2494,7 @@ public Column<T, String> addColumn(String identifier,
*
* @return the new column
*/
public Column<T, String> addColumn(
ValueProvider<T, String> valueProvider) {
public Column<T, String> addColumn(ValueProvider<T, String> valueProvider) {
return addColumn(getGeneratedIdentifier(),
t -> String.valueOf(valueProvider.apply(t)),
new TextRenderer());
Expand Down Expand Up @@ -3406,6 +3400,61 @@ public Registration addSelectionListener(SelectionListener<T> listener)
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<T, ?> 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<T, ?> 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<SortOrder<Column<T, ?>>> order) {
setSortOrder(order, false);
}

/**
* Get the current sort order list.
*
* @return a sort order list
*/
public List<SortOrder<Column<T, ?>>> getSortOrder() {
return Collections.unmodifiableList(sortOrder);
}

@Override
protected GridState getState() {
return getState(true);
Expand Down Expand Up @@ -3685,25 +3734,44 @@ protected Collection<String> getCustomAttributes() {
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<SortDirection, Stream<SortOrder<String>>> {
private void setSortOrder(List<SortOrder<Column<T, ?>>> 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<SortOrder<String>> apply(SortDirection sortDirection);
sortOrder.addAll(order);
sort(userOriginated);
}

private void sort(boolean userOriginated) {
// Set sort orders
// In-memory comparator
BinaryOperator<SerializableComparator<T>> operator = (comparator1,
comparator2) -> SerializableComparator
.asInstance((Comparator<T> & Serializable) comparator1
.thenComparing(comparator2));
SerializableComparator<T> comparator = sortOrder.stream().map(
order -> order.getSorted().getComparator(order.getDirection()))
.reduce((x, y) -> 0, operator);
getDataCommunicator().setInMemorySorting(comparator);

// Back-end sort properties
List<SortOrder<String>> 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();
}
}

}
Expand Up @@ -4,6 +4,8 @@
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;
Expand All @@ -13,8 +15,11 @@

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;

Expand Down Expand Up @@ -177,4 +182,53 @@ public void testAddSelectionListener_noSelectionMode() {
grid.addSelectionListener(
event -> Assert.fail("never ever happens (tm)"));
}

@Test
public void sortByColumn_sortOrderIsAscendingOneColumn() {
Column<String, ?> column = grid.getColumns().get(1);
grid.sort(column);

SortOrder<Column<String, ?>> sortOrder = grid.getSortOrder().get(0);
Assert.assertEquals(column, sortOrder.getSorted());
Assert.assertEquals(SortDirection.ASCENDING, sortOrder.getDirection());
}

@Test
public void sortByColumnDesc_sortOrderIsDescendingOneColumn() {
Column<String, ?> column = grid.getColumns().get(1);
grid.sort(column, SortDirection.DESCENDING);

SortOrder<Column<String, ?>> sortOrder = grid.getSortOrder().get(0);
Assert.assertEquals(column, sortOrder.getSorted());
Assert.assertEquals(SortDirection.DESCENDING, sortOrder.getDirection());
}

@Test
public void setSortOrder() {
Column<String, ?> column1 = grid.getColumns().get(1);
Column<String, ?> column2 = grid.getColumns().get(2);
List<SortOrder<Column<String, ?>>> order = Arrays.asList(
new SortOrder<>(column2, SortDirection.DESCENDING),
new SortOrder<>(column1, SortDirection.ASCENDING));
grid.setSortOrder(order);

List<SortOrder<Column<String, ?>>> 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<String, ?> column = grid.getColumns().get(1);
grid.sort(column);

grid.clearSortOrder();

assertEquals(0, grid.getSortOrder().size());
}
}
Expand Up @@ -21,6 +21,7 @@
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;
Expand Down Expand Up @@ -338,7 +339,12 @@ private void createColumnsMenu(MenuItem columnsMenu) {
.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) {
Expand Down

0 comments on commit 2984fbe

Please sign in to comment.