Using Command Handlers to do simple prompts

Date:30th June 2009
Product/Release:Visual LANSA Framework
Abstract:How to use Command Handlers as prompting assistants in the Visual LANSA Framework
Submitted By:LANSA Technical Support

Introduction:

The Visual LANSA Framework documentation contains a section about Using Assistants to handle more complex "codes", however the section contains no sample source code and hence it is not immediately clear how to implement the suggestions offered.

The following mini-tutorial demonstrates a simple Command Handler used as an "Assistant" as per the documentation "Approach 1"

Step 1 – Create two simple example prompters:

T_PROMPT1 prompts employees:

BEGIN_COM ROLE(*EXTENDS #VF_AC010) HEIGHT(279) LAYOUTMANAGER(#ATLM_1) WIDTH(498)
DEFINE_COM CLASS(#PRIM_LTVW) NAME(#LTVW_1) COMPONENTVERSION(2) DISPLAYPOSITION(1) FULLROWSELECT(True) HEIGHT(279) KEYBOARDPOSITIONING(SortColumn) LEFT(0) PARENT(#COM_OWNER) SHOWSORTARROW(True) TABPOSITION(1) TOP(0) WIDTH(498)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_1) DISPLAYPOSITION(1) PARENT(#LTVW_1) SOURCE(#EMPNO)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_2) DISPLAYPOSITION(2) PARENT(#LTVW_1) SOURCE(#SURNAME) WIDTH(30)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_3) DISPLAYPOSITION(3) PARENT(#LTVW_1) SOURCE(#GIVENAME) WIDTH(28) WIDTHTYPE(Remainder)
DEFINE_COM CLASS(#PRIM_ATLM) NAME(#ATLM_1)
DEFINE_COM CLASS(#PRIM_ATLI) NAME(#ATLI_1) ATTACHMENT(Center) MANAGE(#LTVW_1) PARENT(#ATLM_1)

mthroutine uExecute OPTIONS(*REDEFINE)
If (#ltvw_1.Entries = 0)
select (#empno #Surname #giveName) from_file(pslmst)
add_entry #ltvw_1
Endselect 
Endif 
Endroutine

EVTROUTINE HANDLING(#LTVW_1.ItemGotSelection) OPTIONS(*NOCLEARMESSAGES *NOCLEARERRORS)
invoke #com_owner.avSignalEvent withid(EMPLOYEE_SELECTED) to(FRAMEWORK) SendAinfo1(#Empno) SendAinfo2(#Surname) SendAinfo3(#GiveName) 
ENDROUTINE
END_COM

T_PROMPT2 prompts departments and sections:

BEGIN_COM ROLE(*EXTENDS #VF_AC010) HEIGHT(279) LAYOUTMANAGER(#ATLM_1) WIDTH(498)
DEFINE_COM CLASS(#PRIM_LTVW) NAME(#LTVW_1) COMPONENTVERSION(2) DISPLAYPOSITION(1) FULLROWSELECT(True) HEIGHT(279) KEYBOARDPOSITIONING(SortColumn) LEFT(0) PARENT(#COM_OWNER) SHOWSORTARROW(True) TABPOSITION(1) TOP(0) WIDTH(498)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_1) DISPLAYPOSITION(1) PARENT(#LTVW_1) SOURCE(#DEPTMENT)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_2) DISPLAYPOSITION(2) PARENT(#LTVW_1) SOURCE(#SECTION) WIDTH(30)
DEFINE_COM CLASS(#PRIM_LVCL) NAME(#LVCL_3) DISPLAYPOSITION(3) PARENT(#LTVW_1) SOURCE(#SECDESC) WIDTH(28) WIDTHTYPE(Remainder)
DEFINE_COM CLASS(#PRIM_ATLM) NAME(#ATLM_1)
DEFINE_COM CLASS(#PRIM_ATLI) NAME(#ATLI_1) ATTACHMENT(Center) MANAGE(#LTVW_1) PARENT(#ATLM_1)

mthroutine uExecute OPTIONS(*REDEFINE)
If (#ltvw_1.Entries = 0)
select (#deptment #section #secdesc) from_file(sectab)
add_entry #ltvw_1
Endselect
Endif
Endroutine

EVTROUTINE HANDLING(#LTVW_1.ItemGotSelection) OPTIONS(*NOCLEARMESSAGES *NOCLEARERRORS)
invoke #com_owner.avSignalEvent withid(SECTION_SELECTED) to(FRAMEWORK) SendAinfo1(#deptment) SendAinfo2(#section)
ENDROUTINE

END_COM

When an employee or department section is selected they broadcast a signal and include the selected item details as additional signal information.

Step 2 – Snap the prompters in as Framework command handlers

In this example the prompters have been snapped as framework level command commands named Example 1 (EXAMPLE_1) and Example 2 (EXAMPLE_2) along with all the other framework level commands:

Snap the prompters in as Framework command handlers

Step 3 Start using the prompters from other command handlers

For this example, the shipped "essential business object" command handler DF_T0023 has been modified slightly...

Start using the prompters from other command handlers

A department and section code have been added at the bottom.

Two small prompt buttons have been added beside the employee number and department code fields. They are just a push button with a "?" as their captions.

In a real application you would probably do something more elaborate involving an image. The following important code was also added to DF_T0023:

* Handle a click on the employee prompt button
EVTROUTINE HANDLING(#PHBN_EMP.Click)
invoke #AVFRAMEWORKMANAGER.avswitch to(Framework) caller(#Com_Owner) Execute(EXAMPLE_1) 
ENDROUTINE

* Handle a click on the department/section prompt button
EVTROUTINE HANDLING(#PHBN_SEC.Click)
invoke #AVFRAMEWORKMANAGER.avswitch to(Framework) caller(#Com_Owner) Execute(EXAMPLE_2)
ENDROUTINE

* Handle one of the prompters signalling the selection of a employee 
* or department/section
EvtRoutine Handling(#Com_owner.avEvent) WithId(#EventId) WithAInfo1(#AInfo1) WithAInfo2(#AInfo2) WithAInfo3(#AInfo3)
case #EventId
when (= EMPLOYEE_SELECTED)
#EmpNo := #AInfo1
#SurName := #AInfo2
#Givename := #AInfo3
when (= SECTION_SELECTED)
#deptment := #AInfo1
#section := #AInfo2
Endcase 
Endroutine

The result looks like this when I click on the employee prompt button:

The result looks like this when I click on the employee prompt button.

As I select employee details in the prompter, the employee number, name and surname details change on the DF_T0023 input form.

It looks like this when I click on the department/section prompt button:

It looks like this when I click on the department/section prompt button.

As I select department/section details in the prompter, the department code and section code change on the DF_T0023 input form.

The full modified version of the shipped DF_T0023 is:

* ================================================================================
* Type : COMMAND HANDLER
* Ancestor : VF_AC010
* Written By : SETUSER on 17th APRIL 2003 at 11:18:07
* Copyright : (C) Copyright
* Framework : Your Framework
* Application : Demo Application
* Business Object : Employees
* Command Handler : Basic Details
* ================================================================================
Function Options(*DIRECT)
BEGIN_COM ROLE(*EXTENDS #VF_AC010) HEIGHT(255) HINT(*MTXTDF_DET1) LAYOUTMANAGER(#MAIN_LAYOUT) WIDTH(600)
* ================================================================================
* Simple Field and Group Definitions
* ================================================================================
Group_by Name(#XG_HEAD) FIELDS(#EMPNO #SURNAME #GIVENAME #ADDRESS1 #ADDRESS2 #ADDRESS3 #POSTCODE #PHONEHME #DEPTMENT #SECTION)

* ================================================================================
* Component definitions
* ================================================================================

* Body and Button arrangement panels
DEFINE_COM CLASS(#PRIM_PANL) NAME(#BUTTON_PANEL) DISPLAYPOSITION(2) HEIGHT(255) HINT(*MTXTDF_DET1) LAYOUTMANAGER(#BUTTON_FLOW) LEFT(512) PARENT(#COM_OWNER) TABPOSITION(2) TABSTOP(False) TOP(0) WIDTH(88)
DEFINE_COM CLASS(#PRIM_PANL) NAME(#BODY_HEAD) DISPLAYPOSITION(1) HEIGHT(255) HINT(*MTXTDF_DET1) LAYOUTMANAGER(#BODY_HEAD_FLOW) LEFT(0) PARENT(#COM_OWNER) TABPOSITION(1) TABSTOP(False) TOP(0) VERTICALSCROLL(True) WIDTH(512)

* Attachment and flow layout managers
DEFINE_COM CLASS(#PRIM_ATLM) NAME(#MAIN_LAYOUT)
DEFINE_COM CLASS(#PRIM_ATLI) NAME(#BUTTON_ATTACH) ATTACHMENT(Right) MANAGE(#BUTTON_PANEL) PARENT(#MAIN_LAYOUT)
DEFINE_COM CLASS(#PRIM_FWLM) NAME(#BUTTON_FLOW) DIRECTION(TopToBottom) FLOWOPERATION(Center) MARGINBOTTOM(4) MARGINLEFT(4) MARGINRIGHT(4) MARGINTOP(4) SPACING(4) SPACINGITEMS(4)
DEFINE_COM CLASS(#PRIM_ATLI) NAME(#BODY_ATTACH) ATTACHMENT(Center) MANAGE(#BODY_HEAD) PARENT(#MAIN_LAYOUT)
DEFINE_COM CLASS(#PRIM_FWLM) NAME(#BODY_HEAD_FLOW) DIRECTION(TopToBottom) MARGINBOTTOM(4) MARGINLEFT(4) MARGINRIGHT(4) MARGINTOP(4) SPACING(4) SPACINGITEMS(4)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_EMPNO) MANAGE(#EMPNO) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_SURNAME) MANAGE(#SURNAME) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_GIVENAME) MANAGE(#GIVENAME) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_ADDRESS1) MANAGE(#ADDRESS1) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_ADDRESS2) MANAGE(#ADDRESS2) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_ADDRESS3) MANAGE(#ADDRESS3) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_POSTCODE) MANAGE(#POSTCODE) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_PHONEHME) MANAGE(#PHONEHME) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_SAVE_BUTTON) MANAGE(#SAVE_BUTTON) PARENT(#BUTTON_FLOW)

* The save button
DEFINE_COM CLASS(#PRIM_PHBN) NAME(#SAVE_BUTTON) BUTTONDEFAULT(True) CAPTION(*MTXTDF_SAVE) DISPLAYPOSITION(1) LEFT(4) PARENT(#BUTTON_PANEL) TABPOSITION(1) TOP(4)

* Collection for detail fields
DEFINE_COM CLASS(#Prim_ACol<#prim_evp>) NAME(#PanelFields)

* Fields in the head area
DEFINE_COM CLASS(#EMPNO.Visual) DISPLAYPOSITION(1) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(1) TOP(4) USEPICKLIST(False) WIDTH(209)
DEFINE_COM CLASS(#SURNAME.Visual) DISPLAYPOSITION(2) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(2) TOP(27) USEPICKLIST(False) WIDTH(324)
DEFINE_COM CLASS(#GIVENAME.Visual) DISPLAYPOSITION(3) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(3) TOP(50) USEPICKLIST(False) WIDTH(324)
DEFINE_COM CLASS(#ADDRESS1.Visual) DISPLAYPOSITION(4) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(4) TOP(73) USEPICKLIST(False) WIDTH(363)
DEFINE_COM CLASS(#ADDRESS2.Visual) DISPLAYPOSITION(5) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(5) TOP(96) USEPICKLIST(False) WIDTH(363)
DEFINE_COM CLASS(#ADDRESS3.Visual) DISPLAYPOSITION(6) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(6) TOP(119) USEPICKLIST(False) WIDTH(363)
DEFINE_COM CLASS(#POSTCODE.Visual) DISPLAYPOSITION(7) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(7) TOP(142) USEPICKLIST(False) WIDTH(216)
DEFINE_COM CLASS(#PHONEHME.Visual) DISPLAYPOSITION(8) HEIGHT(19) HINT(*MTXTDF_DET1) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(8) TOP(165) USEPICKLIST(False) WIDTH(286)
DEFINE_COM CLASS(#DEPTMENT.Visual) NAME(#DEPTMENT) DISPLAYPOSITION(9) HEIGHT(19) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(9) TOP(188) USEPICKLIST(False) WIDTH(201)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_1) MANAGE(#DEPTMENT) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#Section.Visual) NAME(#Section) DISPLAYPOSITION(10) HEIGHT(19) LEFT(4) PARENT(#BODY_HEAD) TABPOSITION(11) TOP(211) USEPICKLIST(False) WIDTH(179)
DEFINE_COM CLASS(#PRIM_FWLI) NAME(#FWLI_2) PARENT(#BODY_HEAD_FLOW)
DEFINE_COM CLASS(#PRIM_PHBN) NAME(#PHBN_EMP) CAPTION('?') DISPLAYPOSITION(11) HEIGHT(19) LEFT(216) PARENT(#BODY_HEAD) TABPOSITION(10) TOP(5) WIDTH(19)
DEFINE_COM CLASS(#PRIM_PHBN) NAME(#PHBN_SEC) CAPTION('?') DISPLAYPOSITION(12) HEIGHT(19) LEFT(207) PARENT(#BODY_HEAD) TABPOSITION(12) TOP(190) WIDTH(19)

* ================================================================================
* Method Definitions
* ================================================================================

* --------------------------------------------------------------------------------
* Handle Initialization
* --------------------------------------------------------------------------------

Mthroutine Name(uInitialize) Options(*REDEFINE)
Define_com #Prim_evp #FormField Reference(*dynamic) 

* Do any initialization defined in the ancestor
Invoke #Com_Ancestor.uInitialize

* Build a collection of all the fields in the panel so that
* a single event routine can listen to all of them for changes
For Each(#Control) In(#Body_Head.ComponentControls)
IF_REF COM(#Control) IS(*INSTANCE_OF #prim_evp)
Set_ref Com(#FormField) to(*dynamic #Control)
Invoke #PanelFields.Insert Item(#FormField)
endif
Endfor
Endroutine

* --------------------------------------------------------------------------------
* Handle Command Execution
* --------------------------------------------------------------------------------

Mthroutine Name(uExecute) Options(*REDEFINE)

* Do any execution logic defined in the ancestor
Invoke #Com_Ancestor.uExecute

* Get the employee number of the employee whose details are to be displayed.
Invoke #avListManager.GetCurrentInstance AKey3(#EMPNO)

* Fetch information from the main file to fill in the header fields on the form
Fetch Fields(#XG_HEAD) From_File(PSLMST) With_Key(#EMPNO)

* Set up the visible form for display
If_status *okay
Set #Body_Head Visible(True)
Else
Set #Body_Head Visible(False)
Use Message_Box_Show (ok ok Warn *Component 'Selected employee was not found') 
Endif
Set #Save_Button Enabled(False)
Endroutine

* --------------------------------------------------------------------------------
* Handle a request to set focus to the filter pane by overriding the default behaviour
* --------------------------------------------------------------------------------

Mthroutine uAcceptFocus Options(*Redefine)
#Empno.SetFocus
#Accepted := True
Endroutine

* ================================================================================
* Event Handlers
* ================================================================================

* --------------------------------------------------------------------------------
* Handle changes in any of the fields on the panel
* --------------------------------------------------------------------------------

EvtRoutine Handling(#PanelFields<>.Changed)

* Enable the save button
Set #SAVE_BUTTON Enabled(True)

* Lock the framework and set a message for the user
Set #avFrameworkManager uLocked(USER) uLockedMessage('Changes made to the current employee details have not been saved. Do you want to save them?')
EndRoutine

* --------------------------------------------------------------------------------
* Handle the save button
* --------------------------------------------------------------------------------

EvtRoutine Handling(#SAVE_BUTTON.Click) 

* Update data base
Update Fields(#XG_HEAD) In_File(PSLMST) With_Key(#EMPNO) Val_Error(*NEXT) Issue_Msg(*YES)

* If update completed okay
If_Status Is(*OKAY)

* Issue a message indicating employee was updated
Message Msgid(DCM0425) Msgf(DC@M01) Msgdta(*MTXTDF_EMP_UPD)

* Update the instance list using the "quick update" method
Use BConcat (#GiveName #SurName) #FullName
Invoke Method(#avListManager.UpdateListEntryData) Akey1(#Deptment) Akey2(#Section) Akey3(#Empno) Visualid2(#FullName) AColumn1(#Phonehme) AColumn2(#Address1) nColumn1(#PostCode)

* Disable the save button again
Set #SAVE_BUTTON Enabled(False)

* Drop the framework lock as no updates are outstanding now
Set #avFrameworkManager uLocked(FALSE)
Endif
Endroutine

* --------------------------------------------------------------------------------
* Handle Termination
* --------------------------------------------------------------------------------

Mthroutine Name(uTerminate) Options(*REDEFINE)

* Clean up the colelction of fields on the panel

Invoke #PanelFields.RemoveAll

* Do any termination defined in the ancestor

Invoke #Com_Ancestor.uTerminate
Endroutine

EVTROUTINE HANDLING(#PHBN_EMP.Click)
invoke #AVFRAMEWORKMANAGER.avswitch to(Framework) caller(#Com_Owner) Execute(EXAMPLE_1) 
ENDROUTINE

EVTROUTINE HANDLING(#PHBN_SEC.Click)
invoke #AVFRAMEWORKMANAGER.avswitch to(Framework) caller(#Com_Owner) Execute(EXAMPLE_2)
ENDROUTINE

EvtRoutine Handling(#Com_owner.avEvent) WithId(#EventId) WithAInfo1(#AInfo1) WithAInfo2(#AInfo2) WithAInfo3(#AInfo3)
case #EventId
when (= EMPLOYEE_SELECTED)
#EmpNo := #AInfo1
#SurName := #AInfo2
#Givename := #AInfo3
when (= SECTION_SELECTED)
#deptment := #AInfo1
#section := #AInfo2
Endcase 
Endroutine
End_Com
Back to Top