diff --git a/pom.xml b/pom.xml
index 9a7b4bd..7ee5d11 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.flowingcode.vaadin.addons
twincolgrid
- 2.9.3-SNAPSHOT
+ 3.0.0-SNAPSHOT
TwinColGrid add-on
14.8.1
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/BaseLazyFilter.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/BaseLazyFilter.java
new file mode 100644
index 0000000..bafd820
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/BaseLazyFilter.java
@@ -0,0 +1,19 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.data.provider.SortOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class BaseLazyFilter implements LazyFilter {
+
+ private Collection selectedItems = new HashSet<>();
+
+ private List> sorting = new ArrayList<>();
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterConfiguration.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterConfiguration.java
new file mode 100644
index 0000000..f23911a
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterConfiguration.java
@@ -0,0 +1,26 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.flowingcode.vaadin.addons.twincolgrid.TwinColModel.TwinColModelMode;
+
+/**
+ * Eager filter configuration for {@link TwinColGrid}.
+ *
+ * @param
+ */
+public class EagerFilterConfiguration extends FilterConfiguration> {
+
+ @SafeVarargs
+ public EagerFilterConfiguration(EagerFilterableColumn... columns) {
+ super(columns);
+ }
+
+ void apply(TwinColGrid grid) {
+ filteredColumns.forEach(grid::addFilterableColumn);
+ }
+
+ @Override
+ boolean supports(TwinColModelMode mode) {
+ return TwinColModelMode.EAGER.equals(mode);
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterableColumn.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterableColumn.java
new file mode 100644
index 0000000..005c556
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerFilterableColumn.java
@@ -0,0 +1,25 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.function.SerializableBiPredicate;
+import lombok.Getter;
+
+/**
+ * Enables in memory filtering support to column.
+ *
+ * @param
+ */
+@Getter
+public class EagerFilterableColumn extends FilterableColumn {
+
+ /**
+ * filter condition to apply to column values.
+ */
+ private final SerializableBiPredicate filterCondition;
+
+ public EagerFilterableColumn(TwinColumn column, String filterPlaceholder,
+ boolean enableClearButton, SerializableBiPredicate filterCondition) {
+ super(column, filterPlaceholder, enableClearButton);
+ this.filterCondition = filterCondition;
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerTwinColModel.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerTwinColModel.java
new file mode 100644
index 0000000..f2fec2d
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/EagerTwinColModel.java
@@ -0,0 +1,95 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.grid.Grid.Column;
+import com.vaadin.flow.component.grid.dnd.GridDropLocation;
+import com.vaadin.flow.component.textfield.TextField;
+import com.vaadin.flow.data.provider.DataProvider;
+import com.vaadin.flow.data.provider.InMemoryDataProvider;
+import com.vaadin.flow.data.provider.ListDataProvider;
+import com.vaadin.flow.data.value.ValueChangeMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import lombok.NonNull;
+
+/**
+ * Model that supports {@link InMemoryDataProvider} for {@link TwinColGrid} available and selection
+ * grids.
+ *
+ * @param
+ */
+class EagerTwinColModel extends TwinColModel> {
+
+ EagerTwinColModel(@NonNull Grid grid, String className) {
+ super(grid, className);
+ this.grid.setDataProvider(DataProvider.ofCollection(new ArrayList<>()));
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ ListDataProvider getDataProvider() {
+ return (ListDataProvider) grid.getDataProvider();
+ }
+
+ @Override
+ void addAll(Collection items) {
+ getDataProvider().getItems().addAll(items);
+ }
+
+ @Override
+ void removeAll(Collection items) {
+ getDataProvider().getItems().removeAll(items);
+ }
+
+ @Override
+ void addFilterableColumn(Column column, EagerFilterableColumn filter) {
+ TextField filterField = new TextField();
+ filterField.setClearButtonVisible(filter.isEnableClearButton());
+ filterField.setValueChangeMode(ValueChangeMode.EAGER);
+ filterField.setSizeFull();
+ filterField.setPlaceholder(filter.getFilterPlaceholder());
+ filterField.addValueChangeListener(
+ event -> getDataProvider()
+ .addFilter(item -> filter.getFilterCondition().test(item, filterField.getValue())));
+
+ if (headerRow == null) {
+ setHeaderRow(grid.appendHeaderRow());
+ }
+
+ headerRow.getCell(column).setComponent(filterField);
+ }
+
+ void clear() {
+ getDataProvider().getItems().clear();
+ }
+
+ void addItems(Collection draggedItems, T dropOverItem, GridDropLocation dropLocation) {
+ if (dropOverItem != null) {
+ Collection collection = getDataProvider().getItems();
+ List list = new ArrayList<>(collection);
+ int dropIndex = list.indexOf(dropOverItem) + (dropLocation == GridDropLocation.BELOW ? 1 : 0);
+ list.addAll(dropIndex, draggedItems);
+ getDataProvider().getItems().clear();
+ addAll(list);
+ } else {
+ addAll(draggedItems);
+ }
+ getDataProvider().refreshAll();
+ }
+
+ Collection getItems() {
+ return getDataProvider().getItems();
+ }
+
+ @Override
+ TwinColModelMode getMode() {
+ return TwinColModelMode.EAGER;
+ }
+
+ @Override
+ boolean supportsAddAll() {
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterConfiguration.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterConfiguration.java
new file mode 100644
index 0000000..554e823
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterConfiguration.java
@@ -0,0 +1,36 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.flowingcode.vaadin.addons.twincolgrid.TwinColModel.TwinColModelMode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+public abstract class FilterConfiguration> {
+
+ protected final Collection filteredColumns = new ArrayList<>();
+
+ @SafeVarargs
+ public FilterConfiguration(C... columns) {
+ filteredColumns.addAll(Arrays.asList(columns));
+ }
+
+ public void addFilteredColumn(C column) {
+ filteredColumns.add(column);
+ }
+
+ /**
+ * Applies this {@link FilterConfiguration} to grid.
+ *
+ * @param grid
+ */
+ abstract void apply(TwinColGrid grid);
+
+ /**
+ * Checks if {@link FilterConfiguration} supports the given {@link TwinColModelMode}
+ *
+ * @param mode mode to check.
+ * @return true mode is supported.
+ */
+ abstract boolean supports(TwinColModelMode mode);
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableColumn.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableColumn.java
new file mode 100644
index 0000000..dbce165
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableColumn.java
@@ -0,0 +1,14 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public abstract class FilterableColumn {
+
+ private final TwinColumn column;
+ private final String filterPlaceholder;
+ private final boolean enableClearButton;
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilter.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilter.java
new file mode 100644
index 0000000..cfbaee4
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilter.java
@@ -0,0 +1,23 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.data.provider.SortOrder;
+import java.util.Collection;
+import java.util.List;
+
+public interface LazyFilter {
+
+ /**
+ * Items already selected.
+ *
+ * @return
+ */
+ Collection getSelectedItems();
+
+ /**
+ * Sorting criterias.
+ *
+ * @return
+ */
+ List> getSorting();
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterConfiguration.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterConfiguration.java
new file mode 100644
index 0000000..d87a9ff
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterConfiguration.java
@@ -0,0 +1,33 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.flowingcode.vaadin.addons.twincolgrid.TwinColModel.TwinColModelMode;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Lazy filter configuration for {@link TwinColGrid}.
+ *
+ * @param
+ */
+@RequiredArgsConstructor
+public class LazyFilterConfiguration extends FilterConfiguration> {
+
+ private final LazyFilter lazyFilter;
+
+ @SafeVarargs
+ public LazyFilterConfiguration(LazyFilter lazyFilter, LazyFilterableColumn... columns) {
+ super(columns);
+ this.lazyFilter = lazyFilter;
+ }
+
+ @Override
+ void apply(TwinColGrid grid) {
+ filteredColumns.forEach(grid::addFilterableColumn);
+ grid.setLazyFilter(lazyFilter);
+ }
+
+ @Override
+ boolean supports(TwinColModelMode mode) {
+ return TwinColModelMode.LAZY.equals(mode);
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableColumn.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableColumn.java
new file mode 100644
index 0000000..3b91990
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableColumn.java
@@ -0,0 +1,38 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.function.SerializableBiPredicate;
+import com.vaadin.flow.function.SerializableConsumer;
+import lombok.Getter;
+
+/**
+ * Enables lazy filtering support to column.
+ *
+ * @param
+ */
+@Getter
+public class LazyFilterableColumn extends FilterableColumn {
+
+ /**
+ * filter bean field to store the query string.
+ */
+ private final SerializableConsumer lazyFilterField;
+
+ /**
+ * filter condition to apply to column values in selection grid.
+ */
+ private final SerializableBiPredicate eagerFilterCondition;
+
+ public LazyFilterableColumn(TwinColumn column, String filterPlaceholder,
+ boolean enableClearButton, SerializableConsumer lazyFilterField,
+ SerializableBiPredicate eagerFilterCondition) {
+ super(column, filterPlaceholder, enableClearButton);
+ this.lazyFilterField = lazyFilterField;
+ this.eagerFilterCondition = eagerFilterCondition;
+ }
+
+ public EagerFilterableColumn asEager() {
+ return new EagerFilterableColumn<>(super.getColumn(), super.getFilterPlaceholder(),
+ super.isEnableClearButton(), eagerFilterCondition);
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyTwinColModel.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyTwinColModel.java
new file mode 100644
index 0000000..d19fd62
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LazyTwinColModel.java
@@ -0,0 +1,101 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.grid.Grid.Column;
+import com.vaadin.flow.component.grid.dnd.GridDropLocation;
+import com.vaadin.flow.component.textfield.TextField;
+import com.vaadin.flow.data.provider.BackEndDataProvider;
+import com.vaadin.flow.data.provider.ConfigurableFilterDataProvider;
+import com.vaadin.flow.data.provider.DataProvider;
+import com.vaadin.flow.data.value.ValueChangeMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import lombok.NonNull;
+
+/**
+ * Model that supports {@link BackEndDataProvider} for {@link TwinColGrid} available grid.
+ *
+ * @param
+ */
+class LazyTwinColModel extends TwinColModel> {
+
+ private final ConfigurableFilterDataProvider> dataProviderWrapper;
+ private LazyFilter lazyFilter;
+
+ LazyTwinColModel(@NonNull Grid grid, String className) {
+ super(grid, className);
+
+ lazyFilter = new BaseLazyFilter<>();
+ dataProviderWrapper = getDataProvider().withConfigurableFilter();
+ dataProviderWrapper.setFilter(lazyFilter);
+ grid.setDataProvider(dataProviderWrapper);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ DataProvider> getDataProvider() {
+ return (DataProvider>) grid.getDataProvider();
+ }
+
+ @Override
+ void addAll(Collection items) {
+ lazyFilter.getSelectedItems().removeAll(items);
+ }
+
+ @Override
+ void removeAll(Collection items) {
+ lazyFilter.getSelectedItems().addAll(items);
+ }
+
+ @Override
+ void addFilterableColumn(Column column, LazyFilterableColumn filter) {
+ TextField filterField = new TextField();
+ filterField.setClearButtonVisible(filter.isEnableClearButton());
+ filterField.setValueChangeMode(ValueChangeMode.EAGER);
+ filterField.setSizeFull();
+ filterField.setPlaceholder(filter.getFilterPlaceholder());
+ filterField.addValueChangeListener(
+ event -> {
+ filter.getLazyFilterField().accept(filterField.getValue());
+ getDataProvider().refreshAll();
+ });
+
+ if (headerRow == null) {
+ setHeaderRow(grid.appendHeaderRow());
+ }
+
+ headerRow.getCell(column).setComponent(filterField);
+ }
+
+ void addItems(Collection draggedItems,
+ T dropOverItem, GridDropLocation dropLocation) {
+ if (dropOverItem != null) {
+ Collection collection = lazyFilter.getSelectedItems();
+ List list = new ArrayList<>(collection);
+ int dropIndex = list.indexOf(dropOverItem) + (dropLocation == GridDropLocation.BELOW ? 1 : 0);
+ list.addAll(dropIndex, draggedItems);
+ lazyFilter.getSelectedItems().clear();
+ addAll(list);
+ } else {
+ addAll(draggedItems);
+ }
+ grid.getDataProvider().refreshAll();
+ }
+
+ > void setFilter(C filter) {
+ lazyFilter = filter;
+ dataProviderWrapper.setFilter(filter);
+ }
+
+ @Override
+ TwinColModelMode getMode() {
+ return TwinColModelMode.LAZY;
+ }
+
+ @Override
+ boolean supportsAddAll() {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
index 2045bdc..0605ba8 100644
--- a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java
@@ -20,6 +20,7 @@
package com.flowingcode.vaadin.addons.twincolgrid;
+import com.flowingcode.vaadin.addons.twincolgrid.TwinColModel.TwinColModelMode;
import com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Component;
@@ -27,7 +28,6 @@
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.HasValue.ValueChangeEvent;
-import com.vaadin.flow.component.ItemLabelGenerator;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.JsModule;
@@ -35,28 +35,21 @@
import com.vaadin.flow.component.grid.Grid.Column;
import com.vaadin.flow.component.grid.Grid.SelectionMode;
import com.vaadin.flow.component.grid.GridNoneSelectionModel;
-import com.vaadin.flow.component.grid.HeaderRow;
-import com.vaadin.flow.component.grid.dnd.GridDropLocation;
import com.vaadin.flow.component.grid.dnd.GridDropMode;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
-import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.DataProvider;
+import com.vaadin.flow.data.provider.InMemoryDataProvider;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.data.renderer.TextRenderer;
-import com.vaadin.flow.data.selection.SelectionListener;
-import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.function.SerializableComparator;
-import com.vaadin.flow.function.SerializableFunction;
+import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.shared.Registration;
-import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@@ -70,7 +63,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.NonNull;
-import org.apache.commons.lang3.StringUtils;
@SuppressWarnings("serial")
@JsModule(value = "./src/fc-twin-col-grid-auto-resize.js")
@@ -80,61 +72,14 @@
public class TwinColGrid extends VerticalLayout
implements HasValue>, Set>, HasComponents, HasSize {
- private static final class TwinColModel implements Serializable {
- final Grid grid;
- final Label columnLabel = new Label();
- final VerticalLayout layout;
- HeaderRow headerRow;
- boolean droppedInsideGrid = false;
- boolean allowReordering = false;
- Registration moveItemsByDoubleClick;
-
- TwinColModel(@NonNull Grid grid, String className) {
- this.grid = grid;
- layout = new VerticalLayout(columnLabel, grid);
-
- layout.setClassName(className);
- grid.setClassName("twincol-grid-items");
- columnLabel.setClassName("twincol-grid-label");
- }
-
- @SuppressWarnings("unchecked")
- ListDataProvider getDataProvider() {
- return (ListDataProvider) grid.getDataProvider();
- }
-
- Collection getItems() {
- return getDataProvider().getItems();
- }
-
- boolean isReorderingEnabled() {
- return allowReordering && grid.getSortOrder().isEmpty();
- }
- }
-
/** enumeration of all available orientation for TwinGolGrid component */
public enum Orientation {
- HORIZONTAL,
- VERTICAL,
- HORIZONTAL_REVERSE,
- VERTICAL_REVERSE;
+ HORIZONTAL, VERTICAL, HORIZONTAL_REVERSE, VERTICAL_REVERSE;
}
- private final TwinColModel available;
-
- private final TwinColModel selection;
-
- /** @deprecated Use getAvailableGrid() */
- @Deprecated protected final Grid leftGrid;
-
- /** @deprecated Use getSelectionGrid() */
- @Deprecated protected final Grid rightGrid;
-
- /** @deprecated Use getAvailableGrid().getDataProvider() */
- @Deprecated protected ListDataProvider leftGridDataProvider;
+ private final TwinColModel available;
- /** @deprecated Use getSelectionGrid().getDataProvider() */
- @Deprecated protected ListDataProvider rightGridDataProvider;
+ private final EagerTwinColModel selection;
private Label captionLabel;
@@ -148,8 +93,6 @@ public enum Orientation {
private Component buttonContainer;
- private Grid draggedGrid;
-
private Label fakeButtonContainerLabel = new Label();
private Orientation orientation = Orientation.HORIZONTAL;
@@ -158,10 +101,6 @@ public enum Orientation {
private boolean isFromClient = false;
- private static ListDataProvider emptyDataProvider() {
- return DataProvider.ofCollection(new LinkedHashSet<>());
- }
-
/** Constructs a new TwinColGrid with an empty {@link ListDataProvider}. */
public TwinColGrid() {
this(Grid::new);
@@ -171,44 +110,6 @@ public TwinColGrid() {
* Constructs a new empty TwinColGrid with caption
*
* @param caption the component caption
- * @deprecated Use {@link TwinColGrid#TwinColGrid()} and {{@link #setCaption(String)}
- */
- @Deprecated
- public TwinColGrid(String caption) {
- this(Grid::new);
- setCaption(caption);
- }
-
- /**
- * Constructs a new TwinColGrid with data provider for options.
- *
- * @param dataProvider the data provider, not {@code null}
- * @param caption the component caption
- * @deprecated Use {@link #TwinColGrid()} and {@link #setDataProvider(ListDataProvider)},
- * {@link #setCaption(String)}
- */
- @Deprecated
- public TwinColGrid(final ListDataProvider dataProvider, String caption) {
- this(Grid::new);
- setDataProvider(dataProvider);
- setCaption(caption);
- }
-
- /**
- * Constructs a new empty TwinColGrid, using the specified supplier for instantiating both grids.
- *
- * @param caption the component caption
- * @param gridSupplier a supplier for instantiating both grids
- * @deprecated Use {@link TwinColGrid#TwinColGrid(Supplier)} and {@link #setCaption(String)}
- */
- @Deprecated
- public TwinColGrid(String caption, Supplier> gridSupplier) {
- this(gridSupplier.get(), gridSupplier.get());
- setCaption(caption);
- }
-
- /**
- * Constructs a new empty TwinColGrid, using the specified supplier for instantiating both grids.
*
* @param gridSupplier a supplier for instantiating both grids
*/
@@ -216,22 +117,6 @@ public TwinColGrid(Supplier> gridSupplier) {
this(gridSupplier.get(), gridSupplier.get());
}
- /**
- * Constructs a new empty TwinColGrid, using the specified grids for each side.
- *
- * @param caption the component caption
- * @param availableGrid the grid that contains the available items
- * @param selectionGrid the grid that contains the selected items
- *
- * @deprecated Use {@link TwinColGrid#TwinColGrid(Grid, Grid)} and {@link #setCaption(String)}
- */
- @Deprecated
- public TwinColGrid(String caption, @NonNull Grid availableGrid,
- @NonNull Grid selectionGrid) {
- this(availableGrid, selectionGrid);
- setCaption(caption);
- }
-
/**
* Constructs a new empty TwinColGrid, using the specified grids for each side.
*
@@ -244,24 +129,23 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri
throw new IllegalArgumentException("Grids must be different");
}
- available = new TwinColModel<>(availableGrid, "twincol-grid-available");
- selection = new TwinColModel<>(selectionGrid, "twincol-grid-selection");
+ if (!(selectionGrid.getDataProvider() instanceof InMemoryDataProvider)) {
+ throw new IllegalArgumentException("Selection Grid only supports InMemoryDataProvider");
+ }
- leftGrid = available.grid;
- rightGrid = selection.grid;
+ available = createModel(availableGrid, "");
+ selection = new EagerTwinColModel<>(selectionGrid, "twincol-grid-selection");
setClassName("twincol-grid");
setMargin(false);
setPadding(false);
- setDataProvider(emptyDataProvider());
- rightGridDataProvider = DataProvider.ofCollection(new LinkedHashSet<>());
- getSelectionGrid().setDataProvider(rightGridDataProvider);
-
getAvailableGrid().setWidth("100%");
getSelectionGrid().setWidth("100%");
+ addAllButton
+ .setVisible(addAllButton.isVisible() && available.supportsAddAll());
addAllButton.addClickListener(
e -> {
List filteredItems = available.getDataProvider().withConfigurableFilter()
@@ -270,8 +154,7 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri
});
addButton.addClickListener(
- e ->
- updateSelection(
+ e -> updateSelection(
new LinkedHashSet<>(getAvailableGrid().getSelectedItems()), new HashSet<>(), true));
removeButton.addClickListener(
@@ -279,26 +162,33 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri
removeAllButton.addClickListener(
e -> {
- List filteredItems= selection.getDataProvider().withConfigurableFilter().fetch(new Query<>()).collect(Collectors.toList());
+ List filteredItems = selection.getDataProvider().withConfigurableFilter()
+ .fetch(new Query<>()).collect(Collectors.toList());
updateSelection(new HashSet<>(), new HashSet<>(filteredItems), true);
});
getElement().getStyle().set("display", "flex");
- forEachSide(
- side -> {
- side.grid.setSelectionMode(SelectionMode.MULTI);
- side.columnLabel.setVisible(false);
- side.layout.setSizeFull();
- side.layout.setMargin(false);
- side.layout.setPadding(false);
- side.layout.setSpacing(false);
- });
+ forEachSide(TwinColModel::init);
add(createContainerLayout());
setSizeUndefined();
}
+ /**
+ * Constructs a new TwinColGrid with the given options.
+ *
+ * @param options the options, cannot be {@code null}
+ */
+ public TwinColGrid(final Collection options) {
+ this();
+ setDataProvider(DataProvider.ofCollection(new LinkedHashSet<>(options)));
+ }
+
+ private TwinColModel createModel(@NonNull Grid grid, String className) {
+ return grid.getDataProvider().isInMemory() ? new EagerTwinColModel<>(grid, className)
+ : new LazyTwinColModel<>(grid, className);
+ }
/**
* Sets the component caption.
@@ -339,8 +229,8 @@ public TwinColGrid withOrientation(Orientation orientation) {
if (this.orientation != orientation) {
this.orientation = orientation;
updateContainerLayout();
- available.grid.getDataProvider().refreshAll();
- selection.grid.getDataProvider().refreshAll();
+ available.getGrid().getDataProvider().refreshAll();
+ selection.getGrid().getDataProvider().refreshAll();
}
return this;
}
@@ -350,7 +240,7 @@ public Orientation getOrientation() {
}
private void updateContainerLayout() {
- Component oldContainerComponent = available.layout.getParent().get();
+ Component oldContainerComponent = available.getLayout().getParent().get();
Component newContainerComponent = createContainerLayout();
replace(oldContainerComponent, newContainerComponent);
}
@@ -389,9 +279,9 @@ private HorizontalLayout createHorizontalContainer(boolean reverse) {
buttonContainer = getVerticalButtonContainer();
HorizontalLayout hl;
if (reverse) {
- hl = new HorizontalLayout(selection.layout, buttonContainer, available.layout);
+ hl = new HorizontalLayout(selection.getLayout(), buttonContainer, available.getLayout());
} else {
- hl = new HorizontalLayout(available.layout, buttonContainer, selection.layout);
+ hl = new HorizontalLayout(available.getLayout(), buttonContainer, selection.getLayout());
}
hl.getElement().getStyle().set("min-height", "0px");
hl.getElement().getStyle().set("flex", "1 1 0px");
@@ -404,9 +294,9 @@ private VerticalLayout createVerticalContainer(boolean reverse) {
buttonContainer = getHorizontalButtonContainer();
VerticalLayout vl;
if (reverse) {
- vl = new VerticalLayout(selection.layout, buttonContainer, available.layout);
+ vl = new VerticalLayout(selection.getLayout(), buttonContainer, available.getLayout());
} else {
- vl = new VerticalLayout(available.layout, buttonContainer, selection.layout);
+ vl = new VerticalLayout(available.getLayout(), buttonContainer, selection.getLayout());
}
vl.getElement().getStyle().set("min-width", "0px");
vl.getElement().getStyle().set("flex", "1 1 0px");
@@ -440,127 +330,31 @@ private HorizontalLayout getHorizontalButtonContainer() {
/** Return the grid that contains the available items. */
public Grid getAvailableGrid() {
- return available.grid;
+ return available.getGrid();
}
/** Return the grid that contains the selected items. */
public Grid getSelectionGrid() {
- return selection.grid;
+ return selection.getGrid();
}
- /**
- * Return the left grid component.
- *
- * @deprecated Use {@link #getAvailableGrid()}. Depending on the orientation, the "left grid" may
- * not be located at the left side.
- */
- @Deprecated
- public Grid getLeftGrid() {
- return leftGrid;
- }
-
- /**
- * Return the right grid component.
- *
- * @deprecated Use {@link #getSelectionGrid()}. Depending on the orientation, the "right grid" may
- * not be located at the right side.
- */
- @Deprecated
- public Grid getRightGrid() {
- return rightGrid;
- }
-
- private void forEachSide(Consumer> consumer) {
+ private void forEachSide(Consumer> consumer) {
consumer.accept(available);
consumer.accept(selection);
}
public final void forEachGrid(Consumer> consumer) {
- consumer.accept(available.grid);
- consumer.accept(selection.grid);
- }
-
- public void setItems(Collection items) {
- setDataProvider(DataProvider.ofCollection(items));
- }
-
- public void setItems(Stream items) {
- setDataProvider(DataProvider.fromStream(items));
- }
-
- /** @deprecated Use {@code getAvailableGrid().setClassName(classname)} */
- @Deprecated
- public void setLeftGridClassName(String classname) {
- getAvailableGrid().setClassName(classname);
- }
-
- /** @deprecated Use {@code getAvailableGrid().addClassName(classname)} */
- @Deprecated
- public void addLeftGridClassName(String classname) {
- getAvailableGrid().addClassName(classname);
- }
-
- /** @deprecated Use {@code getAvailableGrid().removeClassName(classname)} */
- @Deprecated
- public void removeLeftGridClassName(String classname) {
- getAvailableGrid().removeClassName(classname);
- }
-
- /** @deprecated Use {@code getSelectionGrid().setClassName(classname)} */
- @Deprecated
- public void setRightGridClassName(String classname) {
- getSelectionGrid().setClassName(classname);
- }
-
- /** @deprecated Use {@code getSelectionGrid().addClassName(classname)} */
- @Deprecated
- public void addRightGridClassName(String classname) {
- getSelectionGrid().addClassName(classname);
- }
-
- /** @deprecated Use {@code getSelectionGrid().removeClassName(classname)} */
- @Deprecated
- public void removeRightGridClassName(String classname) {
- getSelectionGrid().removeClassName(classname);
- }
-
- public void clearAll() {
- updateSelection(new HashSet<>(), new HashSet<>(selection.getItems()), false);
+ consumer.accept(available.getGrid());
+ consumer.accept(selection.getGrid());
}
private void setDataProvider(ListDataProvider dataProvider) {
- leftGridDataProvider = dataProvider;
getAvailableGrid().setDataProvider(dataProvider);
if (selection.getDataProvider() != null) {
- selection.getItems().clear();
- selection.getDataProvider().refreshAll();
+ selection.clear();
}
}
- /**
- * Constructs a new TwinColGrid with the given options.
- *
- * @param options the options, cannot be {@code null}
- */
- public TwinColGrid(final Collection options) {
- this();
- setDataProvider(DataProvider.ofCollection(new LinkedHashSet<>(options)));
- }
-
- /**
- * Constructs a new TwinColGrid with caption and the given options.
- *
- * @param caption the caption to set, can be {@code null}
- * @param options the options, cannot be {@code null}
- *
- * @deprecated Use {@link #TwinColGrid(Collection)} and {{@link #setCaption(String)}
- */
- @Deprecated
- public TwinColGrid(final Collection options, final String caption) {
- this(options);
- setCaption(caption);
- }
-
/**
* Sets the text shown above the grid with the available items. {@code null} clears the caption.
*
@@ -568,8 +362,8 @@ public TwinColGrid(final Collection options, final String caption) {
* @return this instance
*/
public TwinColGrid withAvailableGridCaption(final String caption) {
- available.columnLabel.setText(caption);
- available.columnLabel.setVisible(true);
+ available.getColumnLabel().setText(caption);
+ available.getColumnLabel().setVisible(true);
fakeButtonContainerLabel.setVisible(true);
return this;
}
@@ -581,97 +375,25 @@ public TwinColGrid withAvailableGridCaption(final String caption) {
* @return this instance
*/
public TwinColGrid withSelectionGridCaption(final String caption) {
- selection.columnLabel.setText(caption);
- selection.columnLabel.setVisible(true);
+ selection.getColumnLabel().setText(caption);
+ selection.getColumnLabel().setVisible(true);
fakeButtonContainerLabel.setVisible(true);
return this;
}
/**
- * Sets the text shown above the grid with the available items. {@code null} clears the caption.
- *
- * @param caption The text to show, {@code null} to clear
- * @return this instance
- * @deprecated Use {@link #withAvailableGridCaption(String)}
- */
- @Deprecated
- public TwinColGrid withRightColumnCaption(final String caption) {
- return withSelectionGridCaption(caption);
- }
-
- /**
- * Sets the text shown above the grid with the available items. {@code null} clears the caption.
- *
- * @param caption The text to show, {@code null} to clear
- * @return this instance
- * @deprecated Use {@link #withSelectionGridCaption(String)}
- */
- @Deprecated
- public TwinColGrid withLeftColumnCaption(final String caption) {
- return withAvailableGridCaption(caption);
- }
-
- /**
- * Adds a new text column to this {@link Grid} with a value provider. The column will use a {@link
- * TextRenderer}. The value is converted to a String using the provided {@code
- * itemLabelGenerator}.
- *
- * @param itemLabelGenerator the value provider
- * @param header the column header
- * @return this instance
- */
- public TwinColGrid addColumn(
- final ItemLabelGenerator itemLabelGenerator, final String header) {
- getAvailableGrid().addColumn(new TextRenderer<>(itemLabelGenerator)).setHeader(header);
- getSelectionGrid().addColumn(new TextRenderer<>(itemLabelGenerator)).setHeader(header);
- return this;
- }
-
- /**
- * Adds a new sortable text column to this {@link Grid} with a value provider. The column will use
- * a {@link TextRenderer}. The value is converted to a String using the provided {@code
- * itemLabelGenerator}.
+ * Adds a column to each grids. Both columns will use a {@link TextRenderer} and the value will be
+ * converted to a String by using the provided {@code itemLabelGenerator}.
*
- * @param itemLabelGenerator the value provider
- * @param comparator the in-memory comparator
- * @param header the column header
- * @return this instance
+ * @param valueProvider the value provider
+ * @return the pair of columns
*/
- public TwinColGrid addSortableColumn(
- final ItemLabelGenerator itemLabelGenerator,
- Comparator comparator,
- final String header) {
- forEachGrid(grid -> grid
- .addColumn(new TextRenderer<>(itemLabelGenerator))
- .setHeader(header)
- .setComparator(comparator)
- .setSortable(true));
- return this;
- }
-
- /**
- * Adds a new sortable text column to this {@link Grid} with a value provider. The column will use
- * a {@link TextRenderer}. The value is converted to a String using the provided {@code
- * itemLabelGenerator}.
- *
- * @param itemLabelGenerator the value provider
- * @param comparator the in-memory comparator
- * @param header the column header
- * @param header the column key
- * @return this instance
- */
- public TwinColGrid addSortableColumn(
- final ItemLabelGenerator itemLabelGenerator,
- Comparator comparator,
- final String header,
- final String key) {
- forEachGrid(grid -> grid
- .addColumn(new TextRenderer<>(itemLabelGenerator))
- .setHeader(header)
- .setComparator(comparator)
- .setSortable(true)
- .setKey(key));
- return this;
+ public TwinColumn addColumn(ValueProvider valueProvider) {
+ Column availableColumn =
+ getAvailableGrid().addColumn(valueProvider);
+ Column selectionColumn =
+ getSelectionGrid().addColumn(valueProvider);
+ return new TwinColumn<>(availableColumn, selectionColumn);
}
public TwinColGrid withoutAddAllButton() {
@@ -730,7 +452,7 @@ public TwinColGrid withDragAndDropSupport() {
* @return The text shown or {@code null} if not set.
*/
public String getAvailableGridCaption() {
- return available.columnLabel.getText();
+ return available.getColumnLabel().getText();
}
/**
@@ -739,7 +461,7 @@ public String getAvailableGridCaption() {
* @return The text shown or {@code null} if not set.
*/
public String getSelectionGridCaption() {
- return selection.columnLabel.getText();
+ return selection.getColumnLabel().getText();
}
/**
@@ -800,7 +522,7 @@ public Set getValue() {
*/
C collectValue(Collector collector) {
Stream stream = selection.getItems().stream();
- SerializableComparator comparator = createSortingComparator(selection.grid);
+ SerializableComparator comparator = createSortingComparator(selection.getGrid());
if (comparator != null) {
return stream.sorted(comparator).collect(collector);
} else {
@@ -830,7 +552,8 @@ public Registration addValueChangeListener(
.addDataProviderListener(
e -> {
ComponentValueChangeEvent, Set> e2 =
- new ComponentValueChangeEvent<>(TwinColGrid.this, TwinColGrid.this, null, isFromClient);
+ new ComponentValueChangeEvent<>(TwinColGrid.this, TwinColGrid.this, null,
+ isFromClient);
listener.valueChanged(e2);
});
}
@@ -860,105 +583,84 @@ public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
getElement().setAttribute("required", requiredIndicatorVisible);
}
- private void updateSelection(final Set addedItems, final Set removedItems, boolean isFromClient) {
+ private void updateSelection(final Set addedItems, final Set removedItems,
+ boolean isFromClient) {
this.isFromClient = isFromClient;
- available.getItems().addAll(removedItems);
- available.getItems().removeAll(addedItems);
+ available.addAll(removedItems);
+ available.removeAll(addedItems);
- selection.getItems().addAll(addedItems);
- selection.getItems().removeAll(removedItems);
+ selection.addAll(addedItems);
+ selection.removeAll(removedItems);
forEachGrid(grid -> {
grid.getDataProvider().refreshAll();
grid.getSelectionModel().deselectAll();
- });
+ });
}
- private void configDragAndDrop(
- final TwinColModel sourceModel, final TwinColModel targetModel) {
+ private void configDragAndDrop(TwinColModel sourceModel, TwinColModel targetModel) {
+ Set draggedItems = new LinkedHashSet<>();
- final Set draggedItems = new LinkedHashSet<>();
+ Grid draggedGrid = sourceModel.getGrid();
- sourceModel.grid.setRowsDraggable(true);
- sourceModel.grid.addDragStartListener(
+ sourceModel.getGrid().setRowsDraggable(true);
+ sourceModel.getGrid().addDragStartListener(
event -> {
- draggedGrid = sourceModel.grid;
-
- if (!(sourceModel.grid.getSelectionModel() instanceof GridNoneSelectionModel)) {
+ if (!(sourceModel.getGrid().getSelectionModel() instanceof GridNoneSelectionModel)) {
draggedItems.addAll(event.getDraggedItems());
}
- sourceModel.grid
+ sourceModel.getGrid()
.setDropMode(sourceModel.isReorderingEnabled() ? GridDropMode.BETWEEN : null);
- targetModel.grid.setDropMode(
+ targetModel.getGrid().setDropMode(
targetModel.isReorderingEnabled() ? GridDropMode.BETWEEN : GridDropMode.ON_GRID);
});
- sourceModel.grid.addDragEndListener(
+ sourceModel.getGrid().addDragEndListener(
event -> {
- if (targetModel.droppedInsideGrid
- && sourceModel.grid == draggedGrid
+ if (targetModel.isDroppedInsideGrid()
+ && sourceModel.getGrid() == draggedGrid
&& !draggedItems.isEmpty()) {
- final ListDataProvider dragGridSourceDataProvider = sourceModel.getDataProvider();
+ sourceModel.removeAll(draggedItems);
- dragGridSourceDataProvider.getItems().removeAll(draggedItems);
- dragGridSourceDataProvider.refreshAll();
-
- targetModel.droppedInsideGrid = false;
+ targetModel.setDroppedInsideGrid(false);
draggedItems.clear();
- sourceModel.grid.deselectAll();
-
- sourceModel.grid.setDropMode(null);
- targetModel.grid.setDropMode(null);
+ sourceModel.getGrid().deselectAll();
+ sourceModel.getDataProvider().refreshAll();
+ sourceModel.getGrid().setDropMode(null);
+ targetModel.getGrid().setDropMode(null);
}
draggedItems.clear();
});
- targetModel.grid.addDropListener(
+ targetModel.getGrid().addDropListener(
event -> {
if (!draggedItems.isEmpty()) {
isFromClient = true;
- targetModel.droppedInsideGrid = true;
+ targetModel.setDroppedInsideGrid(true);
T dropOverItem = event.getDropTargetItem().orElse(null);
- addItems(targetModel, draggedItems, dropOverItem, event.getDropLocation());
+ targetModel.addItems(draggedItems, dropOverItem, event.getDropLocation());
}
});
- sourceModel.grid.addDropListener(event -> {
+ sourceModel.getGrid().addDropListener(event -> {
event.getDropTargetItem().ifPresent(dropOverItem -> {
if (sourceModel.isReorderingEnabled()
&& event.getSource() == draggedGrid
&& !draggedItems.contains(dropOverItem)
&& !draggedItems.isEmpty()) {
isFromClient = true;
- sourceModel.getItems().removeAll(draggedItems);
- addItems(sourceModel, draggedItems, dropOverItem, event.getDropLocation());
+ sourceModel.removeAll(draggedItems);
+ sourceModel.addItems(draggedItems, dropOverItem, event.getDropLocation());
draggedItems.clear();
- draggedGrid = null;
}
});
});
}
- private void addItems(TwinColModel model, Collection draggedItems,
- T dropOverItem, GridDropLocation dropLocation) {
- if (dropOverItem != null) {
- Collection collection = model.getItems();
- List list = new ArrayList<>(collection);
- int dropIndex = list.indexOf(dropOverItem) + (dropLocation == GridDropLocation.BELOW ? 1 : 0);
- list.addAll(dropIndex, draggedItems);
- model.getItems().clear();
- model.getItems().addAll(list);
- model.getDataProvider().refreshAll();
- } else {
- model.getItems().addAll(draggedItems);
- model.getDataProvider().refreshAll();
- }
- }
-
/** Allow drag-and-drop within the selection grid. */
public TwinColGrid withSelectionGridReordering() {
setSelectionGridReorderingAllowed(true);
@@ -967,83 +669,12 @@ public TwinColGrid withSelectionGridReordering() {
/** Configure whether drag-and-drop within the selection grid is allowed. */
public void setSelectionGridReorderingAllowed(boolean value) {
- selection.allowReordering = value;
+ selection.setAllowReordering(value);
}
/** Return whether drag-and-drop within the selection grid is allowed. */
public boolean isSelectionGridReorderingAllowed() {
- return selection.allowReordering;
- }
-
- /** @deprecated Use {@code getAvailableGrid().addSelectionListener(listener);} */
- @Deprecated
- public void addLeftGridSelectionListener(SelectionListener, T> listener) {
- getAvailableGrid().addSelectionListener(listener);
- }
-
- /** @deprecated Use {@code getSelectionGrid().addSelectionListener(listener);} */
- @Deprecated
- public void addRightGridSelectionListener(SelectionListener, T> listener) {
- getSelectionGrid().addSelectionListener(listener);
- }
-
- public TwinColGrid addFilterableColumn(
- final ItemLabelGenerator itemLabelGenerator,
- SerializableFunction filterableValue,
- final String header,
- String filterPlaceholder,
- boolean enableClearButton, String key) {
- forEachSide(
- side -> {
- Column column =
- side.grid.addColumn(new TextRenderer<>(itemLabelGenerator)).setHeader(header);
-
- Optional.ofNullable(key).ifPresent(column::setKey);
-
- TextField filterTF = new TextField();
- filterTF.setClearButtonVisible(enableClearButton);
-
- filterTF.addValueChangeListener(
- event ->
- side.getDataProvider()
- .addFilter(
- filterableEntity ->
- StringUtils.containsIgnoreCase(
- filterableValue.apply(filterableEntity), filterTF.getValue())));
-
- if (side.headerRow == null) {
- side.headerRow = side.grid.appendHeaderRow();
- }
-
- side.headerRow.getCell(column).setComponent(filterTF);
- filterTF.setValueChangeMode(ValueChangeMode.EAGER);
- filterTF.setSizeFull();
- filterTF.setPlaceholder(filterPlaceholder);
- });
-
- return this;
- }
-
- public TwinColGrid addFilterableColumn(
- final ItemLabelGenerator itemLabelGenerator,
- final String header,
- String filterPlaceholder,
- boolean enableClearButton) {
- return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder,
- enableClearButton, null);
- }
-
- public TwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator,
- SerializableFunction filterableValue, String header, String filterPlaceholder,
- boolean enableClearButton) {
- return addFilterableColumn(itemLabelGenerator, filterableValue, header, filterPlaceholder,
- enableClearButton, null);
- }
-
- public TwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator, String header,
- String filterPlaceholder, boolean enableClearButton, String key) {
- return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder,
- enableClearButton, key);
+ return selection.isAllowReordering();
}
public TwinColGrid selectRowOnClick() {
@@ -1051,14 +682,14 @@ public TwinColGrid selectRowOnClick() {
grid.addClassName("hide-selector-col");
grid.addItemClickListener(
- c -> {
+ c -> {
if (grid.getSelectedItems().contains(c.getItem())) {
grid.deselect(c.getItem());
- } else {
+ } else {
grid.select(c.getItem());
- }
- });
- });
+ }
+ });
+ });
return this;
}
@@ -1107,8 +738,8 @@ public void setAutoResize(boolean autoResize) {
*/
public void setMoveItemsByDoubleClick(boolean value) {
forEachSide(side -> {
- if (value && side.moveItemsByDoubleClick == null) {
- side.moveItemsByDoubleClick = side.grid.addItemDoubleClickListener(ev -> {
+ if (value && side.getMoveItemsByDoubleClick() == null) {
+ side.addItemDoubleClickListener(ev -> {
Set item = Collections.singleton(ev.getItem());
if (side == available) {
updateSelection(item, Collections.emptySet(), true);
@@ -1118,9 +749,8 @@ public void setMoveItemsByDoubleClick(boolean value) {
}
});
}
- if (!value && side.moveItemsByDoubleClick != null) {
- side.moveItemsByDoubleClick.remove();
- side.moveItemsByDoubleClick = null;
+ if (!value) {
+ side.removeItemDoubleClickListener();
}
});
}
@@ -1134,4 +764,57 @@ private void updateOrientationOnResize(int width, int height) {
}
}
+ @SuppressWarnings("unchecked")
+ private LazyTwinColModel availableAsLazy() {
+ if (!TwinColModelMode.LAZY.equals(available.getMode())) {
+ throw new IllegalStateException("Available model is not in lazy mode");
+ }
+ return (LazyTwinColModel) available;
+ }
+
+ @SuppressWarnings("unchecked")
+ private EagerTwinColModel availableAsEager() {
+ if (!TwinColModelMode.EAGER.equals(available.getMode())) {
+ throw new IllegalStateException("Available model is not in eager mode");
+ }
+ return (EagerTwinColModel) available;
+ }
+
+ /**
+ * Apply a filter configuration.
+ *
+ * @param filter
+ * @return
+ */
+ public TwinColGrid withFilter(FilterConfiguration filter) {
+ if (!filter.supports(available.getMode())) {
+ throw new IllegalArgumentException("TwinColGrid " + available.getMode().toString()
+ + " mode does not support this type of filter configuration.");
+ }
+ filter.apply(this);
+ return this;
+ }
+
+ TwinColGrid addFilterableColumn(LazyFilterableColumn filter) {
+ if (filter.getLazyFilterField() != null) {
+ availableAsLazy().addFilterableColumn(filter.getColumn().getAvailableColumn(), filter);
+ }
+ if (filter.getEagerFilterCondition() != null) {
+ selection.addFilterableColumn(filter.getColumn().getSelectionColumn(), filter.asEager());
+ }
+ return this;
+ }
+
+ TwinColGrid addFilterableColumn(EagerFilterableColumn filter) {
+ if (filter.getFilterCondition() != null) {
+ availableAsEager().addFilterableColumn(filter.getColumn().getAvailableColumn(), filter);
+ selection.addFilterableColumn(filter.getColumn().getSelectionColumn(), filter);
+ }
+ return this;
+ }
+
+ > void setLazyFilter(F filter) {
+ availableAsLazy().setFilter(filter);
+ }
+
}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColModel.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColModel.java
new file mode 100644
index 0000000..db5822f
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColModel.java
@@ -0,0 +1,121 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.component.ComponentEventListener;
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.grid.Grid.Column;
+import com.vaadin.flow.component.grid.Grid.SelectionMode;
+import com.vaadin.flow.component.grid.HeaderRow;
+import com.vaadin.flow.component.grid.ItemDoubleClickEvent;
+import com.vaadin.flow.component.grid.dnd.GridDropLocation;
+import com.vaadin.flow.component.html.Label;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.data.provider.DataProvider;
+import com.vaadin.flow.shared.Registration;
+import java.io.Serializable;
+import java.util.Collection;
+import lombok.NonNull;
+
+abstract class TwinColModel> implements Serializable {
+
+ enum TwinColModelMode {
+ EAGER, LAZY;
+ }
+
+ protected final Grid grid;
+ private final Label columnLabel = new Label();
+ private final VerticalLayout layout;
+ protected HeaderRow headerRow;
+ private boolean droppedInsideGrid = false;
+ private boolean allowReordering = false;
+ private Registration moveItemsByDoubleClick;
+
+ TwinColModel(@NonNull Grid grid, String className) {
+ this.grid = grid;
+
+ layout = new VerticalLayout(columnLabel, grid);
+ layout.setClassName(className);
+ grid.setClassName("twincol-grid-items");
+ columnLabel.setClassName("twincol-grid-label");
+ }
+
+ void init() {
+ getGrid().setSelectionMode(SelectionMode.MULTI);
+ getColumnLabel().setVisible(false);
+ getLayout().setSizeFull();
+ getLayout().setMargin(false);
+ getLayout().setPadding(false);
+ getLayout().setSpacing(false);
+ }
+
+ boolean isReorderingEnabled() {
+ return allowReordering && grid.getSortOrder().isEmpty();
+ }
+
+ Grid getGrid() {
+ return grid;
+ }
+
+ Label getColumnLabel() {
+ return columnLabel;
+ }
+
+ boolean isDroppedInsideGrid() {
+ return droppedInsideGrid;
+ }
+
+ void setDroppedInsideGrid(boolean droppedInsideGrid) {
+ this.droppedInsideGrid = droppedInsideGrid;
+ }
+
+ void setAllowReordering(boolean allowReordering) {
+ this.allowReordering = allowReordering;
+ }
+
+ boolean isAllowReordering() {
+ return allowReordering;
+ }
+
+ HeaderRow getHeaderRow() {
+ return headerRow;
+ }
+
+ void setHeaderRow(HeaderRow headerRow) {
+ this.headerRow = headerRow;
+ }
+
+ Registration getMoveItemsByDoubleClick() {
+ return moveItemsByDoubleClick;
+ }
+
+ Registration addItemDoubleClickListener(
+ ComponentEventListener> listener) {
+ moveItemsByDoubleClick = grid.addItemDoubleClickListener(listener);
+ return moveItemsByDoubleClick;
+ }
+
+ void removeItemDoubleClickListener() {
+ if (moveItemsByDoubleClick != null) {
+ moveItemsByDoubleClick.remove();
+ moveItemsByDoubleClick = null;
+ }
+ }
+
+ VerticalLayout getLayout() {
+ return layout;
+ }
+
+ abstract > D getDataProvider();
+
+ abstract void addAll(Collection items);
+
+ abstract void removeAll(Collection items);
+
+ abstract void addFilterableColumn(Column column, F filter);
+
+ abstract void addItems(Collection draggedItems, T dropOverItem, GridDropLocation dropLocation);
+
+ abstract TwinColModelMode getMode();
+
+ abstract boolean supportsAddAll();
+
+}
diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColumn.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColumn.java
new file mode 100644
index 0000000..8064d7a
--- /dev/null
+++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColumn.java
@@ -0,0 +1,238 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.component.grid.Grid.Column;
+import com.vaadin.flow.component.grid.SortOrderProvider;
+import com.vaadin.flow.data.provider.QuerySortOrder;
+import com.vaadin.flow.function.SerializableFunction;
+import com.vaadin.flow.function.ValueProvider;
+import java.util.Comparator;
+import java.util.function.Supplier;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/** Fluent helper object that delegates setters on both columns. */
+@RequiredArgsConstructor
+public class TwinColumn {
+
+ /**
+ * Returns the column in the grid with the available items.
+ *
+ * @return The column in the grid with the available items.
+ */
+ @Getter
+ private final Column availableColumn;
+
+ /**
+ * Returns the column in the grid with the selected items.
+ *
+ * @return The column in the grid with the selected items.
+ */
+ @Getter
+ private final Column selectionColumn;
+
+ /**
+ * Sets the width of the columns as a CSS-string.
+ *
+ * @see Column#setWidth(String)
+ *
+ * @param width the width to set both columns to, as a CSS-string, not {@code null}
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setWidth(String width) {
+ availableColumn.setWidth(width);
+ selectionColumn.setWidth(width);
+ return this;
+ }
+
+ /**
+ * Sets the flex grow ratio for the columns. When set to 0, column width is fixed.
+ *
+ * @see Column#setFlexGrow(int)
+ *
+ * @param flexGrow the flex grow ratio
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setFlexGrow(int flexGrow) {
+ availableColumn.setFlexGrow(flexGrow);
+ selectionColumn.setFlexGrow(flexGrow);
+ return this;
+ }
+
+ /**
+ * Enables or disables automatic width for the columns.
+ *
+ * @see Column#setAutoWidth(boolean)
+ *
+ * @param autoWidth whether to enable or disable automatic width on both columns
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setAutoWidth(boolean autoWidth) {
+ availableColumn.setAutoWidth(autoWidth);
+ selectionColumn.setAutoWidth(autoWidth);
+ return this;
+ }
+
+ /**
+ * Sets the user-defined identifier to map the columns.
+ *
+ * @see Column#setKey(String)
+ *
+ * @param key the identifier key, can't be {@code null}
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setKey(String key) {
+ availableColumn.setKey(key);
+ selectionColumn.setKey(key);
+ return this;
+ }
+
+ /**
+ * Sets a comparator to use with in-memory sorting with both columns.
+ *
+ * @see Column#setComparator(Comparator)
+ *
+ * @param comparator the comparator to use when sorting data in both columns
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setComparator(Comparator comparator) {
+ availableColumn.setComparator(comparator);
+ selectionColumn.setComparator(comparator);
+ return this;
+ }
+
+ /**
+ * Sets a comparator to use with in-memory sorting with both columns based on the return type of
+ * the given {@link ValueProvider}.
+ *
+ * @see Column#setComparator(ValueProvider)
+ *
+ * @param the value of the column
+ * @param keyExtractor the value provider used to extract the {@link Comparable} sort key
+ * @return this instance, for method chaining
+ * @see Comparator#comparing(java.util.function.Function)
+ */
+ public > TwinColumn setComparator(
+ ValueProvider keyExtractor) {
+ availableColumn.setComparator(keyExtractor);
+ selectionColumn.setComparator(keyExtractor);
+ return this;
+ }
+
+ /**
+ * Sets strings describing back end properties to be used when sorting the columns.
+ *
+ * @see Column#setSortProperty(String...)
+ *
+ * @param properties the array of strings describing backend properties
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setSortProperty(String... properties) {
+ availableColumn.setSortProperty(properties);
+ selectionColumn.setSortProperty(properties);
+ return this;
+ }
+
+ /**
+ * Sets the sort orders when sorting the columns. The sort order provider is a function which
+ * provides {@link QuerySortOrder} objects to describe how to sort by the columns.
+ *
+ * @see Column#setSortOrderProvider(SortOrderProvider)
+ *
+ * @param provider the function to use when generating sort orders with the given direction
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setSortOrderProvider(SortOrderProvider provider) {
+ availableColumn.setSortOrderProvider(provider);
+ selectionColumn.setSortOrderProvider(provider);
+ return this;
+ }
+
+ /**
+ * Sets whether the user can sort the columns or not.
+ *
+ * @see Column#setSortable(boolean)
+ *
+ * @param sortable {@code true} if the columns can be sorted by the user; {@code false} if not
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setSortable(boolean sortable) {
+ availableColumn.setSortable(sortable);
+ selectionColumn.setSortable(sortable);
+ return this;
+ }
+
+ /**
+ * Sets a header text to both columns.
+ *
+ * @see Column#setHeader(String)
+ *
+ * @param labelText the text to be shown at the columns headers
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setHeader(String labelText) {
+ availableColumn.setHeader(labelText);
+ selectionColumn.setHeader(labelText);
+ return this;
+ }
+
+ /**
+ * Sets a footer text to both columns.
+ *
+ * @see Column#setFooter(String)
+ *
+ * @param labelText the text to be shown at the columns footers
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setFooter(String labelText) {
+ availableColumn.setFooter(labelText);
+ selectionColumn.setFooter(labelText);
+ return this;
+ }
+
+ /**
+ * Sets a header component to both columns.
+ *
+ * @see Column#setHeader(String)
+ *
+ * @param headerComponentSupplier a supplier that instantiates the component to be used in the
+ * header of each column
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setHeader(Supplier footerComponentSupplier) {
+ availableColumn.setHeader(footerComponentSupplier.get());
+ selectionColumn.setHeader(footerComponentSupplier.get());
+ return this;
+ }
+
+ /**
+ * Sets a footer component to both columns.
+ *
+ * @see Column#setFooter(String)
+ *
+ * @param footerComponentSuppleir a supplier that instantiates the component to be used in the
+ * footer of each column
+ * @return this instance, for method chaining
+ */
+ public TwinColumn setFooter(Supplier footerComponentSupplier) {
+ availableColumn.setFooter(footerComponentSupplier.get());
+ selectionColumn.setFooter(footerComponentSupplier.get());
+ return this;
+ }
+
+ /**
+ * Sets the function that is used for generating CSS class names for cells in both columns.
+ *
+ * @see Column#setClassNameGenerator(SerializableFunction)
+ *
+ * @param classNameGenerator the class name generator to set, not {@code null}
+ * @return this instance, for method chaining
+ * @throws NullPointerException if {@code classNameGenerator} is {@code null}
+ */
+ public TwinColumn setClassNameGenerator(SerializableFunction classNameGenerator) {
+ availableColumn.setClassNameGenerator(classNameGenerator);
+ selectionColumn.setClassNameGenerator(classNameGenerator);
+ return this;
+ }
+
+}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/Book.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/Book.java
index 66719b7..49ac39a 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/Book.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/Book.java
@@ -19,39 +19,23 @@
*/
package com.flowingcode.vaadin.addons.twincolgrid;
-import java.util.Objects;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+@RequiredArgsConstructor
+@Getter
+@EqualsAndHashCode
public class Book {
private final String isbn;
private final String title;
- public Book(final String isbn, final String title) {
- this.isbn = isbn;
- this.title = title;
- }
-
- public String getIsbn() {
- return isbn;
- }
-
- public String getTitle() {
- return title;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(isbn, title);
- }
-
- @Override
- public boolean equals(final Object obj) {
- return ObjectUtils.equals(this, (Book) obj, Book::getIsbn, Book::getTitle);
- }
+ private final int price;
@Override
public String toString() {
- return "[Book " + isbn + " - " + title + "]";
+ return "[Book " + isbn + " - " + title + " - " + price + "]";
}
}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookFilter.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookFilter.java
new file mode 100644
index 0000000..bd8b610
--- /dev/null
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookFilter.java
@@ -0,0 +1,14 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class BookFilter extends BaseLazyFilter {
+
+ private String isbn;
+
+ private String title;
+
+}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookService.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookService.java
new file mode 100644
index 0000000..cc8c439
--- /dev/null
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BookService.java
@@ -0,0 +1,95 @@
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.data.provider.SortDirection;
+import com.vaadin.flow.function.SerializableBiPredicate;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+
+public class BookService {
+
+ public static final int BOOKS_COUNT = 500;
+
+ private final List availableBooks = new ArrayList<>();
+
+ private final SerializableBiPredicate isbnFilterPredicate =
+ (book, filter) -> filter == null ? true
+ : StringUtils.containsIgnoreCase(book.getIsbn(), filter);
+
+ private final SerializableBiPredicate titleFilterPredicate =
+ (book, filter) -> filter == null ? true
+ : StringUtils.containsIgnoreCase(book.getTitle(), filter);
+
+
+ public BookService() {
+ initializeData();
+ }
+
+ private void initializeData() {
+ for (int i = 0; i < BOOKS_COUNT; i++) {
+ availableBooks.add(new Book(RandomStringUtils.randomNumeric(8), "Vaadin Recipes " + i,
+ (int) (Math.random() * 1000)));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Stream fetch(int offset, int limit, BookFilter bookFilter) {
+ List filtered = availableBooks.stream()
+ .filter(book -> !bookFilter.getSelectedItems().contains(book))
+ .filter(book -> isbnFilterPredicate.test(book, bookFilter.getIsbn()))
+ .filter(book -> titleFilterPredicate.test(book, bookFilter.getTitle()))
+ .collect(Collectors.toList());
+
+ Comparator combinedComparator = bookFilter.getSorting().stream()
+ .map(sorting -> {
+ Comparator comparator = Comparator
+ .comparing(item -> toComparable(item, sorting.getSorted()));
+ return SortDirection.ASCENDING.equals(sorting.getDirection()) ? comparator
+ : comparator.reversed();
+ })
+ .reduce(Comparator::thenComparing)
+ .orElse((a, b) -> 0);
+
+ return filtered.subList(offset, Math.min(filtered.size(), offset + limit)).stream()
+ .sorted(combinedComparator);
+ }
+
+ private Comparable> toComparable(Book book, String fieldName) {
+ Field sortByField;
+ try {
+
+ sortByField = Book.class.getDeclaredField(fieldName);
+ sortByField.setAccessible(true);
+ Object fieldValue = sortByField.get(book);
+
+ // This check still passes if the type of fieldValue implements Comparable,
+ // where U is an unrelated type from the type of fieldValue, but this is the
+ // best we can do here, since we don't know the type of field at compile time
+ if (!(fieldValue instanceof Comparable) && fieldValue != null) {
+ return null;
+ }
+ return (Comparable>) fieldValue;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public int count(BookFilter bookFilter) {
+ return (int) availableBooks.stream()
+ .filter(book -> !bookFilter.getSelectedItems().contains(book))
+ .filter(book -> isbnFilterPredicate.test(book, bookFilter.getIsbn()))
+ .filter(book -> titleFilterPredicate.test(book, bookFilter.getTitle()))
+ .count();
+ }
+
+ public Book getAny() {
+ int index = (int) (Math.random() * (BookService.BOOKS_COUNT - 1));
+ return availableBooks.get(index);
+ }
+}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
index 6f6fd09..ff6b8a9 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java
@@ -29,7 +29,6 @@
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
@SuppressWarnings("serial")
@@ -47,16 +46,19 @@ public BoundDemo() {
// Binded
final TwinColGrid twinColGrid =
- new TwinColGrid<>(
- availableBooks, "TwinColGrid demo with Binder and row select without checkbox")
- .addSortableColumn(Book::getIsbn, Comparator.comparing(Book::getIsbn), "ISBN")
- .addSortableColumn(Book::getTitle, Comparator.comparing(Book::getTitle), "Title")
+ new TwinColGrid<>(availableBooks)
+ // .addSortableColumn(Book::getIsbn, Comparator.comparing(Book::getIsbn), "ISBN")
+ // .addSortableColumn(Book::getTitle, Comparator.comparing(Book::getTitle), "Title")
.withAvailableGridCaption("Available books")
.withSelectionGridCaption("Added books")
.withoutRemoveAllButton()
.withSizeFull()
.selectRowOnClick();
+ twinColGrid.addColumn(Book::getIsbn).setHeader("ISBN").setSortable(true);
+ twinColGrid.addColumn(Book::getTitle).setHeader("Title").setSortable(true);
+ twinColGrid.setCaption("TwinColGrid demo with Binder and row select without checkbox");
+
final Binder binder = new Binder<>();
binder.forField(twinColGrid.asList()).asRequired().bind(Library::getBooks, Library::setBooks);
binder.setBean(library);
@@ -75,18 +77,20 @@ public BoundDemo() {
}
private void initializeData() {
- selectedBooks.add(new Book("1478375108", "Vaadin Recipes"));
- selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
+ selectedBooks.add(new Book("1478375108", "Vaadin Recipes", 222));
+ selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 121));
- availableBooks.add(new Book("1478375108", "Vaadin Recipes"));
- availableBooks.add(new Book("9781849515221", "Learning Vaadin"));
+ availableBooks.add(new Book("1478375108", "Vaadin Recipes", 232));
+ availableBooks.add(new Book("9781849515221", "Learning Vaadin", 333));
availableBooks
- .add(new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide"));
- availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook"));
- availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision"));
- availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
- availableBooks.add(new Book("9529267533", "Book of Vaadin"));
- availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition"));
+ .add(
+ new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide", 991));
+ availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook", 121));
+ availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision", 244));
+ availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 555));
+ availableBooks.add(new Book("9529267533", "Book of Vaadin", 666));
+ availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition", 423));
}
+
}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DoubleClickDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DoubleClickDemo.java
index e6bc74f..4782394 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DoubleClickDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DoubleClickDemo.java
@@ -25,7 +25,6 @@
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -43,13 +42,14 @@ public DoubleClickDemo() {
initializeData();
final TwinColGrid twinColGrid =
- new TwinColGrid<>(availableBooks, null)
- .addSortableColumn(Book::getIsbn, Comparator.comparing(Book::getIsbn), "ISBN")
- .addSortableColumn(Book::getTitle, Comparator.comparing(Book::getTitle), "Title")
+ new TwinColGrid<>(availableBooks)
.withAvailableGridCaption("Available books")
.withSelectionGridCaption("Added books")
.withSizeFull()
.selectRowOnClick();
+
+ twinColGrid.addColumn(Book::getIsbn).setHeader("ISBN");
+ twinColGrid.addColumn(Book::getTitle).setHeader("Title");
twinColGrid.setValue(selectedBooks);
twinColGrid.setMoveItemsByDoubleClick(true);
@@ -58,16 +58,20 @@ public DoubleClickDemo() {
}
private void initializeData() {
- selectedBooks.add(new Book("1478375108", "Vaadin Recipes"));
- selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
- availableBooks.add(new Book("1478375108", "Vaadin Recipes"));
- availableBooks.add(new Book("9781849515221", "Learning Vaadin"));
- availableBooks.add(
- new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide"));
- availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook"));
- availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision"));
- availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
- availableBooks.add(new Book("9529267533", "Book of Vaadin"));
- availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition"));
+ selectedBooks.add(new Book("1478375108", "Vaadin Recipes", 222));
+ selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 121));
+
+
+ availableBooks.add(new Book("1478375108", "Vaadin Recipes", 232));
+ availableBooks.add(new Book("9781849515221", "Learning Vaadin", 333));
+ availableBooks
+ .add(
+ new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide", 991));
+ availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook", 121));
+ availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision", 244));
+ availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 555));
+ availableBooks.add(new Book("9529267533", "Book of Vaadin", 666));
+ availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition", 423));
}
+
}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DragAndDropDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DragAndDropDemo.java
index ff6205c..6da1c3d 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DragAndDropDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/DragAndDropDemo.java
@@ -30,7 +30,6 @@
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -50,16 +49,16 @@ public DragAndDropDemo() {
initializeData();
twinColGrid = new TwinColGrid<>(availableBooks)
- .addSortableColumn(Book::getIsbn, Comparator.comparing(Book::getIsbn), "ISBN")
- .addSortableColumn(Book::getTitle, Comparator.comparing(Book::getTitle), "Title")
- .withAvailableGridCaption("Available books")
- .withSelectionGridCaption("Added books")
- .withoutAddAllButton()
- .withSizeFull()
- .withDragAndDropSupport()
- .withSelectionGridReordering()
- .selectRowOnClick();
-
+ .withAvailableGridCaption("Available books")
+ .withSelectionGridCaption("Added books")
+ .withoutAddAllButton()
+ .withSizeFull()
+ .withDragAndDropSupport()
+ .withSelectionGridReordering()
+ .selectRowOnClick();
+
+ twinColGrid.addColumn(Book::getIsbn).setHeader("ISBN").setSortable(true);
+ twinColGrid.addColumn(Book::getTitle).setHeader("Title").setSortable(true);
twinColGrid.setCaption("TwinColGrid demo with drag and drop support");
twinColGrid.setValue(selectedBooks);
@@ -75,19 +74,20 @@ public DragAndDropDemo() {
}
private void initializeData() {
- selectedBooks.add(new Book("1478375108", "Vaadin Recipes"));
- selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
+ selectedBooks.add(new Book("1478375108", "Vaadin Recipes", 222));
+ selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 121));
- availableBooks.add(new Book("1478375108", "Vaadin Recipes"));
- availableBooks.add(new Book("9781849515221", "Learning Vaadin"));
+ availableBooks.add(new Book("1478375108", "Vaadin Recipes", 232));
+ availableBooks.add(new Book("9781849515221", "Learning Vaadin", 333));
availableBooks
- .add(new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide"));
- availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook"));
- availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision"));
- availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
- availableBooks.add(new Book("9529267533", "Book of Vaadin"));
- availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition"));
+ .add(
+ new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide", 991));
+ availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook", 121));
+ availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision", 244));
+ availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 555));
+ availableBooks.add(new Book("9529267533", "Book of Vaadin", 666));
+ availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition", 423));
}
private void addReorderingToggle() {
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java
index 779dae3..ee7c8fb 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java
@@ -20,7 +20,6 @@
package com.flowingcode.vaadin.addons.twincolgrid;
-import com.flowingcode.vaadin.addons.demo.DemoSource;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
@@ -28,10 +27,10 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
@SuppressWarnings("serial")
@PageTitle("Filterable")
-@DemoSource
@Route(value = "twincolgrid/filterable", layout = TwincolDemoView.class)
public class FilterableDemo extends VerticalLayout {
@@ -42,13 +41,33 @@ public FilterableDemo() {
initializeData();
final TwinColGrid twinColGrid =
- new TwinColGrid<>(availableBooks, "TwinColGrid demo with filtering support")
- .addFilterableColumn(Book::getIsbn, Book::getIsbn, "ISBN", "ISBN Filter", true)
- .addFilterableColumn(Book::getTitle, "Title", "Title filter", false)
+ new TwinColGrid<>(availableBooks)
.withAvailableGridCaption("Available books")
.withSelectionGridCaption("Added books")
.withoutAddAllButton()
.withSizeFull();
+
+ TwinColumn isbnColumn =
+ twinColGrid.addColumn(Book::getIsbn).setHeader("ISBN").setSortable(true);
+ EagerFilterableColumn isbnFilterableColumn =
+ new EagerFilterableColumn<>(isbnColumn, "ISBN Filter", true,
+ (item, filter) -> StringUtils.isBlank(filter)
+ || StringUtils.containsIgnoreCase(item.getIsbn(), filter));
+
+ TwinColumn titleColumn = twinColGrid.addColumn(Book::getTitle).setHeader("Title");
+ EagerFilterableColumn titleFilterableColumn =
+ new EagerFilterableColumn<>(titleColumn, "Title Filter", true,
+ (item, filter) -> StringUtils.isBlank(filter)
+ || StringUtils.containsIgnoreCase(item.getTitle(), filter));
+
+ twinColGrid.addColumn(Book::getPrice).setHeader("Price").setSortable(true);
+
+ EagerFilterConfiguration filterConfig = new EagerFilterConfiguration<>();
+ filterConfig.addFilteredColumn(isbnFilterableColumn);
+ filterConfig.addFilteredColumn(titleFilterableColumn);
+ twinColGrid.withFilter(filterConfig);
+
+ twinColGrid.setCaption("TwinColGrid demo with filtering support");
twinColGrid.setValue(selectedBooks);
add(twinColGrid);
@@ -56,19 +75,19 @@ public FilterableDemo() {
}
private void initializeData() {
- selectedBooks.add(new Book("1478375108", "Vaadin Recipes"));
- selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
-
+ selectedBooks.add(new Book("1478375108", "Vaadin Recipes", 222));
+ selectedBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 121));
- availableBooks.add(new Book("1478375108", "Vaadin Recipes"));
- availableBooks.add(new Book("9781849515221", "Learning Vaadin"));
+ availableBooks.add(new Book("1478375108", "Vaadin Recipes", 232));
+ availableBooks.add(new Book("9781849515221", "Learning Vaadin", 333));
availableBooks
- .add(new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide"));
- availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook"));
- availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision"));
- availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 "));
- availableBooks.add(new Book("9529267533", "Book of Vaadin"));
- availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition"));
+ .add(
+ new Book("9781782162261", "Vaadin 7 UI Design By Example: Beginner\u2019s Guide", 991));
+ availableBooks.add(new Book("9781849518802", "Vaadin 7 Cookbook", 121));
+ availableBooks.add(new Book("9526800605", "Book of Vaadin: 7th Edition, 1st Revision", 244));
+ availableBooks.add(new Book("9789526800677", "Book of Vaadin: Volume 2 ", 555));
+ availableBooks.add(new Book("9529267533", "Book of Vaadin", 666));
+ availableBooks.add(new Book("1782169776", "Learning Vaadin 7, Second Edition", 423));
}
}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableDemo.java
new file mode 100644
index 0000000..0bbeb0d
--- /dev/null
+++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/LazyFilterableDemo.java
@@ -0,0 +1,118 @@
+/*-
+ * #%L
+ * TwinColGrid add-on
+ * %%
+ * Copyright (C) 2017 - 2022 Flowing Code
+ * %%
+ * 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.
+ * #L%
+ */
+
+package com.flowingcode.vaadin.addons.twincolgrid;
+
+import com.vaadin.flow.component.button.Button;
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.notification.Notification;
+import com.vaadin.flow.component.notification.Notification.Position;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.data.binder.Binder;
+import com.vaadin.flow.data.provider.DataProvider;
+import com.vaadin.flow.data.provider.SortOrder;
+import com.vaadin.flow.router.PageTitle;
+import com.vaadin.flow.router.Route;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+
+@SuppressWarnings("serial")
+@PageTitle("Lazy Filterable")
+@Route(value = "twincolgrid/lazyfilterable", layout = TwincolDemoView.class)
+public class LazyFilterableDemo extends VerticalLayout {
+
+ public LazyFilterableDemo() {
+ BookService bookService = new BookService();
+
+ DataProvider availableDataProvider =
+ DataProvider.fromFilteringCallbacks(
+ query -> {
+ BookFilter filter = query.getFilter().orElseGet(BookFilter::new);
+ filter.setSorting(query.getSortOrders().stream()
+ .map(q -> new SortOrder<>(q.getSorted(), q.getDirection()))
+ .collect(Collectors.toList()));
+ return bookService.fetch(query.getOffset(), query.getLimit(), filter);
+ },
+ query -> bookService.count(query.getFilter().orElseGet(BookFilter::new)));
+
+ Grid availableGrid = new Grid<>();
+ availableGrid.setDataProvider(availableDataProvider);
+
+ Grid selectionGrid = new Grid<>();
+ BookFilter bookFilter = new BookFilter();
+
+ final TwinColGrid twinColGrid =
+ new TwinColGrid<>(availableGrid, selectionGrid)
+ .withAvailableGridCaption("Available books")
+ .withSelectionGridCaption("Added books")
+ .withDragAndDropSupport()
+ .withSelectionGridReordering()
+ .withSizeFull();
+
+ TwinColumn isbnColumn = twinColGrid.addColumn(Book::getIsbn).setHeader("ISBN")
+ .setSortable(true).setSortProperty("isbn");
+ LazyFilterableColumn isbnFilterableColumn =
+ new LazyFilterableColumn<>(isbnColumn, "ISBN Filter", true, bookFilter::setIsbn,
+ (item, filter) -> StringUtils.isBlank(filter)
+ || StringUtils.containsIgnoreCase(item.getIsbn(), filter));
+
+ TwinColumn titleColumn =
+ twinColGrid.addColumn(Book::getTitle).setHeader("Title").setSortable(true)
+ .setSortProperty("title");
+ LazyFilterableColumn titleFilterableColumn =
+ new LazyFilterableColumn<>(titleColumn, "Title Filter", true, bookFilter::setTitle,
+ (item, filter) -> StringUtils.isBlank(filter)
+ || StringUtils.containsIgnoreCase(item.getTitle(), filter));
+
+ twinColGrid.addColumn(Book::getPrice).setHeader("Price").setSortProperty("price");
+
+ LazyFilterConfiguration