Below is my code,I used the name Test1 instead of SysMultiTableLookup
class Test1
{
container lookupItems;
Query query;
int controlIdx;
Common tmpBuffer;
str labels[];
FormControl callingControl;
fieldId lookupField;
boolean useLookupValue;
protected void addFilter(FormRun formRun)
{
FormDataSource formDataSource = formRun.dataSource();
QueryBuildRange queryBuildRange;
FormStringControl callingStringControl;
FormStringControl selectControl;
fieldId selectFieldId;
str callingValue;
;
if (!callingControl || !callingControl.hasChanged())
return;
switch (callingControl.handle())
{
case classnum(FormStringControl):
callingStringControl = callingControl;
if (controlIdx && callingStringControl.text())
{
selectControl = formRun.control(controlIdx);
selectFieldId = selectControl.dataField();
if (selectFieldId)
{
callingValue = callingStringControl.text();
if (strfind(callingValue, '*', 1, 999))
{
queryBuildRange = formDataSource.query().dataSourceNo(1).addRange(selectFieldId);
queryBuildRange.value(callingValue);
}
}
}
break;
}
}
void addLookupControl(int _dataSourceNo, fieldId _fieldId, boolean _returnItem, str _methodName, str _label)
{
lookupItems += [[_dataSourceNo, _fieldId, _returnItem, _methodName]];
if (_label)
this.setLabel(_label);
}
void addLookupField(fieldId _fieldId, int _dataSourceNo = 1, boolean _returnItem = false, str _label = '')
{
;
if (_dataSourceNo > query.dataSourceCount())
throw error(Error::wrongUseOfFunction(funcName()));
this.addLookupControl(_dataSourceNo, _fieldId, _returnItem, '', _label);
}
// this method should not be called before the actually lookup column has been added
void addLookupMethod(str _method, int _dataSourceNo = 1, str _label = '')
{
;
this.addLookupControl(_dataSourceNo, 0, false, _method, _label);
}
protected FormBuildControl addMethodControl(FormBuildGridControl _formBuildGridControl, FormBuildDataSource _formBuildDataSource, str _method, int _labelIdx)
{
DictMethod dictMethod = new DictMethod(UtilElementType::TableInstanceMethod, _formBuildDataSource.table(), _method);
int extendedTypeId;
int returnId;
Types returnType;
SysDictType sysDictType;
FormBuildControl addStandardControl(FormControlType _formControlType)
{
Object obj;
FormBuildControl ret;
;
obj = _formBuildGridControl.addControl(_formControlType, _method);
obj.dataSource(_formBuildDataSource.id());
obj.dataMethod(_method);
if (labels[_labelIdx])
{
obj.label(labels[_labelIdx]);
}
ret = obj;
return ret;
}
;
if (!dictMethod)
return null;
returnType = dictMethod.returnType();
returnId = dictMethod.returnId();
if (returnType == Types::UserType) // EDT - find base type of EDT
{
extendedTypeId = returnId;
if (!extendedTypeId)
return null;
sysDictType = new SysDictType(extendedTypeId);
returnType = sysDictType.baseType();
}
if (returnType == Types::Enum)
{
if (returnId == enumnum(NoYes) ||
(sysDictType && sysDictType.enumId() == enumnum(NoYes)) ||
(returnId == enumNum(Boolean))) //Boolean should also be displayed as a checkbox
{
extendedTypeId = extendedTypeNum(NoYesId); // Simulate NoYesId to have it shown as checkbox
}
}
else if (returnType == Types::Integer)
{
if (sysDictType && Test1::isEqualOrExtending(sysDictType.id(), extendedTypeNum(timeOfDay)))
{
extendedTypeId = extendedTypeNum(timeOfDay);
}
}
return addStandardControl(this.types2ControlType(returnType, extendedTypeId));
}
protected FormBuildGridControl buildGrid(FormBuildGridControl _formBuildGridControl, Form _form)
{
FormBuildDataSource formBuildDataSource;
FormBuildControl formBuildControl;
Object obj;
boolean returnItem;
str method;
int fieldId;
int i;
boolean lookupFieldSet = false;
int dataSourceNo;
;
for (i = 1; i <= conlen(lookupItems); i++)
{
[dataSourceNo, fieldId, returnItem, method] = conpeek(lookupItems, i);
if (!method)
{
formBuildControl = _formBuildGridControl.addDataField(_form.dataSource(dataSourceNo).id(), fieldId);
if (labels[i])
{
obj = formBuildControl;
obj.label(labels[i]);
}
}
else
{
formBuildControl = this.addMethodControl(_formBuildGridControl, _form.dataSource(dataSourceNo), method, i);
}
if(!formBuildControl)
throw error("@SYS72176");
if (!lookupFieldSet || returnItem)
{
controlIdx = formBuildControl.id();
lookupField = fieldId;
lookupFieldSet = true;
}
}
return _formBuildGridControl;
}
protected void buildSelectionList(Query _query)
{
boolean returnItem;
str method;
int fieldId;
int i;
int dataSourceNo;
SelectionField fieldKind()
{
int j;
QueryBuildFieldList qbfl;
;
qbfl = _query.dataSourceNo(dataSourceNo).fields();
for (j = 1; j <= qbfl.fieldCount(); j++)
{
if (qbfl.field(j) == fieldId)
{
return qbfl.fieldKind(j);
}
}
return SelectionField::Database;
}
;
// Test that all are fields (no methods)
// If at least 1 method is present, it is too risky to build a selection field list
for (i = 1; i <= conlen(lookupItems); i++)
{
[dataSourceNo, fieldId, returnItem, method] = conpeek(lookupItems, i);
if (method)
{
return;
}
}
for (i = 1; i <= conlen(lookupItems); i++)
{
[dataSourceNo, fieldId, returnItem, method] = conpeek(lookupItems, i);
_query.dataSourceNo(dataSourceNo).addSelectionField(fieldId, fieldKind());
}
}
// This is a framework class.
//class Test1
//{
//}
protected FormRun formRun()
{
Form form = new Form();
FormRun formRun;
FormBuildDesign formBuildDesign;
FormBuildDataSource formBuildDataSource;
FormDataSource formDataSource;
FormBuildGridControl formBuildGridControl;
FormGridControl formGridControl;
FormStringControl callingStringControl;
QueryBuildDataSource queryBuildDataSource;
Args args;
int idx;
int i;
;
form.name(identifierstr(TemporaryFormName));
for (i = 1; i <= query.dataSourceCount(); i++)
{
queryBuildDataSource = query.dataSourceNo(i);
formBuildDataSource = form.addDataSource(queryBuildDataSource.name());
formBuildDataSource.table(queryBuildDataSource.table());
formBuildDataSource.autoQuery(true);
if (queryBuildDataSource.embedded()) //joined() or level() > 1
{
formBuildDataSource.linkType(this.joinMode2LinkType(queryBuildDataSource.joinMode()));
formBuildDataSource.joinSource(queryBuildDataSource.parentDataSource().name());
}
formBuildDataSource.allowCreate(false);
formBuildDataSource.allowDelete(false);
formBuildDataSource.allowEdit(false);
formBuildDataSource.allowCheck(false);
}
formBuildDesign = form.addDesign('Design');
formBuildDesign.mode(FormMode::Watch);
formBuildDesign.frame(FormFrame::Border);
formBuildDesign.hideIfEmpty(false);
formBuildDesign.hideToolbar(false);
formBuildDesign.top(15);
formBuildDesign.topMargin(2);
formBuildDesign.left(15);
formBuildDesign.leftMargin(0);
formBuildDesign.rightMargin(0);
formBuildDesign.bottomMargin(0);
//DZJ
formBuildDesign.showDeleteButton(NoYes::No);
formBuildDesign.showNewButton(NoYes::No);
formBuildDesign.viewEditMode(viewEditMode::View);
formBuildGridControl = formBuildDesign.addControl(FormControlType::Grid,'Grid');
formBuildGridControl.dataSource(query.dataSourceNo(1).name());
formBuildGridControl.allowEdit(true);
formBuildGridControl.showRowLabels(false);
idx = formBuildGridControl.id();
this.buildGrid(formBuildGridControl, form);
args = new Args();
args.object(form);
if(useLookupValue && !tmpBuffer) //highlighting existing value doesn't work with temp tables
{
args.lookupField(lookupField);
switch (callingControl.handle())
{
case classnum(FormStringControl):
callingStringControl = callingControl;
args.lookupValue(callingStringControl.text());
break;
}
}
formRun = classfactory.formRunClass(args);
form = formRun.form();
formRun.init();
formDataSource = formRun.dataSource(1);
formGridControl = formRun.control(idx);
formGridControl.setFocus();
formRun.selectMode(formRun.control(controlIdx));
if (query)
{
formDataSource.query(query);
}
if (tmpBuffer)
{
if (query.dataSourceCount() > 1)
throw error("Multiple temporary datasource lookups are not supported");
formDataSource.init();
//BP deviation documented
formDataSource.cursor().setTmp(); // if using non-temp table in tmp mode
formDataSource.cursor().setTmpData(tmpBuffer);
}
this.buildSelectionList(formDataSource.query());
formRun.selectMode(formRun.control(controlIdx));
this.addFilter(formRun);
return formRun;
}
FormLinkType joinMode2LinkType(JoinMode _joinMode)
{
switch (_joinMode)
{
case JoinMode::InnerJoin:
return FormLinkType::InnerJoin;
case JoinMode::OuterJoin:
return FormLinkType::OuterJoin;
case JoinMode::ExistsJoin:
return FormLinkType::ExistJoin;
case JoinMode::NoExistsJoin:
return FormLinkType::NotExistJoin;
}
throw error(Error::wrongUseOfFunction(funcName()));
}
FormControl parmCallingControl(FormControl _callingControl = callingControl)
{
;
callingControl = _callingControl;
return callingControl;
}
Query parmQuery(Query _query = query)
{
;
query = _query;
return query;
}
Common parmTmpBuffer(Common _buffer = tmpBuffer)
{
;
tmpBuffer = _buffer;
return tmpBuffer;
}
boolean parmUseLookupValue(boolean _useLookupValue = useLookupValue)
{
;
useLookupValue = _useLookupValue;
return useLookupValue;
}
void performFormLookup()
{
#AOT
FormStringControl callingStringControl;
FormIntControl callingIntControl;
#if.ReferencesPath
FormInt64Control callingInt64Control;
#endif
FormDateControl callingDateControl;
;
if (!callingControl)
throw(error(Error::wrongUseOfFunction(funcname())));
switch (callingControl.handle())
{
case classnum(FormStringControl):
callingStringControl = callingControl;
callingStringControl.performFormLookup(this.formRun());
break;
case classnum(FormIntControl):
callingIntControl = callingControl;
callingIntControl.performFormLookup(this.formRun());
break;
#if.ReferencesPath
case classnum(FormInt64Control):
callingInt64Control = callingControl;
callingInt64Control.performFormLookup(this.formRun());
break;
#endif
case classnum(FormDateControl):
callingDateControl = callingControl;
callingDateControl.performFormLookup(this.formRun());
break;
}
}
void setLabel(str label)
{
labels[conlen(lookupItems)] = label;
}
FormControlType types2ControlType(Types _returnType, UtilElementId _Id)
{
#AOT
switch(_returnType)
{
case Types::String:
return FormControlType::String;
case Types::Real:
return FormControlType::Real;
case Types::Date:
return FormControlType::Date;
#if.ServicesPath
case Types::UtcDateTime:
return FormControlType::DateTime;
#endif
case Types::Integer:
if (_id && Global::isType(_id, extendedTypeNum(timeOfDay)))
return FormControlType::Time;
return FormControlType::Integer;
#if.ReferencesPath
case Types::Int64:
return FormControlType::Int64;
case Types::Guid:
return FormControlType::Guid;
#endif
case Types::Enum:
if (_id && Global::isType(_id, extendedTypeNum(NoYesId)))
return FormControlType::CheckBox;
return FormControlType::ComboBox;
}
throw error(strfmt("@SYS110310", _returnType));
}
static Test1 construct()
{
return new Test1();
}
/// <summary>
/// Simulates the code that is performed in the kernel to allow
/// filtering to work properly in custom lookup forms.
/// </summary>
/// <param name="_isFiltered">
/// The result value from the FilterLookupPreRun method.
/// </param>
/// <param name="_filterString">
/// The filter string contained within the lookup control.
/// </param>
/// <param name="_controlToFilter">
/// The control on the lookup form that is bound to the field to filter the value on.
/// </param>
/// <param name="_formDataSource">
/// The FormDataSource value on the lookup form.
/// </param>
/// <remarks>
/// This method should be called after the super call in the custom lookup
/// form's run method.
/// </remarks>
public static void filterLookupPostRun(boolean _isFiltered,
str _filterString,
FormStringControl _controlToFilter,
FormDataSource _formDataSource)
{
;
if (_isFiltered)
{
//The FormDataSource doesn't have a QueryRun since AutoSearch is false
//Therefore we need to create one so that the filter call below will succeed.
_formDataSource.queryRun(new SysQueryRun(_formDataSource.query()));
_controlToFilter.filter(_filterString);
}
}
/// <summary>
/// This method simulates the code that is performed in the kernel to allow
/// filtering to work properly in custom lookup Forms.
/// </summary>
/// <param name="_lookupControl">
/// The control that contains the field value being looked up.
/// </param>
/// <param name="_controlToFilter">
/// The control on the Lookup Form that is bound to the field to filter the value on.
/// </param>
/// <param name="_formDataSource">
/// The FormDataSource on the Lookup Form.
/// </param>
/// <param name="_listExtraFormDataSources">
/// The list of additional FormDataSource objects on the Lookup Form
/// where the autoSearch parameter should be set to false in case of filtering.
/// </param>
/// <returns>
/// Whether the value in the control contains a value that should be filtered on.
/// </returns>
/// <remarks>
/// This method should be called before the Super method call in the custom Lookup
/// form's run method.
/// </remarks>
public static boolean filterLookupPreRun(FormStringControl _lookupControl,
FormStringControl _controlToFilter,
FormDataSource _formDataSource,
List _listExtraFormDataSources = null)
{
boolean isFiltered = false;
str controlText = _lookupControl.text();
str filterValue = strkeep(controlText, '*');
ListEnumerator listEnumerator;
FormDataSource extraFormDataSource;
;
if (strlen(filterValue) != 0 && _lookupControl.hasChanged())
{
_formDataSource.autoSearch(false);
if(_listExtraFormDataSources)
{
listEnumerator = _listExtraFormDataSources.getEnumerator();
while(listEnumerator && listEnumerator.moveNext())
{
extraFormDataSource = listEnumerator.current();
if(extraFormDataSource)
{
extraFormDataSource.autoSearch(false);
}
}
}
isFiltered = true;
}
else
{
if(_controlToFilter)
{
_formDataSource.formRun().args().lookupField(_controlToFilter.dataField());
_formDataSource.formRun().args().lookupValue(controlText);
}
}
return isFiltered;
}
/// <summary>
/// This method simulates the code that is performed in the kernel to allow
/// filtering to work properly in custom lookup forms with two data sources.
/// </summary>
/// <param name="_lookupControl">
/// The control that contains the field value being looked up.
/// </param>
/// <param name="_controlToFilter">
/// The control on the lookup form that is bound to the field to filter the value on.
/// </param>
/// <param name="_formDataSource">
/// The first FormDataSource value on the lookup form.
/// </param>
/// <param name="_formDataSource2">
/// The second FormDataSource value on the lookup form
/// where the autoSearch parameter should be set to false in case of filtering.
/// </param>
/// <returns>
/// Whether the value in the control contains a value that should be filtered on.
/// </returns>
/// <remarks>
/// This method should be called before the Super method call in the custom lookup
/// form's run method.
/// </remarks>
public static boolean filterLookupPreRun_2DS(FormStringControl _lookupControl,
FormStringControl _controlToFilter,
FormDataSource _formDataSource,
FormDataSource _formDataSource2)
{
List listExtraFormDataSources = new List(Types::Class);
;
listExtraFormDataSources.addEnd(_formDataSource2);
return Test1::filterLookupPreRun(_lookupControl, _controlToFilter, _formDataSource, listExtraFormDataSources);
}
/// <summary>
/// This method simulates the code that is performed in the kernel to allow
/// filtering to work properly in custom lookup forms with three data sources.
/// </summary>
/// <param name="_lookupControl">
/// The control that contains the field value being looked up.
/// </param>
/// <param name="_controlToFilter">
/// The control on the lookup form that is bound to the field to filter the value on.
/// </param>
/// <param name="_formDataSource">
/// The first FormDataSource value on the lookup form.
/// </param>
/// <param name="_formDataSource2">
/// The second FormDataSource value on the lookup form.
/// </param>
/// <param name="_formDataSource3">
/// The third FormDataSource value on the lookup form
/// where the autoSearch parameter should be set to false in case of filtering.
/// </param>
/// <returns>
/// Whether the value in the control contains a value that should be filtered on.
/// </returns>
/// <remarks>
/// This method should be called before the Super method call in the custom lookup
/// form's run method.
/// </remarks>
public static boolean filterLookupPreRun_3DS(FormStringControl _lookupControl,
FormStringControl _controlToFilter,
FormDataSource _formDataSource,
FormDataSource _formDataSource2,
FormDataSource _formDataSource3)
{
List listExtraFormDataSources = new List(Types::Class);
;
listExtraFormDataSources.addEnd(_formDataSource2);
listExtraFormDataSources.addEnd(_formDataSource3);
return Test1::filterLookupPreRun(_lookupControl, _controlToFilter,
_formDataSource, listExtraFormDataSources);
}
client static FormStringControl getCallerStringControl(Args args, boolean throwOnError = true)
{
FormStringControl callerControl;
FormRun caller;
;
if (args && args.caller())
{
if(args.caller().handle() == classnum(FormStringControl))
{
// When constructed from code the control must be inserted in the args.caller()
callerControl = args.caller();
}
else if (Test1::is(args.caller(),classnum(FormRun)))
{
// When the form is assigned on the extended data type the calling formRun is the caller.
caller = args.caller();
if (caller.selectedControl().handle() == classnum(FormStringControl))
callerControl = caller.selectedControl();
}
if (!callerControl)
{
// Test if it has been put in the parmObject object.
if (args.parmObject() && args.parmObject().handle() == classnum(FormStringControl))
callerControl = args.parmObject();
}
}
if (throwOnError && !callerControl)
throw(error(Error::wrongUseOfFunction(funcname())));
return callerControl;
}
public static boolean is(Object _class, classId _classId)
{
boolean ret = new SysDictClass(classidget(_class)).isImplementing(_classId);
if (!ret)
{
ret = SysDictClass::isEqualOrSuperclass(classidget(_class), _classId);
}
return ret;
}
//Method copied over from AX 2009 installation
static boolean isEqualOrExtending(extendedTypeId _id, extendedTypeId _potentialParentId)
{
SysDictType sysDictType;
;
if(_id == _potentialParentId)
{
return true;
}
sysDictType = new SysDictType(_id);
if (sysDictType)
{
return sysDictType.isExtending(_potentialParentId);
}
else
{
return false;
}
}
/// <summary>
/// This method is used in the custom lookup forms
/// to apply a filter on the new tab page when it is activated.
/// </summary>
/// <param name="_lookupControl">
/// The control that contains the field value being looked up.
/// </param>
/// <param name="_controlToFilter">
/// The control on the lookup form that is bound to the field to filter the value on.
/// </param>
/// <param name="_formDataSource">
/// The FormDataSource value on the lookup form.
/// </param>
/// <remarks>
/// Usually this method should be called from the tabChanged method of the tab control
/// on the form.
/// </remarks>
public static void lookupTabChanged(FormStringControl _lookupControl,
FormStringControl _controlToFilter,
FormDataSource _formDataSource)
{
boolean filterLookup;
;
filterLookup = Test1::filterLookupPreRun(_lookupControl, _controlToFilter, _formDataSource);
if(filterLookup)
{
Test1::filterLookupPostRun(filterLookup, _lookupControl.text(), _controlToFilter, _formDataSource);
}
else
{
_formDataSource.executeQuery();
}
}
static Test1 newParameters(FormControl callingControl, Query _query, boolean useLookupValue = true)
{
Test1 sysTableLookup = Test1::construct();
;
if (_query.dataSourceCount() < 1)
throw error(@"Query needs to be defined before building the lookup");
sysTableLookup.parmQuery(_query);
sysTableLookup.parmCallingControl(callingControl);
sysTableLookup.parmUseLookupValue(useLookupValue);
return sysTableLookup;
}
}