iSeries EGL

All things EGL for the iSeries / i5 / Power System

Archive for the ‘EGL DojoDialog’ Category

A Conversational Dialog Box, Events and the InfoBus

leave a comment »

A Dialog Box that uses the InfoBus to Communicate User Driven Events

This post covers the creation of a dialog box and shows how to instantiate it, populate the titles and messages and how to communicate user driven events back to the parent program which launched it. The InfoBus is employed to communicate button events back to the parent program so that it may close the dialog and to act upon those events.

The Problem

The problem which this post addresses centers on the need of the application to launch a process only after asking the user if it is OK to proceed. The application launches a dialog by injecting a specified widget into a DojoDialog. When the dialog is displayed the user can select the “Cancel” or “Approve” button. At this point the event must be communicated back to the parent application so that it can A.) close the dialog and B.) either launch the process that has been approved by the user when selecting the “Proceed” button or do nothing because the user selected the “Cancel” button. The dialog box is shown below.

The dialog box.

 

The source for the dialog box and the code used by the parent application to launch it.

This section presents the source code for the dialog box along with the code used in the parent application which properly sets it up for presentation to the user.

 

The dialog box source.

Looking at the code there are two components that are established for a message title and an area for detail related messages. These are messageTextLabel and messagesTextArea The host program launching the dialog is responsible for populating these. In addition there are two functions which handle the button events. These are ApproveButton_onClick(event Event in) and CancelButton_onClick(event Event in)

package com.mig.widgets.approvedialog;

// RUI Widget

import com.ibm.egl.rui.infobus.infobus;
import com.ibm.egl.rui.widgets.GridLayout;
import com.ibm.egl.rui.widgets.GridLayoutData;
import com.ibm.egl.rui.widgets.GridLayoutLib;
import com.ibm.egl.rui.widgets.Image;
import com.ibm.egl.rui.widgets.TextLabel;
import com.ibm.egl.rui.widgets.html;
import com.mig.claimchecksapproval.libraries.ConstantsLibrary;
import com.mig.claimchecksapproval.libraries.SessionLibrary;
import com.mig.claimchecksapproval.records.GlobalDataRecord;
import com.mig.claimchecksapproval.services.ApproveChecksService;
import com.mig.widgets.waitdialog.waitdialog;
import egl.io.sql.column;
import dojo.widgets.DojoButton;
import dojo.widgets.DojoDialog;
import dojo.widgets.DojoTextArea;

//
//
handler ApproveDialog type RUIWidget{targetWidget = ui, onConstructionFunction = start, cssFile = "css/ClaimChecksApprovalProject.css", @VEWidget{category = "Custom"}}
    ui GridLayout{columns = 3, rows = 5, cellPadding = 4, children = [ GridLayout, messageTextLabel, messagesTextArea]};

    messageTextLabel TextLabel{ layoutData = new GridLayoutData{ row = 2, column = 2,
        horizontalSpan = 1, 
        horizontalAlignment = GridLayoutLib.ALIGN_CENTER }, text="TextLabel",
        fontSize = "14" };

    messagesTextArea DojoTextArea{ layoutData = new GridLayoutData{ row = 4, column = 2,
        horizontalSpan = 1 },  width = 400, height = 100,
        numColumns = 80,
        backgroundColor = "WhiteSmoke",
        id = "messagesTextArea",
        font = "courier",
        fontSize = "12" 
         };

    GridLayout GridLayout{ layoutData = new GridLayoutData{ row = 5, column = 2,
    	horizontalAlignment = GridLayoutLib.ALIGN_RIGHT }, cellPadding = 4, rows = 1, columns = 3,
    	children = [ ApproveButton, CancelButton ] };
    CancelButton DojoButton{ layoutData = new GridLayoutData{ row = 1, column = 3 }, text = "Cancel", onClick ::= CancelButton_onClick };
    ApproveButton DojoButton{ layoutData = new GridLayoutData{ row = 1, column = 2 }, text = "Approve Checks", onClick ::= ApproveButton_onClick };

          
    function start()
    end
        
    function addMessageToApproveDialog(message String in)
        messagesTextArea.value = messagesTextArea.value + message;
    end
    
    function ApproveButton_onClick(event Event in)
        InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, "noData");
    end 

    function CancelButton_onClick(event Event in)
    	InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, "noData");
    end 
   
