diff options
Diffstat (limited to 'client')
5 files changed, 159 insertions, 144 deletions
diff --git a/client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java index 237b6ecf45..95e013ed28 100644 --- a/client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -17,13 +17,18 @@ package com.vaadin.client.data; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.vaadin.client.Profiler; +import com.vaadin.shared.Registration; import com.vaadin.shared.ui.grid.Range; /** @@ -159,8 +164,8 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { @Override public void updateRow() { int index = indexOf(row); - if (index >= 0 && dataChangeHandler != null) { - dataChangeHandler.dataUpdated(index, 1); + if (index >= 0) { + getHandlers().forEach(dch -> dch.dataUpdated(index, 1)); } } } @@ -176,7 +181,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { private final HashMap<Integer, T> indexToRowMap = new HashMap<Integer, T>(); private final HashMap<Object, Integer> keyToIndexMap = new HashMap<Object, Integer>(); - private DataChangeHandler dataChangeHandler; + private Set<DataChangeHandler> dataChangeHandlers = new LinkedHashSet<>(); private CacheStrategy cacheStrategy = new CacheStrategy.DefaultCacheStrategy(); @@ -292,9 +297,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { .partitionWith(cached); handleMissingRows(missingCachePartition[0]); handleMissingRows(missingCachePartition[2]); - } else if (dataChangeHandler != null) { - dataChangeHandler.dataAvailable(cached.getStart(), - cached.length()); + } else { + getHandlers().forEach(dch -> dch + .dataAvailable(cached.getStart(), cached.length())); } } @@ -411,14 +416,19 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { } @Override - public void setDataChangeHandler(DataChangeHandler dataChangeHandler) { - this.dataChangeHandler = dataChangeHandler; + public Registration addDataChangeHandler( + final DataChangeHandler dataChangeHandler) { + Objects.requireNonNull(dataChangeHandler, + "DataChangeHandler can't be null"); + dataChangeHandlers.add(dataChangeHandler); - if (dataChangeHandler != null && !cached.isEmpty()) { + if (!cached.isEmpty()) { // Push currently cached data to the implementation dataChangeHandler.dataUpdated(cached.getStart(), cached.length()); dataChangeHandler.dataAvailable(cached.getStart(), cached.length()); } + + return () -> dataChangeHandlers.remove(dataChangeHandler); } /** @@ -452,21 +462,19 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { Range newUsefulData = partition[1]; if (!newUsefulData.isEmpty()) { // Update the parts that are actually inside - for (int i = newUsefulData.getStart(); i < newUsefulData - .getEnd(); i++) { + int start = newUsefulData.getStart(); + for (int i = start; i < newUsefulData.getEnd(); i++) { final T row = rowData.get(i - firstRowIndex); indexToRowMap.put(Integer.valueOf(i), row); keyToIndexMap.put(getRowKey(row), Integer.valueOf(i)); } - if (dataChangeHandler != null) { - Profiler.enter( - "AbstractRemoteDataSource.setRowData notify dataChangeHandler"); - dataChangeHandler.dataUpdated(newUsefulData.getStart(), - newUsefulData.length()); - Profiler.leave( - "AbstractRemoteDataSource.setRowData notify dataChangeHandler"); - } + Profiler.enter( + "AbstractRemoteDataSource.setRowData notify dataChangeHandler"); + int length = newUsefulData.length(); + getHandlers().forEach(dch -> dch.dataUpdated(start, length)); + Profiler.leave( + "AbstractRemoteDataSource.setRowData notify dataChangeHandler"); // Potentially extend the range if (cached.isEmpty()) { @@ -484,10 +492,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { cached = newUsefulData; } } - if (dataChangeHandler != null) { - dataChangeHandler.dataAvailable(cached.getStart(), - cached.length()); - } + + getHandlers().forEach(dch -> dch.dataAvailable(cached.getStart(), + cached.length())); updatePinnedRows(rowData); } @@ -515,6 +522,12 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { ensureCoverageCheck(); Profiler.leave("AbstractRemoteDataSource.setRowData"); + + } + + private Stream<DataChangeHandler> getHandlers() { + Set<DataChangeHandler> copy = new LinkedHashSet<>(dataChangeHandlers); + return copy.stream(); } private void updatePinnedRows(final List<T> rowData) { @@ -565,9 +578,8 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { cached = cached.offsetBy(-removedRange.length()); } - if (dataChangeHandler != null) { - dataChangeHandler.dataRemoved(firstRowIndex, count); - } + getHandlers().forEach(dch -> dch.dataRemoved(firstRowIndex, count)); + ensureCoverageCheck(); Profiler.leave("AbstractRemoteDataSource.removeRowData"); @@ -612,9 +624,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { keyToIndexMap.remove(getRowKey(row)); } } - if (dataChangeHandler != null) { - dataChangeHandler.dataAdded(firstRowIndex, count); - } + + getHandlers().forEach(dch -> dch.dataAdded(firstRowIndex, count)); + ensureCoverageCheck(); Profiler.leave("AbstractRemoteDataSource.insertRowData"); @@ -760,9 +772,8 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> { size = newSize; dropFromCache(getCachedRange()); cached = Range.withLength(0, 0); - if (dataChangeHandler != null) { - dataChangeHandler.resetDataAndSize(newSize); - } + + getHandlers().forEach(dch -> dch.resetDataAndSize(newSize)); } protected int indexOfKey(Object rowKey) { diff --git a/client/src/main/java/com/vaadin/client/data/DataSource.java b/client/src/main/java/com/vaadin/client/data/DataSource.java index daf1f8656c..3457b7b9fc 100644 --- a/client/src/main/java/com/vaadin/client/data/DataSource.java +++ b/client/src/main/java/com/vaadin/client/data/DataSource.java @@ -16,6 +16,8 @@ package com.vaadin.client.data; +import com.vaadin.shared.Registration; + /** * Source of data for widgets showing lazily loaded data based on indexable * items (e.g. rows) of a specified type. The data source is a lazy view into a @@ -140,7 +142,7 @@ public interface DataSource<T> { * discards the previously set range. * <p> * This method triggers lazy loading of data if necessary. The change - * handler registered using {@link #setDataChangeHandler(DataChangeHandler)} + * handler registered using {@link #addDataChangeHandler(DataChangeHandler)} * is informed when new data has been loaded. * <p> * After any possible lazy loading and updates are done, the change handler @@ -181,7 +183,8 @@ public interface DataSource<T> { * @param dataChangeHandler * the data change handler */ - public void setDataChangeHandler(DataChangeHandler dataChangeHandler); + public Registration addDataChangeHandler( + DataChangeHandler dataChangeHandler); /** * Gets a {@link RowHandle} of a row object in the cache. diff --git a/client/src/main/java/com/vaadin/client/widget/grid/datasources/ListDataSource.java b/client/src/main/java/com/vaadin/client/widget/grid/datasources/ListDataSource.java index 928b0ecf35..584e765127 100644 --- a/client/src/main/java/com/vaadin/client/widget/grid/datasources/ListDataSource.java +++ b/client/src/main/java/com/vaadin/client/widget/grid/datasources/ListDataSource.java @@ -21,13 +21,18 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.widget.grid.events.SelectAllEvent; import com.vaadin.client.widget.grid.events.SelectAllHandler; +import com.vaadin.shared.Registration; import com.vaadin.shared.util.SharedUtil; /** @@ -110,9 +115,8 @@ public class ListDataSource<T> implements DataSource<T> { @Override public void updateRow() { - if (changeHandler != null) { - changeHandler.dataUpdated(ds.indexOf(getRow()), 1); - } + getHandlers() + .forEach(dch -> dch.dataUpdated(ds.indexOf(getRow()), 1)); } } @@ -156,9 +160,7 @@ public class ListDataSource<T> implements DataSource<T> { @Override public boolean add(T e) { if (ds.add(e)) { - if (changeHandler != null) { - changeHandler.dataAdded(ds.size() - 1, 1); - } + getHandlers().forEach(dch -> dch.dataAdded(ds.size() - 1, 1)); return true; } return false; @@ -168,9 +170,7 @@ public class ListDataSource<T> implements DataSource<T> { public boolean remove(Object o) { int index = ds.indexOf(o); if (ds.remove(o)) { - if (changeHandler != null) { - changeHandler.dataRemoved(index, 1); - } + getHandlers().forEach(dch -> dch.dataRemoved(index, 1)); return true; } return false; @@ -185,9 +185,7 @@ public class ListDataSource<T> implements DataSource<T> { public boolean addAll(Collection<? extends T> c) { int idx = ds.size(); if (ds.addAll(c)) { - if (changeHandler != null) { - changeHandler.dataAdded(idx, c.size()); - } + getHandlers().forEach(dch -> dch.dataAdded(idx, c.size())); return true; } return false; @@ -196,9 +194,7 @@ public class ListDataSource<T> implements DataSource<T> { @Override public boolean addAll(int index, Collection<? extends T> c) { if (ds.addAll(index, c)) { - if (changeHandler != null) { - changeHandler.dataAdded(index, c.size()); - } + getHandlers().forEach(dch -> dch.dataAdded(index, c.size())); return true; } return false; @@ -207,12 +203,8 @@ public class ListDataSource<T> implements DataSource<T> { @Override public boolean removeAll(Collection<?> c) { if (ds.removeAll(c)) { - if (changeHandler != null) { - // Have to update the whole list as the removal does not - // have to be a continuous range - changeHandler.dataUpdated(0, ds.size()); - changeHandler.dataAvailable(0, ds.size()); - } + getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size())); + getHandlers().forEach(dch -> dch.dataAvailable(0, ds.size())); return true; } return false; @@ -221,12 +213,8 @@ public class ListDataSource<T> implements DataSource<T> { @Override public boolean retainAll(Collection<?> c) { if (ds.retainAll(c)) { - if (changeHandler != null) { - // Have to update the whole list as the retain does not - // have to be a continuous range - changeHandler.dataUpdated(0, ds.size()); - changeHandler.dataAvailable(0, ds.size()); - } + getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size())); + getHandlers().forEach(dch -> dch.dataAvailable(0, ds.size())); return true; } return false; @@ -236,9 +224,7 @@ public class ListDataSource<T> implements DataSource<T> { public void clear() { int size = ds.size(); ds.clear(); - if (changeHandler != null) { - changeHandler.dataRemoved(0, size); - } + getHandlers().forEach(dch -> dch.dataRemoved(0, size)); } @Override @@ -249,26 +235,20 @@ public class ListDataSource<T> implements DataSource<T> { @Override public T set(int index, T element) { T prev = ds.set(index, element); - if (changeHandler != null) { - changeHandler.dataUpdated(index, 1); - } + getHandlers().forEach(dch -> dch.dataUpdated(index, 1)); return prev; } @Override public void add(int index, T element) { ds.add(index, element); - if (changeHandler != null) { - changeHandler.dataAdded(index, 1); - } + getHandlers().forEach(dch -> dch.dataAdded(index, 1)); } @Override public T remove(int index) { T removed = ds.remove(index); - if (changeHandler != null) { - changeHandler.dataRemoved(index, 1); - } + getHandlers().forEach(dch -> dch.dataRemoved(index, 1)); return removed; } @@ -346,7 +326,7 @@ public class ListDataSource<T> implements DataSource<T> { /** * Handler for listening to changes in the underlying list. */ - private DataChangeHandler changeHandler; + private Set<DataChangeHandler> changeHandlers = new LinkedHashSet<>(); /** * Constructs a new list data source. @@ -392,9 +372,8 @@ public class ListDataSource<T> implements DataSource<T> { "Trying to fetch rows outside of array"); } - if (changeHandler != null) { - changeHandler.dataAvailable(firstRowIndex, numberOfRows); - } + getHandlers() + .forEach(dch -> dch.dataAvailable(firstRowIndex, numberOfRows)); } @Override @@ -408,8 +387,12 @@ public class ListDataSource<T> implements DataSource<T> { } @Override - public void setDataChangeHandler(DataChangeHandler dataChangeHandler) { - this.changeHandler = dataChangeHandler; + public Registration addDataChangeHandler( + DataChangeHandler dataChangeHandler) { + Objects.requireNonNull(dataChangeHandler, + "DataChangeHandler can't be null"); + changeHandlers.add(dataChangeHandler); + return () -> changeHandlers.remove(dataChangeHandler); } /** @@ -443,9 +426,7 @@ public class ListDataSource<T> implements DataSource<T> { */ public void sort(Comparator<T> comparator) { Collections.sort(ds, comparator); - if (changeHandler != null) { - changeHandler.dataUpdated(0, ds.size()); - } + getHandlers().forEach(dch -> dch.dataUpdated(0, ds.size())); } /** @@ -475,4 +456,10 @@ public class ListDataSource<T> implements DataSource<T> { } }; } + + private Stream<DataChangeHandler> getHandlers() { + Set<DataChangeHandler> copy = new LinkedHashSet<>(changeHandlers); + return copy.stream(); + } + } diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java index 53be286ee0..990c85dd1c 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -174,6 +174,7 @@ import com.vaadin.client.widgets.Escalator.SubPartArguments; import com.vaadin.client.widgets.Grid.Editor.State; import com.vaadin.client.widgets.Grid.StaticSection.StaticCell; import com.vaadin.client.widgets.Grid.StaticSection.StaticRow; +import com.vaadin.shared.Registration; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.GridConstants.Section; @@ -4022,6 +4023,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, * on initialization, but not after that. */ private DataSource<T> dataSource; + private Registration changeHandler; /** * Currently available row range in DataSource. @@ -6700,73 +6702,85 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, selectionModel.reset(); - if (this.dataSource != null) { - this.dataSource.setDataChangeHandler(null); + if (changeHandler != null) { + changeHandler.remove(); + changeHandler = null; } this.dataSource = dataSource; - dataSource.setDataChangeHandler(new DataChangeHandler() { - @Override - public void dataUpdated(int firstIndex, int numberOfItems) { - escalator.getBody().refreshRows(firstIndex, numberOfItems); - } + changeHandler = dataSource + .addDataChangeHandler(new DataChangeHandler() { + @Override + public void dataUpdated(int firstIndex, int numberOfItems) { + escalator.getBody().refreshRows(firstIndex, + numberOfItems); + } - @Override - public void dataRemoved(int firstIndex, int numberOfItems) { - escalator.getBody().removeRows(firstIndex, numberOfItems); - Range removed = Range.withLength(firstIndex, numberOfItems); - cellFocusHandler.rowsRemovedFromBody(removed); - } + @Override + public void dataRemoved(int firstIndex, int numberOfItems) { + escalator.getBody().removeRows(firstIndex, + numberOfItems); + Range removed = Range.withLength(firstIndex, + numberOfItems); + cellFocusHandler.rowsRemovedFromBody(removed); + } - @Override - public void dataAdded(int firstIndex, int numberOfItems) { - escalator.getBody().insertRows(firstIndex, numberOfItems); - Range added = Range.withLength(firstIndex, numberOfItems); - cellFocusHandler.rowsAddedToBody(added); - } + @Override + public void dataAdded(int firstIndex, int numberOfItems) { + escalator.getBody().insertRows(firstIndex, + numberOfItems); + Range added = Range.withLength(firstIndex, + numberOfItems); + cellFocusHandler.rowsAddedToBody(added); + } - @Override - public void dataAvailable(int firstIndex, int numberOfItems) { - currentDataAvailable = Range.withLength(firstIndex, - numberOfItems); - fireEvent(new DataAvailableEvent(currentDataAvailable)); - } + @Override + public void dataAvailable(int firstIndex, + int numberOfItems) { + currentDataAvailable = Range.withLength(firstIndex, + numberOfItems); + fireEvent(new DataAvailableEvent(currentDataAvailable)); + } - @Override - public void resetDataAndSize(int newSize) { - RowContainer body = escalator.getBody(); - int oldSize = body.getRowCount(); - - // Hide all details. - Set<Integer> oldDetails = new HashSet<Integer>(visibleDetails); - for (int i : oldDetails) { - setDetailsVisible(i, false); - } + @Override + public void resetDataAndSize(int newSize) { + RowContainer body = escalator.getBody(); + int oldSize = body.getRowCount(); + + // Hide all details. + Set<Integer> oldDetails = new HashSet<Integer>( + visibleDetails); + for (int i : oldDetails) { + setDetailsVisible(i, false); + } - if (newSize > oldSize) { - body.insertRows(oldSize, newSize - oldSize); - cellFocusHandler.rowsAddedToBody( - Range.withLength(oldSize, newSize - oldSize)); - } else if (newSize < oldSize) { - body.removeRows(newSize, oldSize - newSize); - cellFocusHandler.rowsRemovedFromBody( - Range.withLength(newSize, oldSize - newSize)); - } + if (newSize > oldSize) { + body.insertRows(oldSize, newSize - oldSize); + cellFocusHandler.rowsAddedToBody(Range + .withLength(oldSize, newSize - oldSize)); + } else if (newSize < oldSize) { + body.removeRows(newSize, oldSize - newSize); + cellFocusHandler.rowsRemovedFromBody(Range + .withLength(newSize, oldSize - newSize)); + } - if (newSize > 0) { - dataIsBeingFetched = true; - Range visibleRowRange = escalator.getVisibleRowRange(); - dataSource.ensureAvailability(visibleRowRange.getStart(), - visibleRowRange.length()); - } else { - // We won't expect any data more data updates, so just make - // the bookkeeping happy - dataAvailable(0, 0); - } + if (newSize > 0) { + dataIsBeingFetched = true; + Range visibleRowRange = escalator + .getVisibleRowRange(); + dataSource.ensureAvailability( + visibleRowRange.getStart(), + visibleRowRange.length()); + } else { + // We won't expect any data more data updates, so + // just make + // the bookkeeping happy + dataAvailable(0, 0); + } - assert body.getRowCount() == newSize; - } - }); + assert body.getRowCount() == newSize; + } + }); int previousRowCount = escalator.getBody().getRowCount(); if (previousRowCount != 0) { diff --git a/client/src/test/java/com/vaadin/client/ui/grid/ListDataSourceTest.java b/client/src/test/java/com/vaadin/client/ui/grid/ListDataSourceTest.java index 89a2e80679..b3a4f24ebb 100644 --- a/client/src/test/java/com/vaadin/client/ui/grid/ListDataSourceTest.java +++ b/client/src/test/java/com/vaadin/client/ui/grid/ListDataSourceTest.java @@ -56,7 +56,7 @@ public class ListDataSourceTest { DataChangeHandler handler = EasyMock .createNiceMock(DataChangeHandler.class); - ds.setDataChangeHandler(handler); + ds.addDataChangeHandler(handler); handler.dataAdded(4, 1); EasyMock.expectLastCall(); @@ -80,7 +80,7 @@ public class ListDataSourceTest { DataChangeHandler handler = EasyMock .createNiceMock(DataChangeHandler.class); - ds.setDataChangeHandler(handler); + ds.addDataChangeHandler(handler); handler.dataAdded(4, 3); EasyMock.expectLastCall(); @@ -106,7 +106,7 @@ public class ListDataSourceTest { DataChangeHandler handler = EasyMock .createNiceMock(DataChangeHandler.class); - ds.setDataChangeHandler(handler); + ds.addDataChangeHandler(handler); handler.dataRemoved(3, 1); EasyMock.expectLastCall(); @@ -128,7 +128,7 @@ public class ListDataSourceTest { DataChangeHandler handler = EasyMock .createNiceMock(DataChangeHandler.class); - ds.setDataChangeHandler(handler); + ds.addDataChangeHandler(handler); handler.dataRemoved(0, 3); EasyMock.expectLastCall(); @@ -148,7 +148,7 @@ public class ListDataSourceTest { DataChangeHandler handler = EasyMock .createNiceMock(DataChangeHandler.class); - ds.setDataChangeHandler(handler); + ds.addDataChangeHandler(handler); handler.dataRemoved(0, 4); EasyMock.expectLastCall(); |