Form

Form with filters
Init form
Init Test Menu Item
Args with caller
Init dataSource
formHasMethod
Refresh
cacheAddMethod
ModifyField call
Modify field, order : Form, DS, Table
Modify field - enabled - disable
Modify field - enabled - disable in the table !
Get or set value of a control
controlName
Get control or a button in a form without autodeclaration
Edit method
Edit method replace code -> name
MenuFunction
MenuFunction, call the class directly
MenuFunction, example with parm
Call form by form Name with wait
Call form by form Name with wait and test if OK
Call a menuItem by adding a DS delay in the form - Do the LinkActive
Splitter
Field color
Show the column of selection in the grid
Display method in a form
Join dataSource on DS with group by
Form with pack unpack
Form with tmpFrmVirtual
Form Master - detail
Reference Datasource
Run - sum from dataSource
Close , canClose
Icone in a grid
Prompt in run
Call a dialog and refresh the form
JumpRef - Go to main table

Form with filters


public class FormRun extends ObjectRun
{
	QueryBuildRange qbrDlvDate;
}
public void dateModified()
{
	date fromDate, toDate;
	fromDate = fomDateHeader.dateValue();
	toDate   = toDateHeader.dateValue();
	if (!toDateHeader.dateValue())
		toDate = dateMax();
	qbrDlvDate.value(queryRange(fromDate,toDate));
}
public void refreshGrid()
{
	ProdTable_ds.executeQuery();
}
public void init() // (Init of the data source ProdTable_ds)
{
	QueryBuildDataSource qbds;
	QueryBuildRange      qbr;
	date				 fromDate,toDate;
	
	super();
	qbds 	= this.query().dataSourceName(this.name());
	qbds.addSortField(fieldNum(ProdTable,Prod),SortOrder::Descending);
    // To have a small range and not see a lot of lines
	fromDateHeader.dateValue(systemDateGet() - 1);
	toDateHeader.dateValue(systemDateGet());
	fromDate = fromDateHeader.dateValue();
	toDate   = toDateHeader.dateValue();
	qbrDlvDate = qbds.addRange(fieldNum(ProdTable,DlvDate));
	qbrDlvDate.value(queryRange(fromDate,toDate));
}
public boolean modified() // (field dateEdit fromDateHeader)
{
	boolean ret;
	ret = super();
	element.dateModified();
	return ret;
}
public boolean modified() // (field dateEdit toDateHeader)
{
	boolean ret;
	ret = super();
	element.dateModified();
	return ret;
}

Init form

Init()
{
    FormRun               callerForm;
    SalesLine             callerSalesLine;
    FormDataSource        callerDataSource;
	//------------TEST ARGS---------------------------
    if (!element.args()     ||
        !element.args().record().TableId)
    {
         throw error("@SYS22539");
    }
    if (! element.args().caller() || ! element.args().record())
       throw error("@SYS22539");

	if (!element.args().caller())
    {
        // Form cannot be called directly.
        throw error("@SYS96590");
    }

    if(element.args().parmEnumType() == enumnum(CurrentOperationsTax))
    {
        currentOperationsTax = element.args().parmEnum();
        selectCurrentOperationsTax = true;
    }
    else
    {
        selectCurrentOperationsTax = false;
    }

    if (element.args().dataset() == tablenum(WMSShipment))
    {
        wmsShipment = element.args().record();
    }

    callerForm          = element.args().caller();
    callerSalesLine     = element.args().record();
    callerDataSource    = element.args().record().dataSource();

    super(); //the super() method call the init of the dataSource
}


//Interesting example : SmmOpportunityStatusUpdate (parm with 2 values with ;)
    // Get value of ReasonId and CustAccount # from args.parm()
    container                   parms;
	;
	
    parms = str2con(args.parm(), ";");   //   ==========================

    if (conLen(parms) != 2)
    {
        throw error(strFmt("@SYS54195",funcName()));
    }

    smmOpportunityStatusUpdate.parmReasonId(conPeek(parms, 1));
    smmOpportunityStatusUpdate.paramCustAccountNo(conPeek(parms, 2));
    smmOpportunityStatusUpdate.parmRemoveOpenActivities(args.refField());

// Another example
	FormRun callerForm;
    if (!element.args().caller() || !element.args().dataset())
        throw error(strfmt("@SYS22678",element.name()));
    callerForm  = element.args().caller();
	if (callerForm.name() == formStr(InventTableListPage))
        InventTableDrag_ds.executeQuery();
// Another example to test if the caller is a form
if (SysDictClass::is(element.args().caller(), classnum(FormRun)))
{
	parentForm = element.args().caller();
    // Cast the caller and make sure it is the right form.
    if (parentForm.name() == formstr(AifValueSubstitutionComponentConfig))
}


// Another example to test !!!!!!!!!!!!!!!!!!!!!!!!!!!
    Object caller;

    if (bomVersion.bomId)
        return bomVersion.bomId;
    else
    {
        caller = element.args().caller();
        if (caller)
        {
            if (SysDictClass::isEqualOrSuperclass(classidget(caller),classnum(FormRun)))
            {
                if (formHasMethod(caller,identifierstr(bomId)))
                    return caller.bomId();
            }
            else
            {
                return caller.bomId();
            }
        }
    }