end


Fig.1 – Source code for the dialog box (ApproveDialog.egl)

 

The code used by the parent application to present the dialog box

Shown below is the source code for the function in the parent application which launches the dialog box. It shows how it instantiates an object derived from the source presented above and how it injects the object into a DojoDialog box which simply acts as the container or frame for the object which represents its main body. It also shows how those message components are used.

    function presentApproveDialogMenuFunctionReturn(globalDataRecord GlobalDataRecord in)

        //Set title bar text and main body text message for the user instruction.
        title string = "Claim Checks Approval Process Verification";
        processMessage string = "Select 'Approve Checks' or 'Cancel'";
        
        //Set message to inform the user of an outcome of a previous step so they may select the
        //correct button.
        message string = "";        
        if (globalDataRecord.approvalStatus == ConstantsLibrary.CONST_APPROVAL_PROCESS_NOT_APPROVED)
            message = "Claim checks have not yet been approved for the day.\n";
            message = message + "You may proceed by selecting the approval or cancel button. \n";
        end
        if (globalDataRecord.approvalStatus == ConstantsLibrary.CONST_APPROVAL_PROCESS_ONCE_APPROVED)
            message = "** WARNING ! ** Claim checks have already been approved for the day! \n";
            message = message + "You may proceede by approving again or cancel.  If approved \n";
            message = message + "email notification will again be sent and the history screen \n";
            message = message + "will show another group of reports for the day.\n";            
        end
        
        //Create an instance of the ApproveDialog to be injected into a DojoDialog for presentation
        innerApproveDialog ApproveDialog =  new ApproveDialog{messageTextLabel.text = processMessage};
        innerApproveDialog.addMessageToApproveDialog(message);

        //Inject the innerApproveDialog into the DojoDialog and present it to the user.
        approveDialog = new DojoDialog { children = [ innerApproveDialog ]} ;
        approveDialog.title= title;
        approveDialog.draggable = false;
        approveDialog.showDialog();
    end 

Fig. 2 – The Service Return function that launches the dialog box.

The service return function above determines if the process has already been performed. While the process can be performed more than once, it is desirable to inform the user before proceeding. The dialog box is used present the outcome of that process to the user so that they can either cancel or proceed.

Now what?

So far, we’ve shown how a simple widget that acts as the main body for a dialog box is injected into a DojoDialog component that acts as its container. When the DojoDialog is presented to the user they can interact by selecting one of the two available buttons. The buttons then fire the appropriate event functions which we’ll focus on in the next section.

 

Using the InfoBus to provide a communication link

The parent application relies upon the InfoBus to receive information about events taking place between the user and the dialog box. To receive this information the following lines are added to the start() function in the parent application.

   //Register to the InfoBus the callback functions evoked by the ApproveDialog.
   Infobus.subscribe(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, ApproveDialogCancelButtonInfoBusCallBack);
   Infobus.subscribe(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, ApproveDialogApproveButtonInfoBusCallBack);

Fig.3 – The Parent Application. Register to the InfoBus the names of the callback functions.

See Fig. 5 for details of these functions, also in the parent application.

As seen in figure 2, the parent application “owns” the dialog meaning it holds a reference to the dialog object. When displayed the dialog is holding a conversation with the user who can select one of two buttons. No matter which button is selected, the dialog “owns” that event. There are 2 problems to be solved here, the first being the dialog cannot close itself, since it is the application which holds the object reference to the dialog. Any attempt by the dialog to close itself results in an “object not found” error. The second problem is then how to communicate the button event back to the application so that it can close the dialog, since it holds the reference to it, and then either do nothing or proceed with the process.

To accomplish this, the dialog has these button-event functions ApproveButton_onClick(event Event in) and CancelButton_onClick(event Event in), shown below.

    function ApproveButton_onClick(event Event in)
        InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, "noData");
    end 

    function CancelButton_onClick(event Event in)
    	InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, "noData");
    end 

Fig.4 – The dialog’s button-event functions

They are called when either the Approve and Cancel button are selected. These functions use the InfoBus to “publish” the need to call a function that resides in the parent application. Notice that the constants used (their values are arbitrary) are the same constants used by the parent application’s start up processing which registered the call-back functions. Those functions that are in the parent application are going to get called whenever one of the functions are called.

