sah4ez/erp_vaadin_framework

View on GitHub
core/src/main/java/com/github/sah4ez/core/elements/CrossTable.java

Summary

Maintainability
B
4 hrs
Test Coverage
package com.github.sah4ez.core.elements;

import com.github.sah4ez.core.data.CellCondition;
import com.github.sah4ez.core.data.Condition;
import com.github.sah4ez.core.data.DataContainer;
import com.github.sah4ez.core.data.Entity;
import com.vaadin.data.Item;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.ui.CustomTable;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.function.BiFunction;

/**
 * Created by aleksandr on 06.01.17.
 */
abstract public class CrossTable extends Workspace {

    private DataContainer<? extends Entity> firstContainer;
    private DataContainer<? extends Entity> secondContainer;
    private String idFirst = "";
    private String idSecond = "";
    private String captionSecond = "";
    private String captionFirst = "";
    private SelectionModeCrossTable selectionModeCrossTable = SelectionModeCrossTable.SINGLE_CELL;
    private HashMap<Item, HashMap<String, CellCondition>> selectedCell = new HashMap<>();

    public CrossTable(Logic logic, String identify, DataContainer<? extends Entity> firstContainer, DataContainer<? extends Entity> secondContainer) {
        super(logic, identify);
        this.firstContainer = firstContainer;
        this.secondContainer = secondContainer;
        this.getTable().setFilterBarVisible(false);
        getTable().setColumnCollapsingAllowed(true);
        getTable().addItemClickListener(selectionModeListener());
    }

    public DataContainer<? extends Entity> getFirstContainer() {
        return firstContainer;
    }

    public void setFirstContainer(DataContainer<? extends Entity> firstContainer) {
        this.firstContainer = firstContainer;
    }

    public DataContainer<? extends Entity> getSecondContainer() {
        return secondContainer;
    }

    public void setSecondContainer(DataContainer<? extends Entity> secondContainer) {
        this.secondContainer = secondContainer;
    }

    public void createData(String idFirst, String captionFirst, String idSecond, String captionSecond) {
        this.idFirst = idFirst;
        this.captionFirst = captionFirst;
        this.idSecond = idSecond;
        this.captionSecond = captionSecond;
        CustomTable table = getTable();

        table.setSelectable(false);
        table.setImmediate(true);
        table.setNullSelectionAllowed(true);
        table.setSortEnabled(false);
        table.setSizeFull();

        table.addContainerProperty(idFirst,
                Object.class,
                "0",
                "ID",
                null,
                CustomTable.Align.CENTER);
        table.addContainerProperty(captionFirst,
                Object.class,
                "0",
                "Название",
                null,
                CustomTable.Align.CENTER);

        table.removeAllItems();

        initColumns();

        initRows();

        if (getTable().getCellStyleGenerator() == null) {
            getTable().setCellStyleGenerator(cellStyleGenerator());
        }
    }

