Create editable table with LookupFields insted of PickerFields for entities

Hello,
I’m trying to create editable group table with editable=“true” in table and columns. Every new entity is copy of last inputed entity. This entities can be edited and then whole table is committed.
I tried to do this on 7.0.3, but it did not work. I updated CUBA to 7.0.6 . After update it works as intended.

But now I need to change default PickerFields to LookupPickerFields (or to LookupFields). So to replace PickerFields columns created by CUBA I set generators with LookupPickerFields on columns.
And it not working again. There no Picker action in fields i geting, only Lookups and data inputed from UI do not transfers to entities in collection data container.
How can I fix this?

import com.company.pmsinspectionmodule.entity.*;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.gui.UiComponents;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.data.options.ContainerOptions;
import com.haulmont.cuba.gui.components.data.value.ContainerValueSource;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.screen.*;
import com.haulmont.cuba.gui.screen.LookupComponent;

import javax.inject.Inject;
import java.util.*;

@UiController("pmsinspectionmodule_ShippedOrder.manualInputScreen")
@UiDescriptor("shipped-order-ManualInputScreen.xml")
@LookupComponent("shippedOrdersTable")
@LoadDataBeforeShow
public class ShippedOrderBrowseManualInputScreen extends StandardLookup<ShippedOrder> {

    @Inject
    private CollectionContainer<ShippedOrder> shippedOrdersDc;

    @Inject
    private CollectionContainer<Specifications> specificationsesDc;

    @Inject
    private CollectionContainer<ContractProducts> contractProductsesDc;

    @Inject
    private CollectionContainer<Company> companiesDc;

    @Inject
    private CollectionContainer<Product> productsDc;

    @Inject
    private CollectionLoader<Product> productsDl;

    @Inject
    private CollectionContainer<MTR> mTRsDc;

    @Inject
    private CollectionLoader<MTR> mTRsDl;

    @Inject
    private DataManager dataManager;

    @Inject
    private UiComponents uiComponents;

    private Map<String, Product> productMap;
    private Map<String, MTR> mtrMap;


    @Subscribe
    private void onBeforeShow(BeforeShowEvent event) {
        productMap = initProductCodeMap();
        mtrMap = initMTRCodeMap();
    }

    @Subscribe
    private void onAfterShow(AfterShowEvent event) {
        shippedOrdersDc.setItems(new ArrayList<>());
    }

    @Subscribe("shippedOrdersTable.addLine")
    private void onShippedOrdersTableAddLine(Action.ActionPerformedEvent event) {
        if(shippedOrdersDc.getItems()==null||shippedOrdersDc.getItems().size()==0){
            shippedOrdersDc.getMutableItems().add(dataManager.create(ShippedOrder.class));
        }else {
            shippedOrdersDc.getMutableItems().add(getLastItem());
        }
    }

    private ShippedOrder getLastItem(){
        ShippedOrder shippedOrder = dataManager.create(ShippedOrder.class);
        ShippedOrder shippedOrderTemp = shippedOrdersDc.getItems().get(shippedOrdersDc.getItems().size()-1);

        shippedOrder.setProduct(shippedOrderTemp.getProduct());
        shippedOrder.setSpecification(shippedOrderTemp.getSpecification());
        shippedOrder.setActualAmount(shippedOrderTemp.getActualAmount());
        shippedOrder.setDefect(shippedOrderTemp.getDefect());
        shippedOrder.setProviderFact(shippedOrderTemp.getProviderFact());
        shippedOrder.setMtr(shippedOrderTemp.getMtr());
        shippedOrder.setShippment(shippedOrderTemp.getShippment());

        return shippedOrder;
    }


    public Component generateProviderCell(ShippedOrder entity){
        LookupPickerField<Company> lookupPickerField = uiComponents.create(LookupPickerField.of(Company.class));
        lookupPickerField.setValueSource(new ContainerValueSource<>(shippedOrdersDc,"providerFact"));
        lookupPickerField.setOptions(new ContainerOptions<>(companiesDc));
        return lookupPickerField;
    }

    public Component generateProductCell(ShippedOrder entity){
        LookupPickerField<Product> lookupPickerField = uiComponents.create(LookupPickerField.of(Product.class));
        lookupPickerField.setValueSource(new ContainerValueSource<>(shippedOrdersDc,"product"));
        lookupPickerField.setOptionsMap(productMap);
        return lookupPickerField;
    }

    public Component generateSpecificationCell(ShippedOrder entity){
        LookupPickerField<Specifications> lookupPickerField = uiComponents.create(LookupPickerField.of(Specifications.class));
        lookupPickerField.setValueSource(new ContainerValueSource<>(shippedOrdersDc,"specification"));
        lookupPickerField.setOptions(new ContainerOptions<>(specificationsesDc));
        return lookupPickerField;
    }

    public Component generateMTRCell(ShippedOrder entity){
        LookupPickerField<MTR> lookupPickerField = uiComponents.create(LookupPickerField.of(MTR.class));
        lookupPickerField.setValueSource(new ContainerValueSource<>(shippedOrdersDc,"mtr"));
        lookupPickerField.setOptionsMap(mtrMap);
        return lookupPickerField;
    }

    public Component generateContractProductCell(ShippedOrder entity){
        LookupPickerField<ContractProducts> lookupPickerField = uiComponents.create(LookupPickerField.of(ContractProducts.class));
        lookupPickerField.setValueSource(new ContainerValueSource<>(shippedOrdersDc,"shippment"));
        lookupPickerField.setOptions(new ContainerOptions<>(contractProductsesDc));
        lookupPickerField.setValue(entity.getShippment());
        return lookupPickerField;
    }