Init Test Menu Item

Init()
{
	switch (element.args().menuItemName())
    {
        case menuitemdisplaystr(SPLPsGasNominationWeekly):
            isWeek = true;
            break;

        default:
            isWeek = false; //(monthly)
    }

    super(); //the super() method call the init of the dataSource
}

Args with caller

Init()
{
    FormRun               callerForm;
    SalesLine             callerSalesLine;
    FormDataSource        callerDataSource;

	//in the called form we twat from what form we are coming
	if (args.dataset() == tablenum(BankAccountTrans) && args.caller().name() == formstr(BankReconciliation))
	{
	}	

    super(); //the super() method call the init of the dataSource
}

//In the caller
void clicked()
{
    Args args;
    ;

    args = new Args();
    args.caller(element);
...
}

Init dataSource

//For a form in innerjoin use link
//For a form in DELAY     use dynaLink
void init()
{
    QueryBuildDataSource qbds;

    super();
    qbds = this.query().dataSourceTable(tablenum(InventDim)); 			
    //qbds = this.query().dataSourceName(this.name()); 			
    //qbds = this.query().dataSourceName(identifierstr(InventDimTransTo)); 	//if the name is not InventDim
    qbds.clearLinks();
    qbds.addLink(fieldnum(WMSOrderTrans,ToInventDimId),fieldnum(InventDim,InventDimId));
}

// Init : We put the display method in the cache
public void init()
{
    super();

    salesTable_ds.cacheAddMethod(tableMethodStr(SalesTable, customerName));
    salesTable_ds.cacheAddMethod(tableMethodStr(SalesTable, invoiceName));
    if (enableDirectedSelling)
    {
        salesTable_ds.cacheAddMethod(tableMethodStr(SalesTable, editContactPersonName));
    }
}

formHasMethod

void updateCallerForm()
{
    if (element.args() && element.args().caller() && formHasMethod(element.args().caller(), identifierstr(updateAddress)))
    {
        element.args().caller().updateAddress();
    }
}

Refresh

	Research : keep the filters but don't do the edit methods. (research on all the DS)
	Refresh  : refresh the line of the DS but don't do the edit methods. (refresh on one line)

// the refresh is use to show the modification of the DS.
// In our exemple, we cahnge a value of a field in a button,
// and we need the refresh to see the new value on the grid !
// The refresh doesn't read in the Table, the reread read in the table !	



cacheAddMethod

//Init of the DS
public void init()
{
	super();
	this.cacheAddMethod(tablemethodstr(CustBillOfExchangeJour, bankRemittanceFileId));
}

ModifyField call

    inventTable.modifiedField(fieldnum(InventTable,pbaAutoStart));
    inventTable_ds.refresh();

Modify field, order : Form, DS, Table

// When modify, first the modify of the field is called.
The field call the super of the modify of the field in the DS,
The modify field of the data source call the super of the table :
==>
Infos	Message (11:57:52)	modify field level 3 form
Infos	Message (11:57:52)	modify field level 2 DS
Infos	Message (11:57:52)	modify field level 1 (table)

// Field in the form
public boolean modified()
{
    boolean ret;

    info("modify field level 3 form");
    ret = super();

    return ret;
}

public void modified()
{
    info("modify field level 2 DS");
    super();
    element.setFieldVisible();
}
// Same field in the Table.
	case fieldNum(SMAServiceOrderTable, SPLWasteQuotationType) :
		this.CustAccount = "";
		this.SPLWasteBusRelAccount = "";
		info("modify field level 1 (table)");
		break;


Modify field - enabled - disable

Table
Form
// We want that when we the field Approval is checked, the field user group is enable, other else the field is disable.
// In the table  : 
public void modifiedField(fieldId _fieldId)
{
    super(_fieldId);

    //15-02-2016-SBE-BEGIN
    switch (_fieldId)
    {
        case fieldNum(InventJournalName,SPLIsNeedApproval) :
            if (!this.SPLIsNeedApproval)
                this.SPLApprovalUserGroupId = "";  // === Set blank, because the field will be disable !
            break;
    }
    //15-02-2016-SBE-END
}
public boolean validateWrite()
{
    boolean ret;

    ret = super();

    //15-02-2016-SBE-BEGIN
    if (ret)
    {
        if (this.SPLIsNeedApproval)
        {
            if (!this.SPLApprovalUserGroupId)
            {
				// the field %1 is mandatory
                ret = checkFailed(strfmt("@SYS84378",fieldpname(InventJournalName,SPLApprovalUserGroupId)));
            }
        }
        else if (this.SPLApprovalUserGroupId)
        {
			// the field %1 must be empty
            ret = checkFailed(strfmt("@SPL1979",fieldpname(InventJournalName,SPLApprovalUserGroupId)));
        }
    }
    //15-02-2016-SBE-END

    return ret;
}
// In the form  : 
public int active()
{
    int ret;

    ret = super();

    //15-02-2016-SBE-BEGIN
    InventJournalName_ds.object(fieldnum(InventJournalName, SPLApprovalUserGroupId)).allowEdit(InventJournalName.SPLIsNeedApproval);
    //15-02-2016-SBE-END

    return ret;
}
public void modified()
{
    super();
    InventJournalName_ds.object(fieldnum(InventJournalName, SPLApprovalUserGroupId)).allowEdit(InventJournalName.SPLIsNeedApproval);
}