    private void initColumns() {
        CustomTable table = getTable();
        if (secondContainer.size() == 0) secondContainer.loadAllData();
        secondContainer.stream().forEach(o -> {
            try {
                Field id = o.getClass().getDeclaredField(idSecond);
                Field caption = o.getClass().getDeclaredField(captionSecond);
                id.setAccessible(true);
                caption.setAccessible(true);
                table.addContainerProperty(id.get(o).toString(),
                        Object.class,
                        "0",
                        caption.get(o).toString(),
                        null,
                        CustomTable.Align.CENTER);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }

    private void initRows() {
        CustomTable table = getTable();
        if (firstContainer.size() == 0) firstContainer.loadAllData();

        if (secondContainer.size() == 0) secondContainer.loadAllData();

        firstContainer.stream().forEach(o -> {
            Object getItemId = table.addItem();
            Item row = table.getItem(getItemId);
            String id = getValueProperty(o, idFirst);

            row.getItemProperty(idFirst).setValue(id);
            row.getItemProperty(captionFirst).setValue(getValueProperty(o, captionFirst));

            row.getItemPropertyIds().stream().skip(2)
                    .forEach(s -> row.getItemProperty(s).setValue(getCell(id, s)));

        });
    }

    private String getValueProperty(Object object, String property) {
        String result = "";
        try {
            Field field = object.getClass().getDeclaredField(property);
            field.setAccessible(true);
            result = field.get(object).toString();
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    private CustomTable.CellStyleGenerator cellStyleGenerator() {
        return (CustomTable.CellStyleGenerator) (customTable, itemId, property) -> {
            if (customTable == null || itemId == null || property == null) return null;

            String result = null;
            Object value = customTable.getItem(itemId).getItemProperty(property).getValue();
            if (value != null && value instanceof CellCondition) {
                result = ((CellCondition) value).getCssStyle();
            }
            return result;
        };
    }

    public abstract CellCondition getCell(Object idRow, Object idColumn);

    public void setSelectionModeCrossTable(SelectionModeCrossTable mode) {
        selectionModeCrossTable = mode;
    }

    public SelectionModeCrossTable getSelectionModeCrossTable() {
        return selectionModeCrossTable;
    }

    private ItemClickEvent.ItemClickListener selectionModeListener() {
        return this::actionSelectionMode;
    }

    protected void actionSelectionMode(ItemClickEvent itemClickEvent) {
        CustomTable table = ((CustomTable) itemClickEvent.getSource());
        Item item = itemClickEvent.getItem();
        Object property = itemClickEvent.getPropertyId();


        if (table == null || item == null || property == null) return;

        if (!(item.getItemProperty(property).getValue() instanceof CellCondition)) return;

        switch (selectionModeCrossTable) {
            case MULTI_CELL_IN_ROW: {
                multiCellInRowAction(item, property);
                break;
            }
            case MULTI_CELL_IN_COLUMN: {
                multiCellInColumnAction(item, property);
                break;
            }
            case MULTI_CELL: {
                multiCellAction(item, property);
                break;
            }
            default: {
                singleAction(item, property);
                break;
            }
        }
    }

    private void multiCellInRowAction(Item item, Object property){
        if (contains(item, property)) {
            setPrevValue(item, property);
            remove(item, property);
        } else if (selectedCell.containsKey(item)) {
            saveCurrentValue(item, property);
        } else if (selectedCell.isEmpty()) {
            addItemToSelected(item, property);
        }
    }

    private void multiCellInColumnAction(Item item, Object property){
        if (contains(item, property)) {
            setPrevValue(item, property);
            remove(item, property);
        } else if (!selectedCell.containsKey(item) && !selectedCell.isEmpty()) {
            HashMap p = selectedCell.values().stream().findFirst().orElseGet(HashMap::new);
            if (p.keySet().contains(property)){
                addItemToSelected(item, property);
            }
        } else if (selectedCell.isEmpty()){
            addItemToSelected(item, property);
        }
    }

    private void multiCellAction(Item item, Object property){
        if (contains(item, property)) {
            setPrevValue(item, property);
            remove(item, property);
        }else if (!selectedCell.containsKey(item) || selectedCell.isEmpty()) {
            addItemToSelected(item, property);
        } else {
            saveCurrentValue(item, property);
        }
    }

    private void singleAction(Item item, Object property){
        if (contains(item, property)) {
            clearSelect();
        } else {
            if (selectedCell.size() > 0) {
                clearSelect();
            }
            addItemToSelected(item, property);
        }
    }

    private boolean contains(Item item, Object property){
        return selectedCell.containsKey(item) && selectedCell.get(item).containsKey(property);
    }

    private void remove(Item item, Object property){
        selectedCell.get(item).remove(property);
        if (selectedCell.get(item).isEmpty()) {
            selectedCell.remove(item);
        }
    }

    private void setPrevValue(Item item, Object property){
        CellCondition value = selectedCell.get(item).get(property);
        item.getItemProperty(property).setValue(value);
    }

    private void saveCurrentValue(Item item, Object property){
        selectedCell.get(item).put(property.toString(),
                ((CellCondition) item.getItemProperty(property).getValue()));
        item.getItemProperty(property).setValue(Condition.EDIT);
    }

    private void addItemToSelected(Item item, Object property){
        selectedCell.put(item, new HashMap<>());
        saveCurrentValue(item, property);
    }

    private void clearSelect() {
        selectedCell.forEach((item, property) -> property.forEach((cell, value) -> item.getItemProperty(cell).setValue(value)));
        selectedCell.clear();
    }

    public void changeSelectedCellCondition(CellCondition condition) {
        BiFunction<String, CellCondition, CellCondition> function = (s, cellCondition) -> condition;

        selectedCell.forEach((item, property) -> property.replaceAll(function));
    }
}