123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- /*
- * Copyright 2000-2018 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.data.provider;
-
- import java.util.Comparator;
- import java.util.List;
- import java.util.Objects;
- import java.util.Optional;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
-
- import com.vaadin.data.TreeData;
- import com.vaadin.server.SerializableConsumer;
- import com.vaadin.shared.Range;
- import com.vaadin.shared.extension.datacommunicator.HierarchicalDataCommunicatorState;
- import com.vaadin.ui.ItemCollapseAllowedProvider;
-
- /**
- * Data communicator that handles requesting hierarchical data from
- * {@link HierarchicalDataProvider} and sending it to client side.
- *
- * @param <T>
- * the bean type
- * @author Vaadin Ltd
- * @since 8.1
- */
- public class HierarchicalDataCommunicator<T> extends DataCommunicator<T> {
-
- private HierarchyMapper<T, ?> mapper;
-
- /**
- * Collapse allowed provider used to allow/disallow collapsing nodes.
- */
- private ItemCollapseAllowedProvider<T> itemCollapseAllowedProvider = t -> true;
-
- /**
- * Construct a new hierarchical data communicator backed by a
- * {@link TreeDataProvider}.
- */
- public HierarchicalDataCommunicator() {
- super();
- setDataProvider(new TreeDataProvider<>(new TreeData<>()), null);
- }
-
- @Override
- protected HierarchicalDataCommunicatorState getState() {
- return (HierarchicalDataCommunicatorState) super.getState();
- }
-
- @Override
- protected HierarchicalDataCommunicatorState getState(boolean markAsDirty) {
- return (HierarchicalDataCommunicatorState) super.getState(markAsDirty);
- }
-
- @Override
- public List<T> fetchItemsWithRange(int offset, int limit) {
- // Instead of adding logic to this class, delegate request to the
- // separate object handling hierarchies.
- return mapper.fetchItems(Range.withLength(offset, limit))
- .collect(Collectors.toList());
- }
-
- @Override
- public HierarchicalDataProvider<T, ?> getDataProvider() {
- return (HierarchicalDataProvider<T, ?>) super.getDataProvider();
- }
-
- /**
- * Set the current hierarchical data provider for this communicator.
- *
- * @param dataProvider
- * the data provider to set, not <code>null</code>
- * @param initialFilter
- * the initial filter value to use, or <code>null</code> to not
- * use any initial filter value
- *
- * @param <F>
- * the filter type
- *
- * @return a consumer that accepts a new filter value to use
- */
- public <F> SerializableConsumer<F> setDataProvider(
- HierarchicalDataProvider<T, F> dataProvider, F initialFilter) {
- SerializableConsumer<F> consumer = super.setDataProvider(dataProvider,
- initialFilter);
-
- // Remove old mapper
- if (mapper != null) {
- removeDataGenerator(mapper);
- }
- mapper = createHierarchyMapper(dataProvider);
-
- // Set up mapper for requests
- mapper.setBackEndSorting(getBackEndSorting());
- mapper.setInMemorySorting(getInMemorySorting());
- mapper.setFilter(getFilter());
- mapper.setItemCollapseAllowedProvider(getItemCollapseAllowedProvider());
-
- // Provide hierarchy data to json
- addDataGenerator(mapper);
-
- return consumer;
- }
-
- /**
- * Create new {@code HierarchyMapper} for the given data provider. May be
- * overridden in subclasses.
- *
- * @param dataProvider
- * the data provider
- * @param <F>
- * Query type
- * @return new {@link HierarchyMapper}
- */
- protected <F> HierarchyMapper<T, F> createHierarchyMapper(
- HierarchicalDataProvider<T, F> dataProvider) {
- return new HierarchyMapper<>(dataProvider);
- }
-
- /**
- * Set the current hierarchical data provider for this communicator.
- *
- * @param dataProvider
- * the data provider to set, must extend
- * {@link HierarchicalDataProvider}, not <code>null</code>
- * @param initialFilter
- * the initial filter value to use, or <code>null</code> to not
- * use any initial filter value
- *
- * @param <F>
- * the filter type
- *
- * @return a consumer that accepts a new filter value to use
- */
- @Override
- public <F> SerializableConsumer<F> setDataProvider(
- DataProvider<T, F> dataProvider, F initialFilter) {
- if (dataProvider instanceof HierarchicalDataProvider) {
- return setDataProvider(
- (HierarchicalDataProvider<T, F>) dataProvider,
- initialFilter);
- }
- throw new IllegalArgumentException(
- "Only " + HierarchicalDataProvider.class.getName()
- + " and subtypes supported.");
- }
-
- /**
- * Collapses the given item and removes its sub-hierarchy. Calling this
- * method will have no effect if the row is already collapsed.
- *
- * @param item
- * the item to collapse
- */
- public void collapse(T item) {
- collapse(item, true);
- }
-
- /**
- * Collapses the given item and removes its sub-hierarchy. Calling this
- * method will have no effect if the row is already collapsed.
- * {@code syncAndRefresh} indicates whether the changes should be
- * synchronised to the client and the data provider be notified.
- *
- * @param item
- * the item to collapse
- * @param syncAndRefresh
- * {@code true} if the changes should be synchronised to the
- * client and the data provider should be notified of the
- * changes, {@code false} otherwise.
- */
- public void collapse(T item, boolean syncAndRefresh) {
- Integer index = syncAndRefresh ? mapper.getIndexOf(item).orElse(null)
- : null;
- doCollapse(item, index, syncAndRefresh);
- }
-
- /**
- * Collapses the given item and removes its sub-hierarchy. Calling this
- * method will have no effect if the row is already collapsed.
- *
- * @param item
- * the item to collapse
- * @param index
- * the index of the item
- */
- public void collapse(T item, Integer index) {
- doCollapse(item, index, true);
- }
-
- /**
- * Collapses given item and removes its sub-hierarchy. Calling this method
- * will have no effect if the row is already collapsed. The index is
- * provided by the client-side or calculated from a full data request.
- *
- *
- * @param item
- * the item to collapse
- * @param index
- * the index of the item
- * @deprecated Use {@link #collapse(Object, Integer)} instead.
- */
- @Deprecated
- public void doCollapse(T item, Optional<Integer> index) {
- doCollapse(item, index.orElse(null), true);
- }
-
- /**
- * Collapses the given item and removes its sub-hierarchy. Calling this
- * method will have no effect if the row is already collapsed. The index is
- * provided by the client-side or calculated from a full data request.
- * {@code syncAndRefresh} indicates whether the changes should be
- * synchronised to the client and the data provider be notified.
- *
- * @param item
- * the item to collapse
- * @param index
- * the index of the item
- * @param syncAndRefresh
- * {@code true} if the changes should be synchronised to the
- * client and the data provider should be notified of the
- * changes, {@code false} otherwise.
- */
- private void doCollapse(T item, Integer index, boolean syncAndRefresh) {
- Range removedRows = mapper.collapse(item, index);
- if (syncAndRefresh) {
- if (!reset && !removedRows.isEmpty()) {
- getClientRpc().removeRows(removedRows.getStart(),
- removedRows.length());
- }
- refresh(item);
- }
- }
-
- /**
- * Expands the given item. Calling this method will have no effect if the
- * item is already expanded or if it has no children.
- *
- * @param item
- * the item to expand
- */
- public void expand(T item) {
- expand(item, true);
- }
-
- /**
- * Expands the given item. Calling this method will have no effect if the
- * item is already expanded or if it has no children. {@code syncAndRefresh}
- * indicates whether the changes should be synchronised to the client and
- * the data provider be notified.
- *
- * @param item
- * the item to expand
- * @param syncAndRefresh
- * {@code true} if the changes should be synchronised to the
- * client and the data provider should be notified of the
- * changes, {@code
- * false} otherwise.
- */
- public void expand(T item, boolean syncAndRefresh) {
- Integer index = syncAndRefresh ? mapper.getIndexOf(item).orElse(null)
- : null;
- doExpand(item, index, syncAndRefresh);
- }
-
- /**
- * Expands the given item at the given index. Calling this method will have
- * no effect if the item is already expanded.
- *
- * @param item
- * the item to expand
- * @param index
- * the index of the item
- */
- public void expand(T item, Integer index) {
- doExpand(item, index, true);
- }
-
- /**
- * Expands the given item. Calling this method will have no effect if the
- * item is already expanded or if it has no children. The index is provided
- * by the client-side or calculated from a full data request.
- * {@code syncAndRefresh} indicates whether the changes should be
- * synchronised to the client and the data provider be notified.
- *
- * @param item
- * the item to expand
- * @param index
- * the index of the item
- * @param syncAndRefresh
- * {@code true} if the changes should be synchronised to the
- * client and the data provider should be notified of the
- * changes, {@code false} otherwise.
- */
- private void doExpand(T item, Integer index, boolean syncAndRefresh) {
- Range addedRows = mapper.expand(item, index);
- if (syncAndRefresh) {
- if (!reset && !addedRows.isEmpty()) {
- getClientRpc().insertRows(addedRows.getStart(),
- addedRows.length());
- Stream<T> children = mapper.fetchItems(item,
- Range.withLength(0, addedRows.length()));
- pushData(addedRows.getStart(),
- children.collect(Collectors.toList()));
- }
- refresh(item);
- }
- }
-
- /**
- * Expands the given item at given index. Calling this method will have no
- * effect if the row is already expanded. The index is provided by the
- * client-side or calculated from a full data request.
- *
- * @param item
- * the item to expand
- * @param index
- * the index of the item
- * @see #expand(Object)
- * @deprecated use {@link #expand(Object, Integer)} instead
- */
- @Deprecated
- public void doExpand(T item, Optional<Integer> index) {
- expand(item, index.orElse(null));
- }
-
- /**
- * Returns whether given item has children.
- *
- * @param item
- * the item to test
- * @return {@code true} if item has children; {@code false} if not
- */
- public boolean hasChildren(T item) {
- return mapper.hasChildren(item);
- }
-
- /**
- * Returns whether given item is expanded.
- *
- * @param item
- * the item to test
- * @return {@code true} if item is expanded; {@code false} if not
- */
- public boolean isExpanded(T item) {
- return mapper.isExpanded(item);
- }
-
- /**
- * Sets the item collapse allowed provider for this
- * HierarchicalDataCommunicator. The provider should return {@code true} for
- * any item that the user can collapse.
- * <p>
- * <strong>Note:</strong> This callback will be accessed often when sending
- * data to the client. The callback should not do any costly operations.
- *
- * @param provider
- * the item collapse allowed provider, not {@code null}
- */
- public void setItemCollapseAllowedProvider(
- ItemCollapseAllowedProvider<T> provider) {
- Objects.requireNonNull(provider, "Provider can't be null");
- itemCollapseAllowedProvider = provider;
- // Update hierarchy mapper
- mapper.setItemCollapseAllowedProvider(provider);
-
- getActiveDataHandler().getActiveData().values().forEach(this::refresh);
- }
-
- /**
- * Returns parent index for the row or a negative value.
- *
- * @param item
- * the item to find the parent of
- * @return the parent index or a negative value for top-level items
- */
- public Integer getParentIndex(T item) {
- return mapper.getParentIndex(item);
- }
-
- /**
- * Gets the item collapse allowed provider.
- *
- * @return the item collapse allowed provider
- */
- public ItemCollapseAllowedProvider<T> getItemCollapseAllowedProvider() {
- return itemCollapseAllowedProvider;
- }
-
- @Override
- public int getDataProviderSize() {
- return mapper.getTreeSize();
- }
-
- @Override
- public void setBackEndSorting(List<QuerySortOrder> sortOrder,
- boolean immediateReset) {
- if (mapper != null) {
- mapper.setBackEndSorting(sortOrder);
- }
- super.setBackEndSorting(sortOrder, immediateReset);
- }
-
- @Override
- public void setBackEndSorting(List<QuerySortOrder> sortOrder) {
- setBackEndSorting(sortOrder, true);
- }
-
- @Override
- public void setInMemorySorting(Comparator<T> comparator,
- boolean immediateReset) {
- if (mapper != null) {
- mapper.setInMemorySorting(comparator);
- }
- super.setInMemorySorting(comparator, immediateReset);
- }
-
- @Override
- public void setInMemorySorting(Comparator<T> comparator) {
- setInMemorySorting(comparator, true);
- }
-
- @Override
- protected <F> void setFilter(F filter) {
- if (mapper != null) {
- mapper.setFilter(filter);
- }
- super.setFilter(filter);
- }
-
- /**
- * Returns the {@code HierarchyMapper} used by this data communicator.
- *
- * @return the hierarchy mapper used by this data communicator
- */
- protected HierarchyMapper<T, ?> getHierarchyMapper() {
- return mapper;
- }
- }
|