Modify field - enabled - disable in the table !

// In the field of the form
public void modified()
{
    super();
    element.setInventDimId();
    element.setAvailFields();
}
void setAvailFields()
{
    Common      callerRecord;
    ;
    if (element.args() && element.args().record() && element.args().record().RecId)
    {
        callerRecord = element.args().record();
    }
    inventNonConformanceTable.setEditableFields(inventNonConformanceTable_ds, callerRecord);
}
// In the table  : 
/// 
/// Update the form showing this data so reference fields are properly enabled or disabled.
/// 
/// 
/// The form data source for this table.
/// 
/// 
/// The record passed in a as caller when creating a new record.
/// 
client void setEditableFields(FormDataSource _inventNonConformanceTable_ds, Common _callerRecord)
{
    boolean     modifyReference = true;
    boolean     showReference   = true;

    boolean fixCallerReference()
    {
        if (!_callerRecord.RecId)
        {
            return false;
        }

        switch (_callerRecord.TableId)
        {
            case (tablenum(SalesLine))                  :
            case (tablenum(PurchLine))                  :
            case (tablenum(ProdTable))                  :
            case (tablenum(InventQuarantineOrder))      :
            case (tablenum(InventQualityOrderTable))    :
            case (tablenum(InventBatch))                :
            case (tablenum(InventTable))                :
                return true;
        }
        return false;
    }
    ;

    if (this.InventNonConformanceType == InventNonConformanceType::Internal &&
        _callerRecord.RecId &&
        _callerRecord.TableId == tablenum(InventBatch))
        showReference = false;

    modifyReference = !fixCallerReference();

    _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventNonConformanceType)).allowEdit(modifyReference);
    _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, ItemId)).allowEdit(modifyReference);
    _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable,Rush)).allowEdit(this.InventNonConformanceType == InventNonConformanceType::Vend);
    _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable,InventTestInfoStat)).allowEdit(this.RecId && !this.correctionsExist());



    if (showReference || this.RecId)
    {
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventRefId)).allowEdit(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).allowEdit(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).allowEdit(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).allowEdit(modifyReference);
    }
    else
    {
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventRefId)).visible(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).visible(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).visible(modifyReference);
        _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).visible(modifyReference);
    }

    switch(this.InventNonConformanceType)
    {
        case InventNonConformanceType::Cust:
        case InventNonConformanceType::Service:
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).allowEdit(modifyReference);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).allowEdit(modifyReference);
            break;
        case InventNonConformanceType::Vend:
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).allowEdit(modifyReference);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).allowEdit(modifyReference);
            break;
        case InventNonConformanceType::Production:
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).allowEdit(false);
            break;
        case InventNonConformanceType::Internal:
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, CustAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, VendAccount)).allowEdit(false);
            _inventNonConformanceTable_ds.object(fieldnum(InventNonConformanceTable, InventTransIdRef)).allowEdit(modifyReference);
            break;
    }
}

Get or set value of a control

// do Autodeclaration 
//String edit : StringEditAuto.text("valueText");

controlName

	this.design().controlName('ProposalForDimension').enabled(false);
	//comboBox
    this.getEditText()); //value of the comboBox
	//StringEdit
    SPLWMSLocCustomer.text(wmsLocationSPL.SPLCustAccount); //set value for a string edit.


Get control or button in a form without autodeclaration

// my control name is "AccountNum" and form name is "FormAddress"
// The control:: enum enumerates all controls on the given form
element.control(control::AccountNum).enabled(false);  //2009

In Dynamics AX 2012, we have a new method controlId() on the formRun class.
This in conjunction with the new intrinsic method formControlStr() can be used to get the control id.

element.control(element.controlId(formControlStr(FormAddress, AccountNum))).enabled(false);
 
// to check it we do element.control(element.controlId(formControlStr(FormAddress, AccountNum))).tostring() -> give the control class ex checkboxformcontrol : to check it 

//To do a button enable, disable, Convert2CustomerCtrl is the name of the button without autodeclaration
element.design().controlName(identifierStr(Convert2CustomerCtrl)).enabled(enableCustomer);



edit method

public edit LPLSalesDealId LPLEditSalesDealId(
    boolean _set,
    LPLSalesDealId _LPLSalesDealId)
    
