Showing posts with label multiple selection. Show all posts
Showing posts with label multiple selection. Show all posts

Friday, August 4, 2023

How to select\unselect all records in a form grid

 While adding standard command button you can opt for SelectAll to mark all records in a form grid. However, there is no such a command for the opposite - unselect all records.


You can easily achieve it by using the following method and two usual button form controls.

[Form]
public class myForm extends FormRun
{
    public void selectAll(boolean _select)
    {
        VendPaymFormat_DS.markAllLoadedRecords(_select);
    }

    [Control("Button")]
    class FormButtonControlSelectAll
    {
        public void clicked()
        {
            element.selectAll(true);
            super();
        }
    }

    [Control("Button")]
    class FormButtonControlUnSelectAll
    {
        public void clicked()
        {
            element.selectAll(false);
            super();
        }
    }
}






Saturday, April 9, 2022

Multiple company selection in an SSRS report (LedgerLegalEntityLookup)

If you need to provide an SSRS report with a multiple company selection, you can opt for a cross-company query. In this case, such an option will be maintained by the system automatically. (You can try this [SrsReportQuery(queryStr(LogisticsEntityLocationUnion))])

But what if you need to do that without the former? In this case you'll need to use LedgerLegalEntityLookup class as follows. Say we deal with some mySalesBySegment report, which is meant to return some data for a given selection of legal entities.




I hid some not relevant code; so that you can get the gist.

Data contract mySalesBySegmentContract: we keep the user selection of companies as a string.

[DataContract]
[SysOperationContractProcessing(classstr(mySalesBySegmentUIBuilder), SysOperationDataContractProcessingMode::CreateUIBuilderForRootContractOnly)]

class mySalesBySegmentContract implements SysOperationValidatable
{
    ...
    str                                 legalEntityOptionsStr;
    ...
 
    [
        DataMember('legalEntityOptions')
        ,
        SysOperationGroupMember('Grouping'),
        SysOperationDisplayOrder('5')
    ]
    public str parmLegalEntityOptions(str _legalEntityOptions = legalEntityOptionsStr)
    {
        legalEntityOptionsStr = _legalEntityOptions;

        return legalEntityOptionsStr;
    }

}

Report controller mySalesBySegmentController: if no companies selected, let's set it to the user's context.

public class mySalesBySegmentController extends SrsReportRunController
{
 
    protected void prePromptModifyContract()
    {
        mySalesBySegmentContract   dc = this.parmReportContract().parmRdpContract() as mySalesBySegmentContract;

       ...
        if (!dc.parmLegalEntityOptions())
        {
            // Set the default value for the legal entity selection
            dc.parmLegalEntityOptions(con2str([curExt()]));
        }
    }

   
    protected void preRunModifyContract()
    {
        mySalesBySegmentContract   dc;
        container                   legalEntityOptions;

        dc                  = this.parmReportContract().parmRdpContract() as mySalesBySegmentContract;
        legalEntityOptions  = str2con(dc.parmLegalEntityOptions());

        // Default current company if there were no company specifications provided to the API.
        if (legalEntityOptions == conNull())
        {
            legalEntityOptions = [curExt()];
            dc.parmLegalEntityOptions(con2str(legalEntityOptions));
        }
  
    }

    public static void main(Args _args)
    {
        mySalesBySegmentController controller = new mySalesBySegmentController();

        controller.parmReportName(ssrsReportStr(mySalesBySegment, Report));
        controller.parmArgs(_args);
         controller.startOperation();
    }

}

User interface builder mySalesBySegmentUIBuilder: when an SSRS report runs, it shows its dialog twice: the second time in the report viewer, when the report is rendered. Thus we have to override dialog methods in the UIBuilder class to avoid the lovely 'Object reference not set to an instance of an object' error.

public class mySalesBySegmentUIBuilder extends SrsReportDataContractUIBuilder
{
    mySalesBySegmentContract   dc;
    // Legal entity lookup controls
    FormStringControl           dialogLegalEntitySelection;
    LedgerLegalEntityLookup     legalEntityLookup;
    int                         dialogLegalEntityLookupId;
    str                         userLegalEntityRange;
    container                   legalEntityOptions;