    private Map<String, Product> initProductCodeMap(){
        Map <String, Product> map = new HashMap<>();
        productsDl.load();
        for(Product product : productsDc.getItems()){
            map.put(product.getCode(),product);
        }
        return map;
    }

    private Map<String, MTR> initMTRCodeMap(){
        Map<String,MTR> map = new HashMap<>();
        mTRsDl.load();
        for (MTR mtr : mTRsDc.getItems()){
            map.put(mtr.getCode(),mtr);
        }
        return map;
    }
}
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="msg://browseCaption"
        focusComponent="shippedOrdersTable" messagesPack="com.company.pmsinspectionmodule.web.shippedorderManualInput">
    <data>
        <collection id="shippedOrdersDc" class="com.company.pmsinspectionmodule.entity.ShippedOrder"
                    view="shippedOrder-view">
            <loader id="shippedOrdersDl">
                <query><![CDATA[select e from pmsinspectionmodule_ShippedOrder e]]></query>
            </loader>
        </collection>
        <collection id="companiesDc" class="com.company.pmsinspectionmodule.entity.Company">
            <loader id="companiesDl">
                <query><![CDATA[select e from pmsinspectionmodule$Company e]]></query>
            </loader>
        </collection>
        <collection id="productsDc" class="com.company.pmsinspectionmodule.entity.Product">
            <loader id="productsDl">
                <query><![CDATA[select e from pmsinspectionmodule$Product e]]></query>
            </loader>
        </collection>
        <collection id="mTRsDc" class="com.company.pmsinspectionmodule.entity.MTR">
            <loader id="mTRsDl">
                <query><![CDATA[select e from pmsinspectionmodule_CodeMTR e]]></query>
            </loader>
        </collection>
        <collection id="specificationsesDc" class="com.company.pmsinspectionmodule.entity.Specifications">
            <loader id="specificationsesDl">
                <query><![CDATA[select e from pmsinspectionmodule$Specifications e]]></query>
            </loader>
        </collection>
        <collection id="contractProductsesDc" class="com.company.pmsinspectionmodule.entity.ContractProducts">
            <loader>
                <query><![CDATA[select e from pmsinspectionmodule$ContractProducts e]]></query>
            </loader>
        </collection>
    </data>
    <dialogMode height="600" width="800"/>
    <layout expand="shippedOrdersTable" spacing="true">
        <groupTable id="shippedOrdersTable" width="100%" dataContainer="shippedOrdersDc" editable="true"
                    reorderingAllowed="false">
            <actions>
                <action id="addLine" caption="msg://createBtn" icon="FILE_O" shortcut="Insert"/>
                <action id="refresh" type="refresh"/>
                <action id="remove" type="remove"/>
                <action id="excel" type="excel"/>
            </actions>
            <columns>
                <column id="providerFact" editable="true" caption="msg://provider" generator="generateProviderCell"/>
                <column id="specification.contract.contractRSN" collapsed="true"/>
                <column id="specification.contract.typeOfPril" collapsed="true" caption="msg://typePril"/>
                <column id="specification.contract.cipher" collapsed="true" caption="msg://contractCipher"/>
                <column id="product.code" collapsed="true" caption="msg://productionCode"/>
                <column id="product" editable="true" caption="msg://productionName" generator="generateProductCell"/>
                <column id="specification.customer" collapsed="true"/>
                <column id="specification" editable="true" caption="msg://numberOfSpecification"
                        generator="generateSpecificationCell"/>
                <column id="specification.contract.typeOfInspectionControl" collapsed="true"/>
                <column id="actualAmount" editable="true" caption="msg://countBEI"/>
                <column id="product.baseUnit" collapsed="true"/>
                <column id="mtr" editable="true" generator="generateMTRCell"/>
                <column id="mtr.code" editable="true" caption="msg://mtrCode"/>
                <column id="defect" editable="true"/>
                <column id="shippment" editable="true" generator="generateContractProductCell"/>
                <column id="shippment.typeOfShipment" collapsed="true" caption="msg://typeOfShipment"/>
                <column id="shippment.numberRO" collapsed="true"/>
                <column id="shippment.dateRO" collapsed="true"/>
            </columns>
            <rowsCount/>
            <buttonsPanel id="buttonsPanel" alwaysVisible="true">
                <button id="addLineBtn" action="shippedOrdersTable.addLine"/>
                <button id="removeBtn" action="shippedOrdersTable.remove"/>
                <button id="excelBtn" caption="msg://excelBtn" icon="EXCEL_ACTION"/>
            </buttonsPanel>
        </groupTable>
    </layout>
</window>

Hi,

Inspecting your code I found that you use a collection container used by a table to create a value source for a LookupPickerField and that is incorrect. InstanceContainer for a field must be obtained from the table.

InstanceContainer<Foo> instanceContainer = table.getInstanceContainer(entity);

As for the second problem, in order to have certain actions in a LookupPickerField you need to add them explicitly.

Action lookupAction = actions.create(LookupAction.ID);
field.addAction(lookupAction);

Putting all together we get the following:

@Inject
private Table<OrderLine> linesTable;
@Inject
private UiComponents uiComponents;
@Inject
private Actions actions;

public Component productGenerator(OrderLine entity) {
    LookupPickerField<Product> field = uiComponents.create(LookupPickerField.of(Product.class));

    // InstanceContainer must be obtained from the table
    InstanceContainer<OrderLine> instanceContainer = linesTable.getInstanceContainer(entity);
    field.setValueSource(new ContainerValueSource<>(instanceContainer, "product"));
    
    // Explicitly add required actions
    Action lookupAction = actions.create(LookupAction.ID);
    field.addAction(lookupAction);
    
    // Provide additional settings 

    field.setValue(entity.getProduct());

    return field;
}

Regards,
Gleb

1 Like