{
    if (_set)
    {
       if (_LPLSalesDealId && LPLSalesDealTable::exist(_LPLSalesDealId) )
       {
            if (this.LPLSalesDealLineRecid == 0)
            {
                this.LPLSalesDealId = "";
                info("@LPL1820");
            }
        }
        else
        {
            this.LPLSalesDealId = "";
            this.LPLSalesDealLineRecid = 0;
        }
    }
    return  this.LPLSalesDealId;
}

public edit SPLLineNumPair SPLEditLineNumPair(
    boolean _set,
    SPLLineNumPair _SPLLineNumPair
    )
{
    if (_set)
    {
		if (_SPLLineNumPair /*&& LPLSalesDealTable::exist(_LPLSalesDealId)*/ )
		{
            this.SPLLineNumPair = _SPLLineNumPair;
        }
        else
        {
            this.SPLLineNumPair = 0;
        }
    }
    return  round(this.SPLLineNumPair,0.01);
}

Edit method replace code -> name

Edit
public void jumpRef()
{
    salesTable_ContactPersonId.jumpRef();
}
void lookup()
{
    ContactPerson::lookupCustContactPerson(salesTable_contactPersonId,
                                           salesTable.CustAccount,
                                           this,
                                           salesTable.ContactPersonId);
}
client server edit ContactPersonName  editContactPersonName(boolean _set, ContactPersonName _name)
{
    ContactPersonName   name = _name;
    ContactPerson       contactPerson;
    DirPartyTable       partyTable;
    ContactPersonId     contactPersonId;

    if (_set)
    {
        if (name)
        {
            contactPersonId = this.ContactPersonId;
            contactPerson = ContactPerson::find(_name);
            this.ContactPersonId = contactPerson.ContactPersonId;
            if (this.ContactPersonId)
            {
                name = contactPerson.personName();
            }
            else
            {
                select contactPerson
                        where contactPerson.CustAccount ==   this.CustAccount
                    join Name from partyTable
                        where partyTable.RecId == contactPerson.Party &&
                              partyTable.Name        like name;
                if (contactPerson)
                {
                    this.ContactPersonId=contactPerson.ContactPersonId;
                    name=partyTable.Name;
                }
            }
            if (contactPersonId != this.ContactPersonId)
            {
                if (this.checkContactPerson())
                {
                    this.initFromContactInfo();
                    if (this.dataSource())
                    {
                        this.dataSource().refresh();
                    }
                }
                else
                {
                    this.ContactPersonId = contactPersonId;
                }

            }
        }
        else
        {
            this.ContactPersonId='';
        }
    }
    else
    {
        name = this.contactPersonName();
    }

    return name;
}

MenuFunction

clicked()
{
    MenuFunction menuFunction;
    Args args = new Args();
    ;
    //The menu is called with "Parameters"
    menuFunction = new MenuFunction(menuitemactionstr(AssetCalendarCreateYear), MenuItemType::Action);
    args.parm(calId);
    menuFunction.run(args);

    //The menu is called with a record
    args.record(custInvoiceJour);
    new MenuFunction(menuitemactionstr(InterCompanyTransferInventDim), MenuItemType::Action).run(args);

    args.caller(element);
    args.parmObject(purchParmLine_ds.queryRun().query());

    //args.parmEnumType(enumnum(FormOpenMode));  //In all call of the nenuItem we don't need a parmEnumType
    args.parmEnum(FormOpenMode::ForNew);

    args.object(ledgerJournalEngine); //(for a class ?)
}
//for a display form, use identifierstr
    menuFunction = new MenuFunction(identifierstr(InventOnhand), MenuItemType::Display);


MenuFunction, call the class directly

//Here we need to know the result of the class.
//If we call the menuitem Action, we don't know the result,
//Here we can know the result : roundId = SPLSalesRoundIdLookUp.parmRoundId()
clicked()
{
    SPLYearWeek             YearWeek;
    ;
    YearWeek = SPLSalesRound::YearWeek(str2int(WeekDelivery.valueStr()));

	SPLSalesRoundIdLookUp = SPLSalesRoundIdLookUp::construct();

    SPLSalesRoundIdLookUp.parmYearWeek(YearWeek);
    if (SPLSalesRoundIdLookUp.prompt())
    {
		SPLSalesRoundIdLookUp.run();
		roundId = SPLSalesRoundIdLookUp.parmRoundId();
    }
}

MenuFunction, example with parm