    /// <summary>
    /// Override this method in order to initialize the dialog fields after the fields are built.
    /// </summary>
    public void postBuild()
    {
        DialogField dialogField;

        super();
        // parmCompanySelection
        dialogField = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(mySalesBySegmentContract, parmLegalEntityOptions));
        this.setInVisible(dialogField);

        this.constructLegalEntityControl(dialog);
        
    }

    /// <summary>
    /// post runs
    /// </summary>
    public void postRun()
    {
        super();
        
        this.constructLegalEntityLookup(dialog);
        Set userLegalEntitySet = LedgerSecurityHelper::ledgersWithMinimumSecurityAccess(menuItemActionStr(LedgerExchAdj), AccessRight::Edit, MenuItemType::Action);
        userLegalEntityRange = LedgerLegalEntityLookup::getLegalEntityRangeFromLegalEntitySet(userLegalEntitySet);
    }

    /// <summary>
    /// Contstruct
    /// </summary>
    /// <param name = "_dialog">Dialog</param>
    private void constructLegalEntityControl(Dialog _dialog)
    {
        FormBuildGroupControl currentGroup = _dialog.form().design().control(_dialog.curFormGroup().name());
        FormBuildStringControl dialogLegalEntityLookup = currentGroup.addControl(FormControlType::String, 'LegalEntityLookup');
        dialogLegalEntityLookup.extendedDataType(extendedTypeNum(LedgerLegalEntitySelection));
        dialogLegalEntityLookup.lookupOnly(true);
        dialogLegalEntityLookupId = dialogLegalEntityLookup.id();
    }

    /// <summary>
    /// Constructs the lookup for the legal entity selection.
    /// </summary>
    /// <param name = "_control">The <c>FormStringControl</c> object.</param>
    private void legalEntityLookup(FormStringControl _control)
    {
        legalEntityLookup.lookup(_control.text(), userLegalEntityRange);
    }

    /// <summary>
    /// Lookup override
    /// </summary>
    /// <param name = "_dialog">dialog</param>
    private void constructLegalEntityLookup(Dialog _dialog)
    {
        dialoglegalEntitySelection = _dialog.formRun().design().control(dialogLegalEntityLookupId);
        legalEntityLookup = LedgerLegalEntityLookup::construct(_dialog.formRun(), dialoglegalEntitySelection);
        // populates it from the packed paramater
        legalEntityLookup.setSelection(str2con(dc.parmLegalEntityOptions()));
        // let's have our own lookup
        dialoglegalEntitySelection.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(mySalesBySegmentUIBuilder, legalEntityLookup), this);
    }

    /// <summary>
    /// prebuilds
    /// </summary>
    public void preBuild()
    {
        dc = this.dataContractObject() as mySalesBySegmentContract;
        super();
    }

    /// <summary>
    /// Gets it back from the dialog
    /// </summary>
    public void getFromDialog()
    {
        super();
        dc.parmLegalEntityOptions(con2Str(legalEntityLookup.getLegalEntitySelection()));
    }

}

Report data provider mySalesBySegmentDP: we need just to convert the saved string back to a container, then we can loop through it as required by the report logic.

[SRSReportParameterAttribute(classStr(mySalesBySegmentContract))] 
public class mySalesBySegmentDP extends SRSReportDataProviderPreProcessTempDB
{
    container                       legalEntityOptions;
    
    public void processReport()
    {
        mySalesBySegmentContract        dc;
        List                            legalEntityList;
        ListEnumerator                  legalEntityListEnumerator;
        SelectableDataArea              companyId;
        str                             companyName;

        dc                          = this.parmDataContract() as mySalesBySegmentContract;
     
        this.setUserConnection(tmp);
        
        // getting all selected companies from the report query
        legalEntityList             = con2List(str2con(dc.parmLegalEntityOptions()));
        legalEntityListEnumerator   = legalEntityList.getEnumerator();

        while (legalEntityListEnumerator.moveNext())
        {
            companyId   = legalEntityListEnumerator.current();
            companyName = CompanyInfo::findDataArea(companyId).name();
            changecompany(companyId)
            {
                // Populate the base processing table with data from the appropriate source table
                ...
            }
        }
    }
}

