diff --git a/pom.xml b/pom.xml index e783473..8b99a23 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 2.9.3-SNAPSHOT TwinColGrid add-on - 14.8.1 + 14.8.20 1.8 1.8 UTF-8 diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableTwinColumn.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableTwinColumn.java new file mode 100644 index 0000000..0e002cf --- /dev/null +++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableTwinColumn.java @@ -0,0 +1,127 @@ +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.component.textfield.TextField; +import com.vaadin.flow.function.SerializableFunction; +import com.vaadin.flow.function.ValueProvider; +import java.util.Comparator; +import java.util.function.Supplier; + +/** Fluent helper object that delegates setters on both columns. */ +public class FilterableTwinColumn extends TwinColumn { + + public FilterableTwinColumn(Column availableColumn, Column selectionColumn) { + super(availableColumn, selectionColumn); + } + + /** + * Set the placeholder of the filter text field on both columns. + * + * @see TextField#setPlaceholder(String) + */ + public FilterableTwinColumn setFilterPlaceholder(String filterPlaceholder) { + TwinColGrid.getFilterTextField(getAvailableColumn()).setPlaceholder(filterPlaceholder); + TwinColGrid.getFilterTextField(getSelectionColumn()).setPlaceholder(filterPlaceholder); + return this; + } + + /** + * Set to {@code false} to hide the clear button which clears the filter text field. + * + * @see TextField#setClearButtonVisible(boolean) + */ + public FilterableTwinColumn setClearButtonVisible(boolean clearButtonVisible) { + TwinColGrid.getFilterTextField(getAvailableColumn()).setClearButtonVisible(clearButtonVisible); + TwinColGrid.getFilterTextField(getSelectionColumn()).setClearButtonVisible(clearButtonVisible); + return this; + } + + @Override + public FilterableTwinColumn setWidth(String width) { + super.setWidth(width); + return this; + } + + @Override + public FilterableTwinColumn setFlexGrow(int flexGrow) { + super.setFlexGrow(flexGrow); + return this; + } + + @Override + public FilterableTwinColumn setAutoWidth(boolean autoWidth) { + super.setAutoWidth(autoWidth); + return this; + } + + @Override + public FilterableTwinColumn setKey(String key) { + super.setKey(key); + return this; + } + + @Override + public FilterableTwinColumn setComparator(Comparator comparator) { + super.setComparator(comparator); + return this; + } + + @Override + public > TwinColumn setComparator( + ValueProvider keyExtractor) { + super.setComparator(keyExtractor); + return this; + } + + @Override + public FilterableTwinColumn setSortProperty(String... properties) { + super.setSortProperty(properties); + return this; + } + + @Override + public FilterableTwinColumn setSortOrderProvider(SortOrderProvider provider) { + super.setSortOrderProvider(provider); + return this; + } + + @Override + public FilterableTwinColumn setSortable(boolean sortable) { + super.setSortable(sortable); + return this; + } + + @Override + public FilterableTwinColumn setHeader(String labelText) { + super.setHeader(labelText); + return this; + } + + @Override + public FilterableTwinColumn setFooter(String labelText) { + super.setFooter(labelText); + return this; + } + + @Override + public FilterableTwinColumn setHeader(Supplier footerComponentSupplier) { + super.setHeader(footerComponentSupplier); + return this; + } + + @Override + public FilterableTwinColumn setFooter(Supplier footerComponentSupplier) { + super.setFooter(footerComponentSupplier); + return this; + } + + @Override + public FilterableTwinColumn setClassNameGenerator( + SerializableFunction classNameGenerator) { + super.setClassNameGenerator(classNameGenerator); + return this; + } + +} diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LegacyTwinColGrid.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LegacyTwinColGrid.java new file mode 100644 index 0000000..31c5d4d --- /dev/null +++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/LegacyTwinColGrid.java @@ -0,0 +1,424 @@ +package com.flowingcode.vaadin.addons.twincolgrid; + +import com.vaadin.flow.component.ItemLabelGenerator; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.data.provider.ListDataProvider; +import com.vaadin.flow.data.renderer.TextRenderer; +import com.vaadin.flow.data.selection.SelectionListener; +import com.vaadin.flow.function.SerializableFunction; +import java.util.Collection; +import java.util.Comparator; +import java.util.function.Supplier; +import lombok.NonNull; + +/** Implementation of {@code TwinColGrid} with deprecated methods from version 2.9.0. */ +@SuppressWarnings("serial") +@Deprecated +public class LegacyTwinColGrid extends TwinColGrid { + + /** @deprecated Use getAvailableGrid() */ + @Deprecated protected final Grid leftGrid; + + /** @deprecated Use getSelectionGrid() */ + @Deprecated protected final Grid rightGrid; + + /** @deprecated Use getAvailableGrid().getDataProvider() */ + @Deprecated protected ListDataProvider leftGridDataProvider; + + /** @deprecated Use getSelectionGrid().getDataProvider() */ + @Deprecated protected ListDataProvider rightGridDataProvider; + + /** Constructs a new TwinColGrid with an empty {@link ListDataProvider}. */ + @SuppressWarnings("unchecked") + public LegacyTwinColGrid() { + super(); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * Constructs a new empty TwinColGrid, using the specified supplier for instantiating both grids. + * + * @param gridSupplier a supplier for instantiating both grids + */ + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(Supplier> gridSupplier) { + super(gridSupplier); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * Constructs a new empty TwinColGrid, using the specified grids for each side. + * + * @param availableGrid the grid that contains the available items + * @param selectionGrid the grid that contains the selected items + */ + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGrid) { + super(availableGrid, selectionGrid); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * Constructs a new empty TwinColGrid with caption + * + * @param caption the component caption + * @deprecated Use {@link TwinColGrid#TwinColGrid()} and {{@link #setCaption(String)} + */ + @Deprecated + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(String caption) { + super(Grid::new); + setCaption(caption); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * 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 + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(final ListDataProvider dataProvider, String caption) { + super(Grid::new); + setDataProvider(dataProvider); + setCaption(caption); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * 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 + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(String caption, Supplier> gridSupplier) { + super(gridSupplier.get(), gridSupplier.get()); + setCaption(caption); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * 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 + @SuppressWarnings("unchecked") + public LegacyTwinColGrid( + String caption, @NonNull Grid availableGrid, @NonNull Grid selectionGrid) { + super(availableGrid, selectionGrid); + setCaption(caption); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** + * 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 + @SuppressWarnings("unchecked") + public LegacyTwinColGrid(final Collection options, final String caption) { + super(options); + setCaption(caption); + leftGrid = getAvailableGrid(); + rightGrid = getSelectionGrid(); + leftGridDataProvider = (ListDataProvider) getAvailableGrid().getDataProvider(); + rightGridDataProvider = (ListDataProvider) getSelectionGrid().getDataProvider(); + } + + /** @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); + } + + /** + * 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 LegacyTwinColGrid withRightColumnCaption(final String caption) { + withSelectionGridCaption(caption); + 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 #withSelectionGridCaption(String)} + */ + @Deprecated + public LegacyTwinColGrid withLeftColumnCaption(final String caption) { + withAvailableGridCaption(caption); + return this; + } + + /** + * Returns the text shown above the right column. + * + * @return The text shown or {@code null} if not set. + * @deprecated Use {@link #getSelectionGridCaption()} + */ + @Deprecated + public String getRightColumnCaption() { + return getSelectionGridCaption(); + } + + /** + * Returns the text shown above the left column. + * + * @return The text shown or {@code null} if not set. + * @deprecated Use {@link #getAvailableGridCaption()} + */ + @Deprecated + public String getLeftColumnCaption() { + return getAvailableGridCaption(); + } + + /** @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); + } + + /** + * 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; + } + + @Override + protected void setDataProvider(ListDataProvider dataProvider) { + leftGridDataProvider = dataProvider; + super.setDataProvider(dataProvider); + } + + /** + * 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}. + * + * @deprecated Use {@link #addColumn(ItemLabelGenerator)}{@code .setHeader(header)} + * + * @param itemLabelGenerator the value provider + * @param header the column header + * @return this instance + */ + @Deprecated + public LegacyTwinColGrid addColumn( + final ItemLabelGenerator itemLabelGenerator, final String header) { + addColumn(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}. + * + * @deprecated Use + * {@link #addColumn(ItemLabelGenerator)}{@code .setHeader(header).setComparator(comparator)} + * + * @param itemLabelGenerator the value provider + * @param comparator the in-memory comparator + * @param header the column header + * @return this instance + */ + @Deprecated + public LegacyTwinColGrid addSortableColumn( + final ItemLabelGenerator itemLabelGenerator, + Comparator comparator, + final String header) { + addColumn(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}. + * + * @deprecated Use + * {@link #addColumn(ItemLabelGenerator)}{@code .setHeader(header).setComparator(comparator).setKey(key)} + * + * @param itemLabelGenerator the value provider + * @param comparator the in-memory comparator + * @param header the column header + * @param header the column key + * @return this instance + */ + @Deprecated + public LegacyTwinColGrid addSortableColumn( + final ItemLabelGenerator itemLabelGenerator, + Comparator comparator, + final String header, + final String key) { + addColumn(itemLabelGenerator) + .setHeader(header) + .setComparator(comparator) + .setSortable(true) + .setKey(key); + return this; + } + + /** + * Adds a new filterable text column to this {@link TwinColGrid}, with a key. The value is + * converted to a String using the provided {@code itemLabelGenerator} and matches are computed + * against the result of {@code filterableValue}. + * + * @deprecated Use {@code addFilterableColumn(itemLabelGenerator, filterableValue)} and configure + * the other properties on the returned {@link TwinColumn}. + */ + @Deprecated + public LegacyTwinColGrid addFilterableColumn(final ItemLabelGenerator itemLabelGenerator, + SerializableFunction filterableValue, final String header, + String filterPlaceholder, boolean enableClearButton, String key) { + TwinColumn column = + addFilterableColumn(itemLabelGenerator, filterableValue).setHeader(header) + .setFilterPlaceholder(filterPlaceholder).setClearButtonVisible(enableClearButton); + if (key != null) { + column.setKey(key); + } + return this; + } + + /** + * Adds a new filterable text column to this {@link TwinColGrid}, with no key. The value is + * converted to a String using the provided {@code itemLabelGenerator} and matches are computed + * against the result of the same {@code itemLabelGenerator}. + * + * @deprecated Use {@code addFilterableColumn(itemLabelGenerator)} and configure the other + * properties on the returned {@link TwinColumn}. + */ + @Deprecated + public LegacyTwinColGrid addFilterableColumn(final ItemLabelGenerator itemLabelGenerator, + final String header, String filterPlaceholder, boolean enableClearButton) { + return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder, + enableClearButton, null); + } + + /** + * Adds a new filterable text column to this {@link TwinColGrid}, with no key. The value is + * converted to a String using the provided {@code itemLabelGenerator} and matches are computed + * against the result of {@code filterableValue}. + * + * @deprecated Use {@code addFilterableColumn(itemLabelGenerator, filterableValue)} and configure + * the other properties on the returned {@link TwinColumn}. + */ + @Deprecated + public LegacyTwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator, + SerializableFunction filterableValue, String header, String filterPlaceholder, + boolean enableClearButton) { + return addFilterableColumn(itemLabelGenerator, filterableValue, header, filterPlaceholder, + enableClearButton, null); + } + + /** + * Adds a new filterable text column to this {@link TwinColGrid}, with a key. The value is + * converted to a String using the provided {@code itemLabelGenerator} and matches are computed + * against the result of the same {@code itemLabelGenerator}. + * + * @deprecated Use {@code addFilterableColumn(itemLabelGenerator)} and configure the other + * properties on the returned {@link TwinColumn}. + */ + @Deprecated + public LegacyTwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator, + String header, String filterPlaceholder, boolean enableClearButton, String key) { + return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder, + enableClearButton, key); + } +} 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..dcf65ca 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java +++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGrid.java @@ -23,6 +23,7 @@ import com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent; import com.vaadin.flow.component.ClientCallable; import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.HasComponents; import com.vaadin.flow.component.HasSize; import com.vaadin.flow.component.HasValue; @@ -47,7 +48,6 @@ 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; @@ -56,7 +56,6 @@ 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; @@ -124,18 +123,6 @@ public enum Orientation { 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; - - /** @deprecated Use getSelectionGrid().getDataProvider() */ - @Deprecated protected ListDataProvider rightGridDataProvider; - private Label captionLabel; private final Button addAllButton = createActionButton(); @@ -158,6 +145,8 @@ public enum Orientation { private boolean isFromClient = false; + private boolean explicitHeaderRow = true; + private static ListDataProvider emptyDataProvider() { return DataProvider.ofCollection(new LinkedHashSet<>()); } @@ -167,46 +156,6 @@ public TwinColGrid() { this(Grid::new); } - /** - * 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. * @@ -216,22 +165,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. * @@ -247,16 +180,13 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri available = new TwinColModel<>(availableGrid, "twincol-grid-available"); selection = new TwinColModel<>(selectionGrid, "twincol-grid-selection"); - leftGrid = available.grid; - rightGrid = selection.grid; - setClassName("twincol-grid"); setMargin(false); setPadding(false); setDataProvider(emptyDataProvider()); - rightGridDataProvider = DataProvider.ofCollection(new LinkedHashSet<>()); + ListDataProvider rightGridDataProvider = DataProvider.ofCollection(new LinkedHashSet<>()); getSelectionGrid().setDataProvider(rightGridDataProvider); getAvailableGrid().setWidth("100%"); @@ -264,22 +194,31 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri addAllButton.addClickListener( e -> { - List filteredItems = available.getDataProvider().withConfigurableFilter() - .fetch(new Query<>()).collect(Collectors.toList()); + List filteredItems = + available + .getDataProvider() + .withConfigurableFilter() + .fetch(new Query<>()) + .collect(Collectors.toList()); updateSelection(new LinkedHashSet<>(filteredItems), new HashSet<>(), true); }); addButton.addClickListener( e -> updateSelection( - new LinkedHashSet<>(getAvailableGrid().getSelectedItems()), new HashSet<>(), true)); + new LinkedHashSet<>(getAvailableGrid().getSelectedItems()), new HashSet<>(), true)); removeButton.addClickListener( e -> updateSelection(new HashSet<>(), getSelectionGrid().getSelectedItems(), true)); 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); }); @@ -295,10 +234,15 @@ public TwinColGrid(@NonNull Grid availableGrid, @NonNull Grid selectionGri side.layout.setSpacing(false); }); + initMoveItemsByDoubleClick(); add(createContainerLayout()); setSizeUndefined(); } + @SuppressWarnings("deprecation") + private void initMoveItemsByDoubleClick() { + setMoveItemsByDoubleClick(!(this instanceof LegacyTwinColGrid)); + } /** * Sets the component caption. @@ -431,8 +375,7 @@ private VerticalLayout getVerticalButtonContainer() { private HorizontalLayout getHorizontalButtonContainer() { HorizontalLayout hButtonContainer = - new HorizontalLayout( - addAllButton, addButton, removeButton, removeAllButton); + new HorizontalLayout(addAllButton, addButton, removeButton, removeAllButton); hButtonContainer.setPadding(false); hButtonContainer.setSizeUndefined(); return hButtonContainer; @@ -448,28 +391,6 @@ public Grid getSelectionGrid() { return selection.grid; } - /** - * 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) { consumer.accept(available); consumer.accept(selection); @@ -488,48 +409,11 @@ 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); } - private void setDataProvider(ListDataProvider dataProvider) { - leftGridDataProvider = dataProvider; + protected void setDataProvider(ListDataProvider dataProvider) { getAvailableGrid().setDataProvider(dataProvider); if (selection.getDataProvider() != null) { selection.getItems().clear(); @@ -547,20 +431,6 @@ public TwinColGrid(final Collection options) { 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. * @@ -588,90 +458,52 @@ public TwinColGrid withSelectionGridCaption(final String caption) { } /** - * Sets the text shown above the grid with the available items. {@code null} clears the caption. + * Configure this component to create the first header row (for column header labels). If no + * column will have a header, this property must be set to {@code false}. * - * @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. + *

+ * When this property is {@code true} (default), the first column added through this component + * will {@linkplain Grid#appendHeaderRow() append} a header row, which will be the "default header + * row" (used by {@code Column.setHeader}). If no headers are set, then the default header row + * will be empty. * - * @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}. + *

+ * When this property is {@code false}, then {@code Column.setHeader} will allocate a header row + * when called (which prevents an empty row if no headers are set, but also replaces the filter + * componentes). * - * @param itemLabelGenerator the value provider - * @param header the column header + * @param value whether the first header row will be created when a column is added. * @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); + public TwinColGrid createFirstHeaderRow(boolean value) { + explicitHeaderRow = value; 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 - * @return this instance - */ - 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; + private void createFirstHeaderRowIfNeeded() { + if (explicitHeaderRow) { + forEachGrid(grid -> { + if (grid.getColumns().isEmpty() && grid.getHeaderRows().isEmpty()) { + grid.appendHeaderRow(); + } + }); + } } /** - * 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 - * @param header the column key - * @return this instance + * @return the pair of columns */ - 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(ItemLabelGenerator itemLabelGenerator) { + createFirstHeaderRowIfNeeded(); + Column availableColumn = + getAvailableGrid().addColumn(new TextRenderer<>(itemLabelGenerator)); + Column selectionColumn = + getSelectionGrid().addColumn(new TextRenderer<>(itemLabelGenerator)); + return new TwinColumn<>(availableColumn, selectionColumn); } public TwinColGrid withoutAddAllButton() { @@ -742,28 +574,6 @@ public String getSelectionGridCaption() { return selection.columnLabel.getText(); } - /** - * Returns the text shown above the right column. - * - * @return The text shown or {@code null} if not set. - * @deprecated Use {@link #getSelectionGridCaption()} - */ - @Deprecated - public String getRightColumnCaption() { - return getSelectionGridCaption(); - } - - /** - * Returns the text shown above the left column. - * - * @return The text shown or {@code null} if not set. - * @deprecated Use {@link #getAvailableGridCaption()} - */ - @Deprecated - public String getLeftColumnCaption() { - return getAvailableGridCaption(); - } - /** * Set {@code value} to grid * @@ -789,8 +599,8 @@ public void setValue(final Set value) { */ @Override public Set getValue() { - return Collections - .unmodifiableSet(collectValue(Collectors.>toCollection(LinkedHashSet::new))); + return Collections.unmodifiableSet( + collectValue(Collectors.>toCollection(LinkedHashSet::new))); } /** @@ -810,15 +620,17 @@ C collectValue(Collector collector) { private static SerializableComparator createSortingComparator(Grid grid) { // protected method copied from Grid::createSortingComparator - BinaryOperator> operator = (comparator1, comparator2) -> { - /* - * thenComparing is defined to return a serializable comparator as long as both original - * comparators are also serializable - */ - return comparator1.thenComparing(comparator2)::compare; - }; + BinaryOperator> operator = + (comparator1, comparator2) -> { + /* + * thenComparing is defined to return a serializable comparator as long as both original + * comparators are also serializable + */ + return comparator1.thenComparing(comparator2)::compare; + }; return grid.getSortOrder().stream() - .map(order -> order.getSorted().getComparator(order.getDirection())).reduce(operator) + .map(order -> order.getSorted().getComparator(order.getDirection())) + .reduce(operator) .orElse(null); } @@ -830,7 +642,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,7 +673,8 @@ 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); @@ -868,9 +682,10 @@ private void updateSelection(final Set addedItems, final Set removedItems, selection.getItems().addAll(addedItems); selection.getItems().removeAll(removedItems); - forEachGrid(grid -> { - grid.getDataProvider().refreshAll(); - grid.getSelectionModel().deselectAll(); + forEachGrid( + grid -> { + grid.getDataProvider().refreshAll(); + grid.getSelectionModel().deselectAll(); }); } @@ -888,8 +703,8 @@ private void configDragAndDrop( draggedItems.addAll(event.getDraggedItems()); } - sourceModel.grid - .setDropMode(sourceModel.isReorderingEnabled() ? GridDropMode.BETWEEN : null); + sourceModel.grid.setDropMode( + sourceModel.isReorderingEnabled() ? GridDropMode.BETWEEN : null); targetModel.grid.setDropMode( targetModel.isReorderingEnabled() ? GridDropMode.BETWEEN : GridDropMode.ON_GRID); }); @@ -926,25 +741,31 @@ private void configDragAndDrop( } }); - sourceModel.grid.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()); - draggedItems.clear(); - draggedGrid = null; - } - }); - }); - + sourceModel.grid.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()); + draggedItems.clear(); + draggedGrid = null; + } + }); + }); } - private void addItems(TwinColModel model, Collection draggedItems, - T dropOverItem, GridDropLocation dropLocation) { + private void addItems( + TwinColModel model, + Collection draggedItems, + T dropOverItem, + GridDropLocation dropLocation) { if (dropOverItem != null) { Collection collection = model.getItems(); List list = new ArrayList<>(collection); @@ -975,87 +796,65 @@ 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); + private static final String COMPONENT_DATA_FILTER = "TwinColGrid#filterTF"; - Optional.ofNullable(key).ifPresent(column::setKey); + private Column createFilterableColumn(TwinColModel side, + ItemLabelGenerator itemLabelGenerator, + SerializableFunction filterableValue) { + Column column = side.grid.addColumn(new TextRenderer<>(itemLabelGenerator)); + TextField filterTF = new TextField(); - TextField filterTF = new TextField(); - filterTF.setClearButtonVisible(enableClearButton); + filterTF.addValueChangeListener( + event -> + side.getDataProvider() + .addFilter( + filterableEntity -> + StringUtils.containsIgnoreCase( + filterableValue.apply(filterableEntity), filterTF.getValue()))); - filterTF.addValueChangeListener( - event -> - side.getDataProvider() - .addFilter( - filterableEntity -> - StringUtils.containsIgnoreCase( - filterableValue.apply(filterableEntity), filterTF.getValue()))); + if (side.headerRow == null) { + side.headerRow = side.grid.appendHeaderRow(); + } - if (side.headerRow == null) { - side.headerRow = side.grid.appendHeaderRow(); - } + side.headerRow.getCell(column).setComponent(filterTF); - side.headerRow.getCell(column).setComponent(filterTF); - filterTF.setValueChangeMode(ValueChangeMode.EAGER); - filterTF.setSizeFull(); - filterTF.setPlaceholder(filterPlaceholder); - }); + filterTF.setValueChangeMode(ValueChangeMode.EAGER); + filterTF.setSizeFull(); - return this; + ComponentUtil.setData(column, COMPONENT_DATA_FILTER, filterTF); + return column; } - public TwinColGrid addFilterableColumn( - final ItemLabelGenerator itemLabelGenerator, - final String header, - String filterPlaceholder, - boolean enableClearButton) { - return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder, - enableClearButton, null); + static TextField getFilterTextField(Column column) { + return (TextField) ComponentUtil.getData(column, COMPONENT_DATA_FILTER); } - public TwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator, - SerializableFunction filterableValue, String header, String filterPlaceholder, - boolean enableClearButton) { - return addFilterableColumn(itemLabelGenerator, filterableValue, header, filterPlaceholder, - enableClearButton, null); + public FilterableTwinColumn addFilterableColumn(ItemLabelGenerator itemLabelGenerator) { + return addFilterableColumn(itemLabelGenerator, itemLabelGenerator); } - public TwinColGrid addFilterableColumn(ItemLabelGenerator itemLabelGenerator, String header, - String filterPlaceholder, boolean enableClearButton, String key) { - return addFilterableColumn(itemLabelGenerator, itemLabelGenerator, header, filterPlaceholder, - enableClearButton, key); + public FilterableTwinColumn addFilterableColumn(ItemLabelGenerator itemLabelGenerator, + SerializableFunction filterableValue) { + + createFirstHeaderRowIfNeeded(); + + Column availableColumn = createFilterableColumn(available, itemLabelGenerator, filterableValue); + Column selectionColumn = createFilterableColumn(selection, itemLabelGenerator, filterableValue); + + return new FilterableTwinColumn<>(availableColumn, selectionColumn); } public TwinColGrid selectRowOnClick() { - forEachGrid(grid -> { - grid.addClassName("hide-selector-col"); + forEachGrid( + grid -> { + grid.addClassName("hide-selector-col"); - grid.addItemClickListener( + grid.addItemClickListener( c -> { - if (grid.getSelectedItems().contains(c.getItem())) { - grid.deselect(c.getItem()); + if (grid.getSelectedItems().contains(c.getItem())) { + grid.deselect(c.getItem()); } else { - grid.select(c.getItem()); + grid.select(c.getItem()); } }); }); @@ -1077,9 +876,7 @@ private Button createActionButton() { return button; } - /** - * Return whether autoResize is set or not. - */ + /** Return whether autoResize is set or not. */ public boolean isAutoResize() { return autoResize; } @@ -1106,23 +903,26 @@ public void setAutoResize(boolean autoResize) { * @param value if true, a a doubleclick event will immediately move an item to the other grid */ public void setMoveItemsByDoubleClick(boolean value) { - forEachSide(side -> { - if (value && side.moveItemsByDoubleClick == null) { - side.moveItemsByDoubleClick = side.grid.addItemDoubleClickListener(ev -> { - Set item = Collections.singleton(ev.getItem()); - if (side == available) { - updateSelection(item, Collections.emptySet(), true); + forEachSide( + side -> { + if (value && side.moveItemsByDoubleClick == null) { + side.moveItemsByDoubleClick = + side.grid.addItemDoubleClickListener( + ev -> { + Set item = Collections.singleton(ev.getItem()); + if (side == available) { + updateSelection(item, Collections.emptySet(), true); + } + if (side == selection) { + updateSelection(Collections.emptySet(), item, true); + } + }); } - if (side == selection) { - updateSelection(Collections.emptySet(), item, true); + if (!value && side.moveItemsByDoubleClick != null) { + side.moveItemsByDoubleClick.remove(); + side.moveItemsByDoubleClick = null; } }); - } - if (!value && side.moveItemsByDoubleClick != null) { - side.moveItemsByDoubleClick.remove(); - side.moveItemsByDoubleClick = null; - } - }); } @ClientCallable @@ -1133,5 +933,4 @@ private void updateOrientationOnResize(int width, int height) { this.withOrientation(Orientation.HORIZONTAL); } } - } diff --git a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java index 053e415..fd93c7f 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java +++ b/src/main/java/com/flowingcode/vaadin/addons/twincolgrid/TwinColGridListAdapter.java @@ -72,7 +72,6 @@ public HasValue> getHasValue() { public List getOldValue() { return null; } - } @NonNull @@ -95,20 +94,26 @@ public Registration addValueChangeListener( List registrations = new ArrayList<>(); - registrations.add(delegate.addValueChangeListener(ev -> { - List value = new ArrayList<>(ev.getValue()); - ValueChangeEvent> listEvent; - listEvent = new ValueChangeEventImpl(ev.isFromClient(), new ArrayList<>(value)); - listener.valueChanged(listEvent); - })); + registrations.add( + delegate.addValueChangeListener( + ev -> { + List value = new ArrayList<>(ev.getValue()); + ValueChangeEvent> listEvent = + new ValueChangeEventImpl(ev.isFromClient(), new ArrayList<>(value)); + listener.valueChanged(listEvent); + })); // sorting the grid changes its value under List::equals - registrations.add(delegate.getSelectionGrid().addSortListener(ev -> { - List value = getValue(); - ValueChangeEvent> listEvent; - listEvent = new ValueChangeEventImpl(ev.isFromClient(), value); - listener.valueChanged(listEvent); - })); + registrations.add( + delegate + .getSelectionGrid() + .addSortListener( + ev -> { + List value = getValue(); + ValueChangeEvent> listEvent = + new ValueChangeEventImpl(ev.isFromClient(), value); + listener.valueChanged(listEvent); + })); return () -> registrations.forEach(Registration::remove); } @@ -117,5 +122,4 @@ public Registration addValueChangeListener( public List getEmptyValue() { return Collections.emptyList(); } - } 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/BoundDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/BoundDemo.java index 6f6fd09..56c99d1 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,29 +46,38 @@ 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) .withAvailableGridCaption("Available books") .withSelectionGridCaption("Added books") .withoutRemoveAllButton() .withSizeFull() .selectRowOnClick(); + twinColGrid.addColumn(Book::getIsbn).setComparator(Book::getIsbn).setHeader("ISBN"); + twinColGrid.addColumn(Book::getTitle).setComparator(Book::getTitle).setHeader("Title"); + 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); add(twinColGrid); - add(new Button("Get values", ev -> { - binder.getBean().getBooks() - .forEach(book -> Notification.show(book.getTitle(), 3000, Position.BOTTOM_START)); - })); + add( + new Button( + "Get values", + ev -> { + binder + .getBean() + .getBooks() + .forEach(book -> Notification.show(book.getTitle(), 3000, Position.BOTTOM_START)); + })); - add(new Button("Clear TwinColGrid", ev -> { - twinColGrid.clear(); - })); + add( + new Button( + "Clear TwinColGrid", + ev -> { + twinColGrid.clear(); + })); setSizeFull(); } @@ -78,11 +86,10 @@ 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("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 ")); 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..4e2aeeb 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,15 +42,15 @@ 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).setComparator(Book::getIsbn).setHeader("ISBN"); + twinColGrid.addColumn(Book::getTitle).setComparator(Book::getTitle).setHeader("Title"); twinColGrid.setValue(selectedBooks); - twinColGrid.setMoveItemsByDoubleClick(true); add(new Span("Move items by double click"), twinColGrid); setSizeFull(); 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..9658eff 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; @@ -49,9 +48,8 @@ public class DragAndDropDemo extends VerticalLayout { public DragAndDropDemo() { initializeData(); - twinColGrid = new TwinColGrid<>(availableBooks) - .addSortableColumn(Book::getIsbn, Comparator.comparing(Book::getIsbn), "ISBN") - .addSortableColumn(Book::getTitle, Comparator.comparing(Book::getTitle), "Title") + twinColGrid = + new TwinColGrid<>(availableBooks) .withAvailableGridCaption("Available books") .withSelectionGridCaption("Added books") .withoutAddAllButton() @@ -60,12 +58,19 @@ public DragAndDropDemo() { .withSelectionGridReordering() .selectRowOnClick(); + twinColGrid.addColumn(Book::getIsbn).setComparator(Book::getIsbn).setHeader("ISBN"); + twinColGrid.addColumn(Book::getTitle).setComparator(Book::getTitle).setHeader("Title"); + twinColGrid.setCaption("TwinColGrid demo with drag and drop support"); twinColGrid.setValue(selectedBooks); final Label countLabel = new Label("Selected items in left grid: 0"); - twinColGrid.getAvailableGrid().addSelectionListener( - e -> countLabel.setText("Selected items in left grid: " + e.getAllSelectedItems().size())); + twinColGrid + .getAvailableGrid() + .addSelectionListener( + e -> + countLabel.setText( + "Selected items in left grid: " + e.getAllSelectedItems().size())); twinColGrid.addValueChangeListener(e -> countLabel.setText("Selected items in left grid: 0")); add(twinColGrid, countLabel); @@ -78,11 +83,10 @@ 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("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 ")); @@ -95,16 +99,18 @@ private void addReorderingToggle() { Span description = new Span("(Reordering is disabled while the grid is sorted)"); description.setVisible(false); - SerializableRunnable refresh = () -> { - boolean sorted = !twinColGrid.getSelectionGrid().getSortOrder().isEmpty(); - boolean allowed = twinColGrid.isSelectionGridReorderingAllowed(); - description.setVisible(sorted && allowed); - }; - - checkbox.addValueChangeListener(ev -> { - twinColGrid.setSelectionGridReorderingAllowed(ev.getValue()); - refresh.run(); - }); + SerializableRunnable refresh = + () -> { + boolean sorted = !twinColGrid.getSelectionGrid().getSortOrder().isEmpty(); + boolean allowed = twinColGrid.isSelectionGridReorderingAllowed(); + description.setVisible(sorted && allowed); + }; + + checkbox.addValueChangeListener( + ev -> { + twinColGrid.setSelectionGridReorderingAllowed(ev.getValue()); + refresh.run(); + }); twinColGrid.getSelectionGrid().addSortListener(ev -> refresh.run()); add(new Div(checkbox, description)); 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..9e4bb61 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java +++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/FilterableDemo.java @@ -42,13 +42,18 @@ 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(); + + twinColGrid.addFilterableColumn(Book::getIsbn).setHeader("ISBN") + .setFilterPlaceholder("ISBN Filter").setClearButtonVisible(true); + twinColGrid.addFilterableColumn(Book::getTitle).setHeader("Title") + .setFilterPlaceholder("Title filter").setClearButtonVisible(false); + + twinColGrid.setCaption("TwinColGrid demo with filtering support"); twinColGrid.setValue(selectedBooks); add(twinColGrid); @@ -59,16 +64,14 @@ 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("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")); } - } diff --git a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/OrientationDemo.java b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/OrientationDemo.java index c8b4a01..97accdc 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/OrientationDemo.java +++ b/src/test/java/com/flowingcode/vaadin/addons/twincolgrid/OrientationDemo.java @@ -27,7 +27,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; @@ -45,18 +44,20 @@ public OrientationDemo() { 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() .withOrientation(Orientation.VERTICAL); + + twinColGrid.addColumn(Book::getIsbn).setComparator(Book::getIsbn).setHeader("ISBN"); + twinColGrid.addColumn(Book::getTitle).setComparator(Book::getTitle).setHeader("Title"); twinColGrid.setValue(selectedBooks); FormLayout formLayout = new FormLayout(); - Select orientationField = new Select<>(Orientation.values()); + Select orientationField = new Select<>(); + orientationField.setItems(Orientation.values()); orientationField.addValueChangeListener(ev -> twinColGrid.withOrientation(ev.getValue())); orientationField.setValue(twinColGrid.getOrientation()); orientationField.setWidth("225px");