call with parm
void clicked()
{
    SPLSalesRoundAddRemoveRouteId   SPLSalesRoundAddRemoveRouteId;
    MenuFunction menuFunction;
    Args args = new Args();
    ;
    menuFunction = new MenuFunction(menuitemactionstr(SPLSalesRoundAddRouteId), MenuItemType::Action);
    if (splRoundRecIdCriteria)
    {
        args.parm(int642str(splRoundRecIdCriteria));
        menuFunction.run(args);
        WMSPickingRoute_ds.executeQuery();
    }
}
//In the class
static void main(Args args)
{
    SPLSalesRoundAddRemoveRouteId    SPLSalesRoundAddRemoveRouteId;
    boolean                          bAddRouteId;
    SPLSalesRoundRecId               SPLSalesRoundRecId;
;
    SPLSalesRoundAddRemoveRouteId = SPLSalesRoundAddRemoveRouteId::construct();
     
    switch (args.menuItemName())
    {
        case menuitemActionStr(SPLSalesRoundAddRouteId):
            bAddRouteId = true;
            break;

        default:
            bAddRouteId = false;
    }
    SPLSalesRoundRecId = str2int64(args.parm());
    
    SPLSalesRoundAddRemoveRouteId.parmAddRouteId(bAddRouteId);
    SPLSalesRoundAddRemoveRouteId.parmSPLSalesRoundRecId(SPLSalesRoundRecId);

    if (SPLSalesRoundAddRemoveRouteId.prompt())
        SPLSalesRoundAddRemoveRouteId.run();
}


Call form by form Name with wait

    formRun.wait(true);   -> the first form is blocked
	formRun.wait();       -> the first form is not blocked but we cannot close it.

// example : (wait)
void clicked()
{
    Args            args;
    FormRun         formRun;
    ;
    super();
...
    args = new args();
    args.parmObject(incomeCustGroupParameters);
    args.name(formStr(SPLIncomeByCustomerGroup));
    args.caller(element);
    formRun = classFactory.formRunClass(Args);
    formRun.init();
    formrun.run();
} 	

// another example (detach)
    // Launch results form
    args = new Args();
    args.caller(element);
    args.name(formstr(AuditPolicyTestRule));
    args.record(element.args().record());
    args.parm(int642str(batchJob.RecId));
    formRun = classfactory.formRunClass(args);
    formRun.init();
    formRun.run();
    formRun.detach();

//another example
void browseChannelAddress(FormStringControl _control)
{
    Args args;
    MenuFunction menuFunction;
    MenuItemNameDisplay browseMenuItem;
    FormRun formRun;
    AifIntegrationAdapter integrationAdapter;

    integrationAdapter = AifAdapterManager::getIntegrationAdapter(aifChannel.AdapterClassId);

    args = new Args();

    browseMenuItem = integrationAdapter.getAddressDisplayMenuItem();
    menuFunction = new MenuFunction(browseMenuItem, MenuItemType::Display);
    args = new Args(menuFunction.object());
    args.lookupValue(_control.text());
    args.parm(aifInboundPort.Name);

    formRun = ClassFactory::formRunClassOnClient(args);
    formRun.init();
    formRun.run();

    if (!formRun.closed())
        formRun.wait();

    if (formRun.closedOk())
    {
        //aifChannel.TransportAddress = args.lookupValue(); //Original SYS Code
        //Start MCS
        if (_control.id() == element.controlId(formControlStr(AifInboundPort, AifChannel_McsTransportAddressProcessed)))
        {
            aifChannel.McsTransportAddressProcessed = args.lookupValue();
        }
        else
        {
            aifChannel.TransportAddress = args.lookupValue();
        }
        //End MCS
        aifChannel_ds.active();
    }
}

//Wait(true)
void clicked()
{
    FormRun formRun;
    Args args = new Args();

    args.name(formstr(AssetImpairmentTestResultEntryList_JP));
    args.record(AssetImpairmentTestResult_JP);

    formRun = ClassFactory.formRunClass(args);
    formRun.form().design().windowType(FormWindowType::PopUp);
    formRun.init();
    formRun.run();
    formRun.wait(true);

    AssetImpairmentTestResult_JP_DS.reread();
}

//Form run with menu : to test
void clicked()
{
    BankStatementTaxDocument    bankStatementTaxDocument;
    Args                        args;
    FormRun                     formRun;

    if (bankStmtISOAccountStatement.Posted)
    {
        args = new Args();
        args.caller(this);
        args.record(bankStmtISOAccountStatement);

        formRun = new MenuFunction(menuitemDisplayStr(TaxTrans), MenuItemType::Display).create(args);
        formRun.run();
    }
}

// form lookup : performFormLookup
public void lookup()
{
    FormRun formRun;
    Args args;

    args = new Args(formStr(COSLedgerPeriodLookup));
    args.caller(this);
    args.parm(date2str(dateTo2.dateValue(), -1, -1, -1, -1, -1, -1, DateFlags::None));
    args.parmEnumType(2);
    formRun = ClassFactory::formRunClassOnClient(args);
    formRun.init();
    this.performFormLookup(formRun);
}

Call form by form Name with wait and test if OK

// In the clicked of the parent form
//==================================
void clicked()
{
    FormRun     SPLFormRun;
    Args        SPLargs = new Args();
    boolean    SPLIsOK;
    object     objectForm;
    ;
    super();

    SPLargs.name(formstr(SalCalculateItemSizes));
    SPLargs.record(purchLine);
    SPLargs.caller(element);

    SPLFormRun = ClassFactory.formRunClass(SPLargs);
    SPLFormRun.init();
    SPLFormRun.run();
    SPLFormRun.wait(true);
    objectForm = SPLFormRun;
    SPLIsOK = objectForm.parmOK();
    if (SPLIsOK)
        element.SPLRereadFromCalcSize();
}
// On the son form
//================
public class FormRun extends ObjectRun
{
    Boolean                OK;
}
public boolean parmOK(boolean _OK = OK)
{
    ;
    OK = _OK;
    return OK;
}
void clicked()
{
    ;
	super();
    if (purchLine && element.args().caller() && formHasMethod(element.args().caller(), identifierstr(SPLRereadFromCalcSize)))
	{
	     element.parmOK(true);
    }
    else
        source.reread();
    element.close();
}