Saturday, December 11, 2021

Multiple enum values selection in forms and tables

Previously I posted three supporting functions to work with multiple enum values selection. Now, let's see how they can be used in real scenarios.

With these functions you can easily expose enum values in selection lists and then save the user selection in tables.

Enum lists in a form

Check first how to show two grids in a form; so that the user could move enum values from one to another.




[Form]
public class SysPolicyTypesOneCompanyActiveOnly extends FormRun
{

    private Map                 policyTypes = wzhTest::createMapForEnum(enumStr(SysPolicyTypeEnum));
    private SysPolicyTypeEnum   type;
 
    private void resetSysPolicyTypeListPanel()
    {
        SysPolicyTypeAvailableGrid.deleteRows(0, SysPolicyTypeAvailableGrid.rows());
        SysPolicyTypeEnabledGrid.deleteRows(0, SysPolicyTypeEnabledGrid.rows());

        var mapEnumerator = policyTypes.getEnumerator();
        while (mapEnumerator.moveNext())
        {
            type        = mapEnumerator.currentKey();
            
            if (SysPolicyTypesOneCompanyActiveOnly::exist(type))
            {
                this.addRowForTypes(SysPolicyTypeEnabledGrid, type);
            }
            else
            {
                this.addRowForTypes(SysPolicyTypeAvailableGrid, type);
            }
        }

        SysPolicyTypeAvailableGrid.row(SysPolicyTypeAvailableGrid.rows() ? 1 : 0);
        SysPolicyTypeEnabledGrid.row(SysPolicyTypeEnabledGrid.rows() ? 1 : 0);
    }

    private int addRowForTypes(FormTableControl _table, SysPolicyTypeEnum _type)
    {
        int i;
        // Insert it into the data set in sorted order.
        for (i = _table.rows(); i >= 1; i--)
        {
            SysPolicyTypeEnum typeIdTmp = _table.cell(1, i).data();
            
            if (strCmp(enum2Str(typeIdTmp), enum2Str(_type)) < 0)
            {
                // We need to insert after the current item.
                break;
            }
        }

        // Insert the new item, i is equal to the index of the item we need to insert after.
        _table.insertRows(i, 1);
        _table.cell(1, i + 1).data(_type);

        return i + 1;
    }
...
}

Multiple enum values in a table

In order to save user's selection of particular Enum values in a table, you can add a string type field there. 

The rest is to convert these selected values from string to a list or a container to present them in a form.

Say, we need to let the user to select particular FiscalPeriodStatus values.



First, we add a new string field FiscalPeriodStatusSelection to our table.


We can show the currently saved selection via a display method

    /// <summary>
    /// Returns Fiscal period statuses string values
    /// </summary>
    /// <param name = "_parm">container</param>
    /// <returns>string values of selected period statuses</returns>
    [SysClientCacheDataMethodAttribute(true)]
    public display LedgerExchAdjFiscalPeriodStatusSelection fiscalPeriodStatusSelectionDisp()
    {
        return wzhTest::enumValuesStr2EnumStrStr(this.FiscalPeriodStatusSelection, enumName2Id(enumStr(FiscalPeriodStatus)));
}

And updates this field via AnotherClass which treats the user's selection (in a form, for example)

    this.FiscalPeriodStatusSelection = con2Str(AnotherClass.getFiscalPeriodStatusSelectionCont(), wzhTest::ContSeparator);

    /// <summary>
    /// Gets FiscalPeriodStatus selection as a container
    /// </summary>
    /// <returns>container</returns>
    public container getFiscalPeriodStatusSelectionCont()
    {
        container                               cont;
        
        while (...)
        {
            cont += SomeBufferOrList.FiscalPeriodStatus;
        }
                
        return cont;
    }