Change-Id: I59767f8e197d3802110df4ad6da7581f101b6835feature/vaadin8-book-vol2
@@ -16,6 +16,7 @@ | |||
package com.vaadin.tokka.server.communication.data; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
@@ -178,7 +179,9 @@ public class DataCommunicator<T> extends AbstractExtension { | |||
private boolean reset = false; | |||
private final Set<T> updatedData = new HashSet<T>(); | |||
private Range pushRows = Range.withLength(0, 40); | |||
private Comparator<T> inMemorySorting; | |||
private List<SortOrder<String>> backEndSorting = new ArrayList<>(); | |||
public DataCommunicator() { | |||
addDataGenerator(handler); | |||
@@ -200,13 +203,12 @@ public class DataCommunicator<T> extends AbstractExtension { | |||
} | |||
// FIXME: Sorting and Filtering with Backend | |||
List<Object> sortOrders = Collections.emptyList(); | |||
Set<Object> filters = Collections.emptySet(); | |||
if (initial || reset) { | |||
// FIXME: Rethink the size question. | |||
int dataSourceSize = (int) getDataSource().apply( | |||
new Query(0, Integer.MAX_VALUE, sortOrders, filters)) | |||
new Query(0, Integer.MAX_VALUE, backEndSorting, filters)) | |||
.count(); | |||
rpc.reset(dataSourceSize); | |||
} | |||
@@ -226,10 +228,9 @@ public class DataCommunicator<T> extends AbstractExtension { | |||
} | |||
rowsToPush = rowsToPush.skip(offset).limit(limit); | |||
} else { | |||
Query query = new Query(offset, limit, sortOrders, filters); | |||
Query query = new Query(offset, limit, backEndSorting, filters); | |||
rowsToPush = getDataSource().apply(query); | |||
} | |||
pushData(offset, rowsToPush); | |||
} | |||
@@ -392,6 +393,12 @@ public class DataCommunicator<T> extends AbstractExtension { | |||
reset(); | |||
} | |||
public void setBackEndSorting(List<SortOrder<String>> sortOrder) { | |||
backEndSorting.clear(); | |||
backEndSorting.addAll(sortOrder); | |||
reset(); | |||
} | |||
/** | |||
* Creates a {@link DataKeyMapper} to use with this DataCommunicator. | |||
* <p> |
@@ -30,7 +30,7 @@ public class Query implements Serializable { | |||
private final int offset; | |||
private final int limit; | |||
private final List<Object> sortOrders; | |||
private final List<SortOrder<String>> sortOrders; | |||
private final Set<Object> filters; | |||
/** | |||
@@ -57,7 +57,7 @@ public class Query implements Serializable { | |||
* @param filters | |||
* filtering for fetching | |||
*/ | |||
public Query(int offset, int limit, List<Object> sortOrders, | |||
public Query(int offset, int limit, List<SortOrder<String>> sortOrders, | |||
Set<Object> filters) { | |||
this.offset = offset; | |||
this.limit = limit; | |||
@@ -91,7 +91,7 @@ public class Query implements Serializable { | |||
* | |||
* @return list of sort orders | |||
*/ | |||
public List<Object> getSortOrders() { | |||
public List<SortOrder<String>> getSortOrders() { | |||
return sortOrders; | |||
} | |||
@@ -0,0 +1,39 @@ | |||
/* | |||
* Copyright 2000-2014 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.tokka.server.communication.data; | |||
import java.io.Serializable; | |||
import com.vaadin.shared.data.sort.SortDirection; | |||
public class SortOrder<T> implements Serializable { | |||
private T sorted; | |||
private SortDirection direction; | |||
public SortOrder(T sorted, SortDirection direction) { | |||
this.sorted = sorted; | |||
this.direction = direction; | |||
} | |||
public T getSorted() { | |||
return sorted; | |||
} | |||
public SortDirection getDirection() { | |||
return direction; | |||
} | |||
} |
@@ -15,13 +15,18 @@ | |||
*/ | |||
package com.vaadin.tokka.ui.components.grid; | |||
import java.util.Arrays; | |||
import java.util.Comparator; | |||
import java.util.List; | |||
import java.util.function.Function; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import com.vaadin.server.AbstractExtension; | |||
import com.vaadin.shared.data.sort.SortDirection; | |||
import com.vaadin.shared.tokka.data.DataProviderConstants; | |||
import com.vaadin.shared.tokka.ui.components.grid.ColumnState; | |||
import com.vaadin.tokka.server.communication.data.SortOrder; | |||
import com.vaadin.tokka.server.communication.data.TypedDataGenerator; | |||
import elemental.json.Json; | |||
@@ -31,6 +36,7 @@ public class Column<T, V> extends AbstractExtension implements | |||
TypedDataGenerator<T> { | |||
private Function<T, V> getter; | |||
private Function<SortDirection, Stream<SortOrder<String>>> sortOrderProvider; | |||
Column(String caption, Function<T, V> getter) { | |||
this.getter = getter; | |||
@@ -109,4 +115,20 @@ public class Column<T, V> extends AbstractExtension implements | |||
}; | |||
return sortDirection == SortDirection.ASCENDING ? c : c.reversed(); | |||
} | |||
public Column<T, V> setSortProperty(String... properties) { | |||
sortOrderProvider = dir -> Arrays.asList(properties).stream() | |||
.map(s -> new SortOrder<>(s, dir)); | |||
return this; | |||
} | |||
public Column<T, V> setSortBuilder( | |||
Function<SortDirection, Stream<SortOrder<String>>> provider) { | |||
sortOrderProvider = provider; | |||
return this; | |||
} | |||
public List<SortOrder<String>> getSortOrder(SortDirection direction) { | |||
return sortOrderProvider.apply(direction).collect(Collectors.toList()); | |||
} | |||
} |
@@ -15,24 +15,27 @@ | |||
*/ | |||
package com.vaadin.tokka.ui.components.grid; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.HashSet; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import com.vaadin.shared.data.sort.SortDirection; | |||
import com.vaadin.shared.tokka.ui.components.grid.GridServerRpc; | |||
import com.vaadin.tokka.server.communication.data.DataSource; | |||
import com.vaadin.tokka.server.communication.data.KeyMapper; | |||
import com.vaadin.tokka.server.communication.data.SingleSelection; | |||
import com.vaadin.tokka.server.communication.data.SortOrder; | |||
import com.vaadin.tokka.ui.components.AbstractListing; | |||
public class Grid<T> extends AbstractListing<T> { | |||
private KeyMapper<Column<T, ?>> columnKeys = new KeyMapper<>(); | |||
private Set<Column<T, ?>> columnSet = new HashSet<>(); | |||
private List<SortOrder<Column<T, ?>>> sortOrder = new ArrayList<>(); | |||
public Grid() { | |||
setSelectionModel(new SingleSelection<T>()); | |||
@@ -40,34 +43,23 @@ public class Grid<T> extends AbstractListing<T> { | |||
@Override | |||
public void setSortOrder(List<String> columnIds, | |||
List<SortDirection> sortDirections) { | |||
assert columnIds.size() == sortDirections.size() : "Column and sort direction counts don't match."; | |||
List<SortDirection> directions) { | |||
assert columnIds.size() == directions.size() : "Column and sort direction counts don't match."; | |||
sortOrder.clear(); | |||
if (columnIds.size() == 0) { | |||
// Somehow there's suddenly no sort order anymore.. | |||
getDataCommunicator().setBackEndSorting( | |||
Collections.emptyList()); | |||
getDataCommunicator().setInMemorySorting(null); | |||
return; | |||
} | |||
if (getDataCommunicator().getDataSource().isInMemory()) { | |||
Comparator<T> c = columnKeys.get(columnIds.get(0)) | |||
.getComparator(sortDirections.get(0)); | |||
for (int i = 1; i < columnIds.size(); ++i) { | |||
c = c.thenComparing(columnKeys.get(columnIds.get(i)) | |||
.getComparator(sortDirections.get(i))); | |||
} | |||
getDataCommunicator().setInMemorySorting(c); | |||
} else { | |||
Map<Column<T, ?>, SortDirection> sortOrder = new LinkedHashMap<>(); | |||
for (int i = 0; i < columnIds.size(); ++i) { | |||
sortOrder.put(columnKeys.get(columnIds.get(i)), | |||
sortDirections.get(i)); | |||
} | |||
// FIXME: Handle the sortOrder map so DataSource can | |||
// understand | |||
sortOrder.forEach((col, dir) -> System.err | |||
.println("Sorting column: " + col.getCaption() | |||
+ " to " + dir)); | |||
for (int i = 0; i < columnIds.size(); ++i) { | |||
Column<T, ?> column = columnKeys.get(columnIds.get(i)); | |||
sortOrder.add(new SortOrder<>(column, directions.get(i))); | |||
} | |||
updateSortOrder(); | |||
} | |||
}); | |||
} | |||
@@ -90,4 +82,33 @@ public class Grid<T> extends AbstractListing<T> { | |||
column.remove(); | |||
} | |||
} | |||
@Override | |||
public void setDataSource(DataSource<T, ?> data) { | |||
super.setDataSource(data); | |||
updateSortOrder(); | |||
} | |||
protected void updateSortOrder() { | |||
if (getDataCommunicator().getDataSource() == null) { | |||
return; | |||
} | |||
if (getDataCommunicator().getDataSource().isInMemory()) { | |||
Comparator<T> comparator = sortOrder | |||
.stream() | |||
.map(order -> order.getSorted().getComparator( | |||
order.getDirection())) | |||
.reduce((x, y) -> 0, Comparator::thenComparing); | |||
getDataCommunicator().setInMemorySorting(comparator); | |||
} else { | |||
List<SortOrder<String>> sortProperties = new ArrayList<>(); | |||
sortOrder | |||
.stream() | |||
.map(order -> order.getSorted().getSortOrder( | |||
order.getDirection())) | |||
.forEach(sortProperties::addAll); | |||
getDataCommunicator().setBackEndSorting(sortProperties); | |||
} | |||
} | |||
} |
@@ -1,23 +1,88 @@ | |||
package com.vaadin.tokka.tests.components; | |||
import java.util.Arrays; | |||
import java.util.Comparator; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.stream.Stream; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.shared.data.sort.SortDirection; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.tokka.server.communication.data.DataSource; | |||
import com.vaadin.tokka.server.communication.data.InMemoryDataSource; | |||
import com.vaadin.tokka.ui.components.grid.Grid; | |||
import com.vaadin.ui.Button; | |||
public class GridSortable extends AbstractTestUI { | |||
private static class CustomDataSource extends InMemoryDataSource<Bean> { | |||
private static List<Bean> list = Arrays.asList(new Bean("Foo", 100), | |||
new Bean("Bar", 200), new Bean("Bar", 100)); | |||
private static Map<String, Comparator<Bean>> comparators = new HashMap<>(); | |||
static { | |||
comparators.put("value", Comparator.comparing(Bean::getValue)); | |||
comparators.put("intVal", Comparator.comparing(Bean::getIntVal)); | |||
} | |||
public CustomDataSource() { | |||
super( | |||
query -> { | |||
Stream<Bean> beans = list.stream(); | |||
Comparator<Bean> comparator = query | |||
.getSortOrders() | |||
.stream() | |||
.map(s -> { | |||
Comparator<Bean> c = comparators.get(s | |||
.getSorted()); | |||
if (c == null) { | |||
throw new IllegalArgumentException( | |||
"Could not sort by '" | |||
+ s.getSorted() + "'"); | |||
} | |||
return s.getDirection() == SortDirection.ASCENDING ? c | |||
: c.reversed(); | |||
}) | |||
.reduce((x, y) -> 0, Comparator::thenComparing); | |||
return beans.sorted(comparator); | |||
}); | |||
} | |||
@Override | |||
public boolean isInMemory() { | |||
return false; | |||
} | |||
} | |||
private InMemoryDataSource<Bean> dataSource; | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
Grid<Bean> grid = new Grid<Bean>(); | |||
grid.addColumn("Sortable String", Bean::getValue); | |||
grid.addColumn("Sortable Integer", Bean::getIntVal); | |||
grid.addColumn("Not sortable toString()", Bean::toString).setSortable( | |||
false); | |||
grid.addColumn("Sortable String", Bean::getValue).setSortProperty( | |||
"value"); | |||
grid.addColumn("Sortable Integer", Bean::getIntVal).setSortProperty( | |||
"intVal"); | |||
grid.addColumn("Not sortable toString()", Bean::toString) | |||
.setSortable(false).setSortProperty("Not Sortable."); | |||
grid.setDataSource(DataSource.create(new Bean("Foo", 0), new Bean( | |||
"Bar", 1), new Bean("Bar", 0))); | |||
dataSource = DataSource.create(new Bean("Foo", 0), new Bean("Bar", 1), | |||
new Bean("Bar", 0)); | |||
grid.setDataSource(dataSource); | |||
addComponent(grid); | |||
addComponent(new Button("Change DataSource", e -> { | |||
if (grid.getDataSource() != dataSource) { | |||
grid.setDataSource(dataSource); | |||
} else { | |||
grid.setDataSource(new CustomDataSource()); | |||
} | |||
})); | |||
} | |||
} |