Call a menuItem by adding a DS delay in the form - Do the LinkActive

//If we call a menuItem and give a record the form called doesn't execute linkActive, only if we send the DS.
//So in a form that haven't a DS, we must add a DS in Delay that doesn't do nothing
DS

Splitter

//declaration
public class FormRun extends ObjectRun
{
    #MACROLIB.Resource
    InventDimParm           inventDimParmPriceSetup;
    InventDimCtrl_Frm       inventDimFormSetup;
    SysFormSplitter_Y       _formSplitterVertical;
}
public void init()
{
    super();
   _formSplitterVertical   = new SysFormSplitter_Y(ctrlSplitVertical, table, this);
}
int mouseUp(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;

    ret = super(x, y, button, ctrl, shift);

    return _formSplitterVertical.mouseUp(x, y, button, ctrl, shift);
}
int mouseMove(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;

    ret = super(x, y, button, ctrl, shift);

    return _formSplitterVertical.mouseMove(x,y,button,ctrl,shift);
}
int mouseDown(int x, int y, int button, boolean ctrl, boolean shift)
{
    int ret;

    ret = super(x, y, button, ctrl, shift);

    return _formSplitterVertical.mouseDown(x, y, button, ctrl, shift);
}
splitter
splitter property

Field color

public int active()
{
    int ret;
    container contFieldError;

    ret = super();
    SPLSalesInterfaceLine_ds.allowEdit(SPLSalesInterfaceLine.Status != SPLSalesInterfaceLineStatus::Integrated);

    // Red Color
    contFieldError = SPLSalesInterfaceLineError::ErrorsContainer(SPLSalesInterfaceLine);

    // for each group fields(should be NOT AUTO)
    element.findControls(element.control(Control::Identification), ContFieldError);
    element.findControls(element.control(Control::Status), ContFieldError);
    element.findControls(element.control(Control::General1), ContFieldError);
    element.findControls(element.control(Control::Reference), ContFieldError);
    element.findControls(element.control(Control::Parameters), ContFieldError);

    return ret;
}

void findControls(FormGroupControl _formGroupControl, container _contFieldError )
{
	Counter             controlCount;
	int                 i;
	Object              formControl;
	Boolean             boRed;
	Integer             fieldId;
	FieldName           nameField;
	formBuildDataSource formBuildDataSource;
	tableName           tableName;
	refTableiD          tableId;
	;

	controlCount            = _formGroupControl.controlCount();

	for (i = 1; i Less= controlCount; i++)
	{
		formControl = _formGroupControl.controlNum(i);

		if (formControl.dataSource() && formControl.dataField())
		{
			formBuildDataSource = element.form().dataSource(formControl.dataSource());
			tableID = formBuildDataSource.table();
			nameField = fieldid2name(tableId,  formControl.dataField());
			fieldId = fieldname2id(tableId, nameField);
			boRed = false;
			if (conFind(_contFieldError, fieldId) != 0)
				boRed = true;
			element.ControlColor(formControl,boRed);
		}
	}
}

// 23/03/2009 SPL GPO-Geodis
void ControlColor(FormStringControl  _FormControl, boolean _boRed)
{    ;

	_FormControl.colorScheme(FormColorScheme::Auto);
	_FormControl.backgroundColor(WindowsPalette::WindowBackground);

	if (_boRed)
	{
	_FormControl.backgroundColor(WinApi::RGB2Int(255, 0, 0));
	_FormControl.colorScheme(FormColorScheme::RGB);
	}
}

//Field color of just one control in the grid
// 08/01/2017-aSPL_ARP_137_SalesUpdApproval
// SalesLine_SPLSalesStatusApproval is autoDeclaration yes in the grid
public void displayOption(SalesLine _salesLine, FormRowDisplayOption _options)
{
    int myColor=WinApi::RGB2int(0,0,250);
    ;
    if (_salesLine.SPLSalesStatusApproval == SPLSalesStatusApproval::Waiting)
    {
        _options.textColor(myColor);
        _options.affectedElementsByControl(SalesLine_SPLSalesStatusApproval.id());
    }
    super(_salesLine, _options);
}

Show the column of selection in the grid

In the Grid ShowRowLabels = No -> The column of selection is not display
Selection column

Display method in a form

//The display method in a form is not for a grid. It is for a single line.
//If we put it on a grid, it displays the same value for all the Lines
display method

//To work in display method and read parameter global, we need to declare the display method in the DS of the form.
//For this, we need to send the Record in the function.
form_displaymethInDS.jpg
display DS