The constants CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT and CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT of the ConstantsLibrary are used by the Infobus.publish command to establish links back to the parent application’s ApproveDialogCancelButtonInfoBusCallBack and ApproveDialogApproveButtonInfoBusCallBack functions. The values of the constants are arbitrary in nature meaning their values don’t really matter. They simply act as a handle or a means by which a lookup can be performed so that the proper function can be called when the user selects either the “Cancel” or “Approve” button.

When the user selects either button provided by the dialog the function in the parent application is called which then closes the dialog and then proceeds with the appropriate processing.

    /**
     * This function is called when the Cancel button of the Approve Dialog is selected.
     */
    function ApproveDialogCancelButtonInfoBusCallBack(event string in, data any in)
        approveDialog.hideDialog();
        approveDialog.destroy();
    end

    /**
     *  Approve the claim checks by calling this service which will;
     *  1.  Create the PDF document containing all table data shown  
     *  2.  Writes all URL values obtained from CLM0002PF to CLM003PF
     *
     */ 
    function ApproveDialogApproveButtonInfoBusCallBack(event string in, data any in)

        //Close the Approval Dialog box and destroy the object reference.
        approveDialog.hideDialog();
        approveDialog.destroy();  

        //Show another wait dialog while the approval process is running
        message string = "Approval Processing is now executing.";
        innerWaitDialog =  new WaitDialog{messageTextLabel.text = message};
        processingDialog = new DojoDialog { children = [ innerWaitDialog ]} ;
        processingDialog.title= "Approval Processing";
        processingDialog.draggable = false;
        processingDialog.showDialog();

       :
       :  Main process occurs here
       :

    end 

Fig. 5 – The event functions for the Approve and Cancel buttons.

 

Shown here is the parent application after the user has selected the “Approve” button. As a result, another dialog is presented which indicates the process has been launched.

A Process in Progress dialog box.

 

Conclusion

This post showed how to create a somewhat reusable dialog box to be injected into a DojoDialog component which was then instantiated, initialized and presented by the parent application. The problem of communicating dialog button events back to the parent application was addressed by the use of the InfoBus which calls the appropriate functions for further processing by the parent program.

 
 

Advertisements

Written by iseriesadmin

October 18, 2012 at 8:44 am

Making a Dialog Box

leave a comment »

The Dialog Box in EGL

This post illustrates how to code a simple dialog box to show a message that instructs the user to be patient while some background activity is executing. One common activity is the loading of data with which to populate the screen.

Shown below is the EGL code that performs the following steps:

  1. Create a label to contain the message.
  2. Create the GridLayout and assigns the label as a child component.
  3. Create a dialog box and assign GridLayout containing the label as a child component.

    //Create a label to contain the message.  Assigning text is optional at this time as it will probably be replaced at runtime.
    loggingViewerDialog_TextLabel1 TextLabel{ layoutData = new GridLayoutData{ row = 1, column = 1 }, text = "Please wait while data is being loaded." };
    
    //Create the GridLayout and assign loggingViewerDialog_TextLabel1 as a child
    loggingViewerDialog_GridLayout GridLayout{ layoutData = new GridLayoutData{ row = 2, column = 3,
        horizontalSpan = 1, verticalAlignment = GridLayoutLib.VALIGN_TOP }, cellPadding = 4, rows = 3, columns = 3,
        children = [ loggingViewerDialog_TextLabel1 ] };
    
    //Create a dialog box and assign loggingViewerDialog_GridLayout as a child 
    loggingViewerDialog DojoDialog {title = "Wait",  children = [ loggingViewerDialog_GridLayout ]} ;

Fig.1 – EGL code for a simple dialog box.

The code shown below shows how to display the dialog box.

    loggingViewerDialog.showDialog();

Fig.2 – Displaying the dialog box.

To hide the dialog, use the following code.

    loggingViewerDialog.hideDialog();

Fig.3 – Hiding the dialog box.

This is the resulting dialog box.

A simple Dialog Box

Written by iseriesadmin

June 22, 2012 at 8:32 am

Posted in EGL DojoDialog

Tagged with