Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.imunity.vaadin.elements.grid.EditableGrid Maven / Gradle / Ivy
/*
* Copyright (c) 2021 Bixbit - Krzysztof Benedyczak. All rights reserved.
* See LICENCE.txt file for licensing information.
*/
package io.imunity.vaadin.elements.grid;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.customfield.CustomField;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.grid.dnd.GridDropLocation;
import com.vaadin.flow.component.grid.dnd.GridDropMode;
import com.vaadin.flow.component.grid.editor.Editor;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.Setter;
import com.vaadin.flow.data.binder.Validator;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.data.renderer.Renderer;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.function.ValueProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY;
import static com.vaadin.flow.component.button.ButtonVariant.LUMO_TERTIARY;
import static com.vaadin.flow.component.grid.ColumnTextAlign.END;
import static io.imunity.vaadin.elements.CssClassNames.POINTER;
public class EditableGrid extends CustomField>
{
private final Grid grid = new Grid<>();
private final Editor editor = grid.getEditor();
private final GridListDataView gridListDataView;
private final Function msg;
private final VerticalLayout layout;
private final Button add;
private Grid.Column actions;
private T draggedItem;
private boolean editing;
public EditableGrid(Function msg, Supplier supplier)
{
this.msg = msg;
this.gridListDataView = grid.setItems(new ArrayList<>());
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
editor.setBinder(new Binder<>());
add = new Button(msg.apply("add"), VaadinIcon.PLUS_CIRCLE_O.create(), e ->
{
if (editor.isOpen())
{
editor.cancel();
}
T element = supplier.get();
gridListDataView.addItem(element);
editor.editItem(element);
editing = false;
});
add.addThemeVariants(LUMO_PRIMARY);
editor.addOpenListener(e -> add.setEnabled(false));
editor.addCloseListener(e -> add.setEnabled(true));
editor.addCloseListener(e ->
{
Binder binder = editor.getBinder();
if(binder.validate().hasErrors() && binder.getBean() != null)
{
gridListDataView.removeItem(binder.getBean());
updateValue();
}
});
editor.setBuffered(true);
grid.addItemDoubleClickListener(e ->
{
if (!editor.isOpen())
{
editor.editItem(e.getItem());
editing = true;
}
});
layout = new VerticalLayout(add, grid);
layout.setPadding(false);
layout.setAlignItems(FlexComponent.Alignment.END);
add(layout);
addActionColumn();
enableRowReordering();
}
private void addActionColumn()
{
actions = grid.addComponentColumn(bean ->
{
Icon removeIcon = VaadinIcon.TRASH.create();
removeIcon.addClassName(POINTER.getName());
removeIcon.addClickListener(event ->
{
gridListDataView.removeItem(bean);
updateValue();
fireEvent(new ComponentValueChangeEvent<>(this, this, getValue(), true));
});
Icon moveIcon = VaadinIcon.RESIZE_H.create();
moveIcon.addClassName(POINTER.getName());
HorizontalLayout layout = new HorizontalLayout(moveIcon, removeIcon);
layout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
return layout;
})
.setHeader(msg.apply("actions"))
.setEditorComponent(addEditButtons())
.setAutoWidth(true)
.setTextAlign(END);
}
public Grid.Column addColumn(ValueProvider get, Setter set, boolean req)
{
Grid.Column tColumn = grid.addColumn(get)
.setEditorComponent(getBaseEditorComponent(get, set, req, null));
putActionColumnToEnd(tColumn);
return tColumn;
}
public Grid.Column addColumn(ValueProvider get, Setter set, Validator validator)
{
Grid.Column tColumn = grid.addColumn(get)
.setEditorComponent(getBaseEditorComponent(get, set, true, validator));
putActionColumnToEnd(tColumn);
return tColumn;
}
public void setAddingEnabled(boolean enabled)
{
add.setEnabled(enabled);
}
public boolean isEditorOpen()
{
return editor.isOpen();
}
public void addEditorCloseListener(Runnable runnable)
{
editor.addCloseListener(e -> runnable.run());
}
public void addEditorOpenListener(Runnable runnable)
{
editor.addOpenListener(e -> runnable.run());
}
private void putActionColumnToEnd(Grid.Column tColumn)
{
List> columns = new ArrayList<>(grid.getColumns());
columns.set(columns.size() - 2, tColumn);
columns.set(columns.size() - 1, actions);
grid.setColumnOrder(columns);
}
public Grid.Column addComboBoxColumn(ValueProvider get, Setter set, List items)
{
Grid.Column tColumn = grid.addColumn(get)
.setEditorComponent(getSelectEditorComponent(get, set, items));
putActionColumnToEnd(tColumn);
return tColumn;
}
public Grid.Column addCheckboxColumn(ValueProvider get, Setter set)
{
Grid.Column tColumn = grid.addColumn(get).setRenderer(new ComponentRenderer<>(c -> getReadOnlyCheckbox(get.apply(c))))
.setEditorComponent(getCheckboxEditorComponent(get, set));
putActionColumnToEnd(tColumn);
return tColumn;
}
private Checkbox getReadOnlyCheckbox(boolean val)
{
Checkbox checkbox = new Checkbox();
checkbox.setReadOnly(true);
checkbox.setValue(val);
return checkbox;
}
public Grid.Column addCustomColumn(ValueProvider componentValueGetter, Setter componentValueSetter,
HasValue, F> component)
{
Binder.BindingBuilder bindingBuilder = editor.getBinder().forField(component);
if(component.isRequiredIndicatorVisible())
bindingBuilder.asRequired();
bindingBuilder.bind(componentValueGetter, componentValueSetter);
Grid.Column tColumn = grid.addColumn(componentValueGetter)
.setEditorComponent((Component) component);
putActionColumnToEnd(tColumn);
return tColumn;
}
public Grid.Column addCustomColumn(ValueProvider columnValueProvider,
ValueProvider componentValueGetter, Setter componentValueSetter, HasValue, F> component)
{
Binder.BindingBuilder bindingBuilder = editor.getBinder().forField(component);
if(component.isRequiredIndicatorVisible())
bindingBuilder.asRequired();
bindingBuilder.bind(componentValueGetter, componentValueSetter);
Grid.Column tColumn = grid.addColumn(columnValueProvider)
.setEditorComponent((Component) component);
putActionColumnToEnd(tColumn);
return tColumn;
}
public Grid.Column addCustomColumn(ValueProvider get, Renderer presentation, Setter set, HasValue, F> component)
{
editor.getBinder().forField(component).bind(get, set);
Grid.Column tColumn = grid.addColumn(get).setRenderer(presentation)
.setEditorComponent((Component) component);
putActionColumnToEnd(tColumn);
return tColumn;
}
public Grid.Column addIntColumn(ValueProvider get, Setter set)
{
Grid.Column tColumn = grid.addColumn(get)
.setEditorComponent(getIntegerEditorComponent(get, set));
putActionColumnToEnd(tColumn);
return tColumn;
}
private TextField getBaseEditorComponent(ValueProvider get, Setter set, boolean req, Validator validator)
{
TextField field = new TextField();
field.setValueChangeMode(ValueChangeMode.EAGER);
Binder.BindingBuilder bindingBuilder = editor.getBinder().forField(field);
if(req)
bindingBuilder = bindingBuilder.asRequired(msg.apply("fieldRequired"));
if(validator != null)
bindingBuilder = bindingBuilder.withValidator(validator);
bindingBuilder.bind(get, set);
return field;
}
private IntegerField getIntegerEditorComponent(ValueProvider get, Setter set)
{
IntegerField field = new IntegerField();
field.setMin(1);
field.setMax(65535);
field.setValueChangeMode(ValueChangeMode.EAGER);
editor.getBinder()
.forField(field)
.asRequired(msg.apply("fieldRequired"))
.bind(get, set);
return field;
}
private Select getSelectEditorComponent(ValueProvider get, Setter set, List items)
{
Select field = new Select<>();
field.setWidthFull();
field.setItems(items);
editor.getBinder().forField(field).bind(get, set);
return field;
}
private Checkbox getCheckboxEditorComponent(ValueProvider get, Setter set)
{
Checkbox field = new Checkbox();
editor.getBinder().forField(field).bind(get, set);
return field;
}
private void enableRowReordering()
{
grid.setDropMode(GridDropMode.BETWEEN);
grid.setRowsDraggable(true);
grid.addDragStartListener(e -> draggedItem = e.getDraggedItems().get(0));
grid.addDropListener(e ->
{
T targetPerson = e.getDropTargetItem().orElse(null);
GridDropLocation dropLocation = e.getDropLocation();
if (targetPerson == null || draggedItem.equals(targetPerson))
return;
gridListDataView.removeItem(draggedItem);
if (dropLocation == GridDropLocation.BELOW)
gridListDataView.addItemAfter(draggedItem, targetPerson);
else
gridListDataView.addItemBefore(draggedItem, targetPerson);
updateValue();
});
grid.addDragEndListener(e -> draggedItem = null);
}
private Component addEditButtons()
{
Button save = new Button(msg.apply("save"), e ->
{
if(editor.getBinder().validate().isOk())
{
editor.save();
editor.cancel();
fireEvent(new ComponentValueChangeEvent<>(this, this, getValue(), true));
}
});
save.addThemeVariants(LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
Button cancel = new Button(msg.apply("cancel"), e ->
{
if(!editing)
gridListDataView.removeItem(editor.getItem());
updateValue();
editor.cancel();
fireEvent(new ComponentValueChangeEvent<>(this, this, getValue(), true));
});
cancel.addThemeVariants(LUMO_TERTIARY);
editor.getBinder()
.addStatusChangeListener(status -> save.setEnabled(status.getBinder().isValid()));
editor.addOpenListener(e -> save.setEnabled(false));
return new Div(save, cancel);
}
@Override
protected List generateModelValue()
{
return getValue();
}
@Override
public List getValue()
{
return gridListDataView.getItems().toList();
}
@Override
protected void setPresentationValue(List ts)
{
gridListDataView.removeItems(gridListDataView.getItems().toList());
gridListDataView.addItems(ts);
}
@Override
public void setHeight(String height)
{
layout.setHeight(height);
}
}