Join dataSource on DS with group by

//The display method in a form is not for a grid. It is for a single line.
//If we put it on a grid, it displays the same value for all the Lines
join with group by

Form with pack unpack

//We can add method Pack - Unpack in a form
//Ex SalesReleaseOrderPicking : In this exemple We save a Query in the Pack - Unpack
//To use this we need to add method : LastValueType, LastValueUserId ...

final class FormRun extends ObjectRun
{
    SysQueryRun                             selectSalesLines;
    container                               salesLinesQueryPacked;
 
    SysLastValue                            sysLastValue;

    #define.CurrentVersion(1)
    #localmacro.CurrentList
        salesLinesQueryPacked
    #endmacro
}
// Template method, must be named lastValueType
private UtilElementType lastValueType()
{
    return UtilElementType::Form;
}
// Template method, must be named lastValueUserId
private UserId lastValueUserId()
{
    return curUserId();
}
...

Form with tmpFrmVirtual

//in 2009, we can use a special column link to a temporary table to kown if a line is selected
//Example BOMExpandSales.
form with tmpFrmVirtual
code for tmpFrmVirtual

Form Master - detail

// Table Master - detail.
The aims is to explain that in the bouton Refresh :
- the refresh is good is the execute query of the line is done before the execute query of the master
- Or we must put the filter of the line before the execute query of the master:
Ex :
Refresh : 
master_ds.executeQuery();
line_ds_range.value("x");    
line_ds.executeQuery;     ----> Not GOOD
//----------------------------------------------------------------------//
line_ds_range.value("x");    
master_ds.executeQuery();
line_ds.executeQuery;     ----> GOOD
//=============================================================================================//
// Init Master
public void init()
{
    queryBuildDataSource    queryBuildDataSource;
    queryBuildRange         queryBuildRangeDate;

    super();

    queryBuildDataSource = this.query().dataSourceTable(tablenum(SMAAgreementTable));
    queryBuildDataSource.addRange(fieldNum(SMAAgreementTable,StartDate)).value(queryRange(dateNull(),systemDateGet()));

    queryBuildRangeDate = queryBuildDataSource.addRange(fieldNum(SMAAgreementTable,EndDate));
    queryBuildRangeDate.value(queryValue(dateNull()));
    queryBuildRangeDate = queryBuildDataSource.addRange(fieldNum(SMAAgreementTable,EndDate));
    queryBuildRangeDate.value(queryRange(systemDateGet(),dateMax()));

    queryBuildDataSource.addRange(fieldNum(SMAAgreementTable,Suspended)).value(queryValue(NoYes::No));

    qbrAgreementId = queryBuildDataSource.addRange(fieldNum(SMAAgreementTable,AgreementId));

    if (SMAAgreementIdCaller)
    {
        HeaderAgreementId.text(SMAAgreementIdCaller);
        qbrAgreementId.value(queryValue(SMAAgreementIdCaller));
    }
}
//ExecuteQuery Master
public void executeQuery()
{
    if (HeaderAgreementId.text())
        qbrAgreementId.value(queryValue(HeaderAgreementId.text()));
    else
        qbrAgreementId.value("");

    super();
}
//=============================================================================================//
// Init Line //
public void init()
{
    queryBuildDataSource    queryBuildDataSource;

    super();

    queryBuildDataSource = this.query().dataSourceTable(tablenum(SPLWasteSMAFormula));

    qbrNextRevisionDate = queryBuildDataSource.addRange(fieldNum(SPLWasteSMAFormula,NextRevisionPeriodDate));
}

//ExecuteQuery Line
public void executeQuery()
{
    //date dateStart,dateEnd;

	// this part is to put in the button refresh before execute query of the master
    //if (HeaderDateMonthYear.dateValue())
    //{
    //    dateStart = dateStartMth(HeaderDateMonthYear.dateValue());
    //    dateEnd   = dateEndMth(HeaderDateMonthYear.dateValue());
    //   qbrNextRevisionDate.value(queryRange(dateStart,dateEnd));
    //}
    //else
    //    qbrNextRevisionDate.value(queryRange(dateNull(),dateMax()));

    super();
}
//=============================================================================================//
//Refresh button // === NOT GOOD ===
void clicked()
{
    super();
    SMAAgreementTable_ds.executeQuery();
    SPLWasteSMAFormula_ds.executeQuery();
    ProjTable_ds.executeQuery();
}
//======================================//
void clicked() // ==== GOOD ====
{
    date dateStart,dateEnd;
    ;
    super();
    
    // Filter for SPLWasteSMAFormula <=============Range of line before the master executeQuery
    if (HeaderDateMonthYear.dateValue())
    {
        dateStart = dateStartMth(HeaderDateMonthYear.dateValue());
        dateEnd   = dateEndMth(HeaderDateMonthYear.dateValue());
        qbrNextRevisionDate.value(queryRange(dateStart,dateEnd));
    }
    else
        qbrNextRevisionDate.value(queryRange(dateNull(),dateMax()));
    
    SMAAgreementTable_ds.executeQuery();
    SPLWasteSMAFormula_ds.executeQuery();
    ProjTable_ds.executeQuery();
}
Master-detail

Reference Datasource

//We can add a reference Data source with a relation key to use it in a form.


Run - sum from dataSource

//It is possible to do a sum in the run, the run goes after the execute query.
public void run()
{
    SPLGuarantee localSPLGuarantee;
    real receivedTotal, givenTotal;
    ;
    TotalReceived.realValue(0);
    TotalGiven.realValue(0);
    super();
    for (localSPLGuarantee = SPLGuarantee_ds.getFirst(false);localSPLGuarantee;localSPLGuarantee = SPLGuarantee_ds.getNext())
    {
        if (!localSPLGuarantee.Closed)
        {
            if (localSPLGuarantee.GuaranteeDirection == SPLGuaranteeDirection::Given)
            {
                givenTotal      += localSPLGuarantee.AmountCalcMst;
            }
            else
            {
                receivedTotal   += localSPLGuarantee.AmountCalcMst;
            }
        }
    }
    TotalReceived.realValue(receivedTotal);
    TotalGiven.realValue(givenTotal);
}


Close , canClose

Close is called when we click on the button Close or on X of the Window.
When we click on the button Close or on X of the Window, we first call the CanClose.

1 - CanClose
2 - LeaveRecord... , write...
3 - Close


//Code To refresh the caller record 
public void close()
{
    Common          common;
    FormDataSource  callingFormDataSource;

    if(SPLWASTEBSDTable.ServiceOrderId && SPLWASTEBSDTable.ServiceOrderLineNum)
        SMAServiceOrderLine::SPLWasteUpdateQtyFromBSD(SPLWASTEBSDTable.ServiceOrderId,SPLWASTEBSDTable.ServiceOrderLineNum);

    common = element.args().record();

    if (common)
    {
        callingFormDataSource = common.dataSource();
        if (callingFormDataSource)
        {
            // Referenced datasources must be reread before calling research as data has been modified behind the scenes
            // without calling research will fail to position selection correctly
            callingFormDataSource.reread();
            callingFormDataSource.rereadReferenceDataSources();
            callingFormDataSource.research(true);
        }

    }

    super();
}

Example of form without button close : SalesCreateOrder


Icone in a grid




//PurchParmTable
//BP Deviation documented



display ImageRes checkIfLines()
{
    #resAppl
    ;

    // Invoices and Invoice Approval Journals with an error log should show the error warning icon
    if ((this.Log != '') &&
        (this.Ordering == DocumentStatus::Invoice || this.Ordering == DocumentStatus::ApproveJournal))
    {
        return #ImageError;
    }

    if (PurchParmLine::existTableRefId(this.ParmId, this.TableRefId))
    {
        return #ImageOK;
    }

    return #ImageWarning;
	
	//return 0 -> empty
}


Prompt in run

//In the run we can call the prompt to apply a filter
public void run()
{
    SysQueryRun queryRunCriteria;
    super();

    queryRunCriteria = new SysQueryRun(spldrivertable_ds.query());
    queryRunCriteria.promptAllowAddDataSource(false);

    if (queryRunCriteria.prompt())
    {
        spldrivertable_ds.query(queryRunCriteria.query());
    }
    spldrivertable_ds.executeQuery();
}

Call a dialog and refresh the form

// Refresh the caller form !
// Case of a form that call a dialog
class SPLSalesImportXls extends RunBase
{
    Object                  objectForm;
}
static void main(Args args)
{
    SPLSalesImportXls.setObject(args.caller());
	....
    if (SPLSalesImportXls.prompt())
        SPLSalesImportXls.run();
}
public void run()
{
    FormRun formRun;
    #Task
    try
    {
        if (this.checkDir(fileNameOpen))
        {
            this.readfileXLS();
        }
    }
    catch (Exception::Deadlock)
    {
        retry;
    }
    formRun = objectForm;
    formRun.task(#taskFormRefresh_F5); //(2012 TaskF5))
}
public Object setObject(Object _object)
{
    ;
    objectForm = _object;
    return objectForm;
}

JumpRef - Go to main table

// On a control in a form to see, Right click -> Go to main table
// We need to override the jumpref method
public void jumpRef()
{
    Args                SPLArgs;
    MenuFunction        SPLMenuFunction;
    InventTransferTable inventTransferTable;
    ;
    if (salesLine.InventRefType == InventRefType::InventTransfer && salesLine.InventRefId)
    {
        inventTransferTable = InventTransferTable::find(salesLine.InventRefId);
        SPLArgs         = new Args();
        SPLMenuFunction = new MenuFunction(menuitemDisplayStr(InventTransferOrder), MenuItemType::Display);
        SPLArgs         = new Args(SPLMenuFunction.object());
        SPLArgs.caller(element);
        SPLArgs.record(inventTransferTable);
        SPLMenuFunction.run(SPLArgs);
    }
    else
        super();
}