Creating a UIM List Application

Article ID: 1732
Unlike IBM, which uses panel groups for most OS/400 panels, most programmers still use display files to present panels in programs. I guess one reason for this attachment to display files is that they seem easier to code than panel groups. You can define a display file with fewer than 100 lines of DDS, but a panel group may require as many as 400 lines of code! Why bother writing so many lines of code when far fewer lines can give the same result?

The answer is that panel groups offer significant advantages over display files, especially when used in action-list applications (i.e., work-with panels). This article discusses those advantages and explains how to use UIM in a list application. I also provide the WRKUSR utility as an example of a list application that uses UIM. This utility is useful in its own right and is available for download here — for a description of WRKUSR, see "The WRKUSR Utility", below

Panel Groups vs. Display Files

Versatility. Panel group tag language is more versatile than DDS. It provides UIM (User Interface Manager)-specific commands, called dialog commands, that assign functions to list options and function keys in the panel-group source. UIM, a part of OS/400, is responsible for all operations related to panel groups. When you use dialog commands, you can leave list-option and function-key processing to UIM; you don't need to write the code to handle these requests. However, depending on the nature of your application and the action you assign to the option or function key, you may need to provide an exit program to assist UIM in its processing.

Ease of coding command lines. It's much easier to include a command line in a UIM panel than in a display file — simply specify a CMDLINE tag. A UIM-provided command line has all the facilities of a typical OS/400 command line. You can enter commands on it, prompt a command, and retrieve previous commands (using the appropriate dialog commands). You can even specify parameters for list options on the command line. UIM adds these parameters to the end of the list option's command string before executing the command. Providing these functions in a display file application requires many lines of code.

Easier list management. UIM lists are easier to fill than subfiles. You don't need to keep track of a subfile record number. UIM assigns every entry a unique identifier, called a handle, and uses the handle in all operations related to the list entry. If UIM invokes an exit program to perform an action on the list entry, UIM passes the handle to the exit program so it can access the entry.

Scrolling support is better in UIM, too. To add entries to an incomplete list, all you have to do is specify the exit program UIM calls. UIM handles everything else related to scrolling; you don't have to enable and disable scrolling keys, indicate whether there are more entries to see, or determine which entry should be at the top of the page. All UIM needs is for the exit program to tell it when the list is complete.

Longer list records. A subfile record is limited to the width of the display device on which it is shown; a UIM list has no such limitation. If you define a UIM list wider than the display device, you just specify which list columns should be displayed. You can show different views of the list one after the other by using the CHGVIEW dialog command — this is the service provided by the F11 function key in most OS/400 work-with panels.

A wider choice of languages. Not all high-level languages support subfiles. To use a subfile, you must develop it in a language that supports it, such as RPG or Cobol. But application programs interact with panel groups through APIs, so you can use any programming language that allows calls to APIs (and I can't think of any that don't) to develop a UIM application. In fact, panel groups are about the only means of displaying lists in languages that don't support subfiles.

Combined display and print panels. Unlike a DDS source member, a panel group can contain both display and print panels. The advantage of having both types of panels in the same object is data sharing. Once your program puts data into the panel group's variable pool, that data is available to all the panels. Consequently, you can print what a display panel shows without having to gather the information all over again.

Consistency. In panel groups, UIM, not the programmer, controls how information in the panel is organized. UIM follows predetermined guidelines to ensure panel consistency. Since IBM uses panel groups for most OS/400 panels, using such panels in your own applications will give your displays a familiar look. Thus your users will relate to them easily, especially if you assign list options and function keys those functions commonly associated with them, such as 2=Change, 3=Copy, F3=Exit, F4=Prompt.

UIM Dialog Commands

UIM provides a number of dialog commands that you can specify in certain attributes of several UIM tags. Dialog commands provide screen management functions (e.g., scrolling, displaying help modules) and programming-related functions. Three programming-related commands — CALL, CMD, and RETURN — deserve some attention here.

The CALL dialog command specifies that UIM call a program. The syntax for the command is CALL pgm-var, where pgm-var is a dialog variable that contains the name or address of the program to be called. The parameter passed to the program depends on the function for which it is called (e.g., whether to process a function key or a list option). I'll discuss this further later.

The CMD dialog command specifies that UIM submit a system command for processing. Its syntax is CMD cmd-string, where cmd-string is the command string to be processed. If the string contains dialog variables, UIM substitutes their current value into the command string before submitting it to the system. Each dialog variable must be preceded by an ampersand (&) and followed by a period (.). The command string can also contain prompt characters to make the system prompt the command before executing it.

The RETURN dialog command returns control to the application program that displayed the panel from which the command was executed. The syntax is RETURN n, where n is an integer. When UIM returns control to the application program, it places the value n in the Function Requested parameter of the QUIDSPP (Display Panel) API, thus providing a way for the program to process certain function keys, such as F5=Refresh.

Defining a List Panel

A panel group has two sections — the prologue and the body. The prologue contains tags that define elements referred to later in the body, while the body contains tags that define the panels of the panel group. Figure 1 shows the required order of tags in the source for a panel group.

Variables in a panel group are called dialog variables. A dialog variable is defined by a VAR tag, which in turn refers to a CLASS tag that provides the variable's attributes — its type, length, and characteristics. The VAR tag also specifies an error status variable (if any) associated with the dialog variable. UIM automatically defines the error status variable as a one-byte character variable and sets the variable to 1 if the dialog variable is in error. An application program can also set the error status of a dialog variable during a put operation. If it sets the value to 1, UIM takes the variable to be in error. UIM uses reverse text to display variables in error.

Variable records are the structures through which application programs access dialog variables. A VARRCD tag defines a variable record. Its VARS attribute specifies the name (s) and order of the variables in the record. An application program cannot put or get information from a dialog variable except through a variable record. You specify the name of the variable record to use for the put or get operation as a parameter in the call to the appropriate API. The values you put or get must be in the same order as the variables in the record.

Lists are the UIM equivalents of subfiles. The LISTDEF tag defines a list, specifying the dialog variables within it. A list can have no more than 50 dialog variables. Each dialog variable contains a column of information. You don't have to display all the columns of a list; a LISTVIEW tag in a panel definition lets you specify which columns to display. You can use several LISTVIEW tags to define different views of a list.

All of a panel's active function keys must be defined. UIM does not automatically assign a function to any key, even the engraved keys (e.g., Enter, Print, Page up). A KEYI tag defines a function key. In the tag's ACTION attribute, you specify a dialog command to indicate the action UIM is to take when the key is pressed. The KEYI tags for a panel's function keys are grouped in a key list. The key list tag, KEYL, provides a name for the list. When defining the panel, you specify this name to refer to the function keys.

The panel group body contains the panel definitions. A PANEL tag begins the definition of a display panel and specifies the panel's name, help module, key list, and size. It also specifies a truth table (if any) for the panel, dialog variables to contain information about the location of the cursor when the panel is exited, and the action UIM should take if the user presses Enter and there is no request to process. The USREXIT attribute of this tag specifies a general exit program for the panel. UIM calls this program each time the user presses a function key or Enter and dialog variables or list entries have changed. The general exit program can perform additional validity checking or some other function. In the WRKUSR utility, the general exit program for the Position List panel positions the list to the entry specified by the user.

Within a list panel definition, you can define a data presentation area to provide information on the list. Tags for defining the depth, layout, and content of data presentation areas include DATA, DATACOL, DATAGRP, and DATAI. A DATA tag begins the definition of the data area and specifies the depth and layout of the area. A DATACOL tag defines a column in the data area. A data area can have two or three columns — the first for the prompt text, the second for the data, and the third (if specified) for the choices. A DATAI tag defines a data item displayed in the data area. It specifies the dialog variable from which UIM gets the value it displays and the prompt text for the item. If the data area has three columns, DATAC tags define the choices associated with each data item. DATAGRP tags specify how UIM should group data items.

A LIST tag begins the definition of a list area. A list area includes the lines for the legend of the list options, the column headings, and the rows of list entries. The LIST tag's LISTDEF attribute specifies the list from which UIM takes the data it displays in the list area. The ACTOR attribute specifies how the list options are processed — by either UIM or the application program. For non-action lists (i.e., lists that have no options), specify ACTOR=NONE. The PARMS attribute names a dialog variable in which UIM stores parameters entered on the command line for action list processing. This dialog variable will be included in the command string associated with the list options so that the parameters are added to the command before it's processed.

A LISTACT tag defines the action UIM performs on a list entry. The OPTION attribute assigns a number to the list action. This is the number the user types beside a list entry to request the specified action. The ENTER attribute specifies the action the UIM takes when the user presses Enter, and the PROMPT attribute specifies the action taken when the user requests the prompt function. You can specify either the CALL or CMD dialog command for these attributes. The USREXIT attribute names the exit program UIM calls after it performs the action specified for the ENTER or PROMPT attribute. Typically, the exit program updates or removes the list entry.

A LISTCOL tag defines a column in a list area. It specifies the dialog variable whose data UIM displays in the column. It also specifies the column's width and the text used as the column heading. A LISTVIEW tag specifies the list columns that are to be displayed together. You can use several LISTVIEW tags to define different views of a wide list. If you use list views, you'll also have to assign the CHGVIEW dialog command to a function key (e.g., F11), which the user can press to see each view of the list. You must specify at least one LISTVIEW tag in a list area definition.

A print head panel is required for UIM printing. It contains title text for the printout and information to be printed on every page. If there is data you want UIM to print on every page of a report, specify it in the print head panel. The PRTTRAIL tag, which can be specified only within the definition of a print head panel, provides text printed at the end of a report (e.g., END OF LISTING).

A PRTPNL tag begins the definition of a print panel. PRTPNL is similar to the PANEL tag for display panels but has fewer attributes and fewer tags available for use within the print panel definition. The PRTPNL tag specifies the name of the panel, its width, and its truth table (if any).

Figure 2 shows samples of the UIM tags discussed above. These are taken from the source of the WRKUSR utility panel group. Figures 3a and 3b show two of the utility's display panels, and Figure 3c shows a printout from its print panel. For more information on the UIM tag language and dialog commands, refer to Appendix 1.1 and Appendix 1.2 of Application Display Programming (SV41-3715 for V3R2; SC41-4715 for V3R6).

The Application Program

An application program for a UIM list application should perform the following tasks.

  1. Perform preliminary processing, such as validating values entered by the user and checking that objects referred to exist and that the user has the appropriate authority to use them.

  2. Depending on whether the output is to be displayed or printed, call the QUIOPNDA (Open Display Application) API to open a UIM display application or the QUIOPNPA (Open Print Application) API to open a print application. A panel group must be opened by one of these APIs before an application program can interact with it. UIM assigns a unique identifier — a handle — to the open application and returns the handle to the application program. This handle is specified in every other call to a UIM API for the open application.

  3. Update the appropriate dialog variables with the names or addresses of the exit programs for the application, using the QUIPUTV (Put Dialog Variable) API.

  4. Update any variables used when presenting heading information in the panels, again using API QUIPUTV.

  5. Generate the information to be displayed in the list (if it does not already exist). This may involve running a DSPxxx command and directing the output to a physical file or calling an API to generate a list in a user space.

  6. Clear the UIM list of any previous entries using the QUIDLTL (Delete List) API. You'll need this step if your application may have to rebuild the list — during refresh processing, for instance.

  7. Build the UIM list one entry at a time using the QUIADDLE (Add List Entry) API, or add multiple entries all at once using the QUIADDLM (Add Multiple List Entries) API. It's preferrable to add multiple entries for better performance. If the information for building the list is from a user space or user index, you can further improve performance by retrieving multiple entries all together.

  8. Indicate to the UIM whether the list is complete. Have the program call the QUISETLA (Set List Attributes) API with the value of the List Contents parameter set to ALL, for a complete list, or TOP, for an incomplete list that can accept more entries at the bottom. If the program doesn't specify this parameter, UIM assumes the list is complete, as it is when all entries are added to the list before it's displayed or printed (you shouldn't use the approach of adding all entries to the list unless you expect it to have only a few entries). If the program marks the list incomplete, it should also tell UIM the exit program to call when more entries are needed. The name of the dialog variable that refers to the exit program is specified in the Program Dialog Variable parameter of API QUISETLA. One call to the API is sufficient to pass all this information.

  9. If the output is to be printed, call the QUIPRTP (Print Panel) API for the print head panel, then call it again to print the list. If the list is incomplete, UIM calls the exit program specified in the list's attribute to add more entries. It calls this program repeatedly until all entries are added to the list. When it has printed the entire list, UIM returns control to the application program, which starts clean-up processing.

    If the output is to be displayed, call the QUIDSPP (Display Panel) API to display the panel. If the panel is being displayed following refresh processing, have the application program set the list attribute so that the page being displayed when the function key was pressed is the page UIM displays. This is done before calling the API. Setting a page to display involves specifying the handle of the list entry at the top of the page in the Display Position Attribute parameter of API QUISETLA. The application program will need to get the handle of this entry using the QUIGETLE (Get List Entry) API before setting the list's attribute.

    When the application program calls the QUIDSPP API, UIM assumes control and displays the panel. UIM also handles processing of the user's requests related to the panel. If the user chooses an option or presses a function key, UIM processes it. This may involve calling an exit program that returns control to UIM when it is through. For example, if the user attempts to scroll beyond the last entry in an incomplete list, UIM calls the list extension exit program for more entries. The application program is not notified. When the exit program marks the list complete, UIM changes "More . . ." at the lower right corner of the screen to "Bottom." UIM returns control to the application program only when it processes a RETURN, EXIT, or CANCEL dialog command in the first panel of the application.

  10. When control returns to the application program, use the Function Requested parameter of API QUIDSPP to determine whether the user requested a refresh or some other function the application program is to process. For refresh requests, the program should retrieve the list entry at the top of the current page and save it. This involves a call to the QUIRTVLA (Retrieve List Attributes) API to get the list entry's handle and then a call to the QUIGETLE API to retrieve the list entry's value. The program will later use this value to set the current page as the page UIM displays when it redisplays the panel.

  11. If the user made no request, close the UIM application, clean up the work space (delete the temporary output file, user space, and so on), and quit. The QUICLOA (Close Application) API closes both display and print applications.
In the WRKUSR utility, a separate program — RPG program WRKUSRR (Figure 4)- performs steps 7 and 8. This program adds 25 entries at a time to the list of users. I used RPG to take advantage of its array support. The program stacks the entries in an array before adding them to the UIM list. Hence, it accomplishes with one call to API QUIADDLM what would have taken it 25 calls to API QUIADDLE! This is obviously a performance gain. When the program has added the entries, it sets the list attribute to indicate whether the list is complete. It uses the assumption that if it got 25 records it needed from the database file, then there are probably still some more records in the file; but if it did not get 25 records, it has reached the end of the file, and the list is complete.

Exit Programs

Generally speaking, all user programs called by UIM are exit programs. These include programs called as a result of the CALL dialog command, programs specified in the USREXIT attribute of a panel definition (PANEL) or list action (LISTACT) tag, and programs called to add more entries to an incomplete list. All exit programs are specified by naming a dialog variable that refers to the program to call.

The definition of the dialog variable determines whether UIM calls the program by address or by name. If the dialog variable is defined as a pointer, the call is by address. This is the most efficient way of calling a program, but to use it, the application program must be developed in a language, such as C/400 or Pascal, that supports pointers. If the dialog variable is defined as a 20-byte character variable, the call is by name. The first 10 bytes contain the name of the program, and the second 10 bytes contain its library or the special value *LIBL or *CURLIB. If the dialog variable is defined as a 130- byte character variable, the call is in the extended program model environment. This is the least efficient way of calling an exit program. Unless you are pushed against a wall, do not use this type of call.

The parameter UIM passes an exit program depends on two things: the type of exit parameter interface for the application, and the function for which the exit program is called. You specify the type of exit parameter interface in the Exit Parameter Interface parameter of the QUIOPNDA or QUIOPNPA API. Using this parameter, you can request that UIM pass either a single parameter structure or multiple parameters to exit programs. It's more efficient for UIM to pass a single parameter structure simply because it's easier to manage information on a single location in memory than on several different locations. The rest of this discussion assumes the single-parameter case.

The content of the parameter structure depends on the function for which UIM calls the exit program. Figure 5 shows the various parameter structures for the different calls of exit programs. Notice that the first four fields in all the structures are the same, so rather than specify a different exit program for each type of function, you can have a single exit program handle all the different requests. This program will use the value in the parameter structure's Type of Call field to determine the function UIM requested. It may then call a service program to process the request. The advantage of this approach is that you need to define only one dialog variable for the exit program. If you had several exit programs, you would need to define several dialog variables, and your application program would need to make several calls to API QUIPUTV to update each of them.

The WRKUSR utility has a single exit program, WRKUSRXC (Figure 6), which receives the parameter structure, determines the function requested, and calls the appropriate service program to process it. The service program may display or print a panel, causing control to return to UIM, which may then call the exit program again to process another request on the new panel. As you can see, the exit program may be called several times for different functions during processing, and you should bear this in mind when designing your application.

For example, if a user presses F17=Position to on the Work with Users panel, UIM calls WRKUSRXC for function key processing. WRKUSRXC determines that the user pressed F17 and calls service program WRKUSRX1C to service the request. This program displays the Position List panel (Figure 3b) with a call to the QUIDSPP API. At this point, UIM regains control. When the user specifies the entry to position the list to and presses Enter, UIM again calls exit program WRKUSRXC, this time as a general panel exit program. WRKUSRXC in turn calls service program WRKUSRX2C to position the list. Although control passes back and forth, the operation goes so smoothly that you don't realize several programs are involved.

I use a general panel exit program call to position the list so that if an error occurs while the list is being positioned, UIM redisplays the Position List panel (with the appropriate error message). Had I used a function key processing call or some other exit program call, the Position List panel would not be redisplayed when an error occurs. Rather, the user would be returned to the Work with Users panel and would have to press F17 again to get back to the Position List display.

For more information about the UIM APIs and exit programs, refer to Chapters 58 and 59 of System Programmers Interface Reference (SC41-8223 for V2R3) or Chapters 67 and 68 of System API Reference (SC41-3801 for V3R2; SC41-4801 for V3R6).

Summary of Performance Considerations

Here are some tips to improve performance in your UIM application.
  • Except for short lists, build lists in stages — one or two screens at a time. If the list might be printed, increase the number of entries added at a time to reduce the number of times UIM needs to call the list extension exit program to print the entire list.
  • Add multiple entries at a time rather than one entry after another. If you can, generate the data to be displayed in a user space rather than an output file so you can retrieve several entries at a time.
  • If the programming language you're using can efficiently manipulate data structures, use the single-parameter interface for exit programs.
  • Have a single program handle all exit program calls. When the exit program determines the function requested, it should call a service program to process the request.

UIM All the Way

I hope our discussion has aroused your interest in UIM list applications. I know there are die-hard sticklers to DDS who would not try anything else even if you put a gun to their head. For them it's DDS or nothing. Well, fine! Stick to DDS; it has its own kicks, too. But for those of us who are more amiable to change (and I sure hope we're in the majority); for those who are eager to try out some new idea or new product to see if it offers some benefits; for the daring and courageous who like new challenges, I present the UIM alternative. Try it, and you'll go UIM the rest of the way.


The WRKUSR Utility

The WRKUSR utility offers an alternative way of working with user profiles. It presents a panel similar to IBM's Work with User Profiles panel, but with several additional features.

  • It has two more columns — for user class and group profile — which give you more information at a glance (Figure 3a).
  • It provides a function key, F16, for resequencing the list of user profiles by user, class, group, or text. For instance, if you position the cursor on the Class column and press F16, the utility reorders the list of users by user class. This alternative comes in handy when you want to work with users of a particular class or group profile.
  • It has a flexible search facility that depends on the way the list is ordered. You can search by user profile, user class, group profile, or text description. If, like most people, you enter users' names in the text description of their profiles, this utility gives you a way of searching for users by name.
  • You can print a list of user profiles from the utility's main panel by pressing F21. The printout includes a column that tells you the percentage of each user's allowed storage that user has used. A value of 0.00% means the user's storage is not limited — in other words, that the user's maximum allowed storage is *NOMAX (fig.3c).
  • It lets you rename a user profile by choosing option 7.
  • It lets you duplicate a user profile by choosing option 3. This option is similar to the copy option supplied by IBM, but has the added feature of letting you duplicate the user's object authorities.
Installing WRKUSR

WRKUSR utility has many objects — 14 in all. To create each one manually could be a burden, so I also provide a source member, CRTWRKUSR, that contains the create commands for the objects. You can compile this member into a CL program, which you can then call to install the utility.
— A.O.


DUPUSRPRF and RNMUSRPRF

The WRKUSR utility also uses two other commands I created: the DUPUSRPRF and RNMUSRPRF commands. To get the most from WRKUSR, you should also create these commands. Here's how:

1. Create the commands:


CRTCMD CMD(library/DUPUSRPRF)  +
       PGM(DUPUSPFC)           +
       SRCFILE(QCMDSRC)        +
       HLPPNLGRP(DUPUSPFH)     +
       HLPID(*CMD) 

CRTCMD CMD(library/RNMUSRPRF)  +
       PGM(DUPUSPFC)           +
       SRCFILE(QCMDSRC)        +
       HLPPNLGRP(DUPUSPFH)     +
       HLPID(*CMD)
2. Create help panel group DUPUSPFH:

NLGRP PNLGRP(library/DUPUSPFH) +
          SRCFILE(QPNLSRC)
3. The next step is to create the processing programs. But first, notice that CL program DUPUSPF1C contains some commented-out lines that contain the annotation "V3.1." These lines reflect changes IBM made to the CRTUSRPRF (Create User Profile) command in Version 3 of OS/400. If you're on Version 3, remove the comment marks from these lines before creating the program. Then create the processing programs using the following commands:

LPGM PGM(library/DUPUSPFC)       +
         SRCFILE(QCLSRC)

CRTCLPGM PGM(library/DUPUSPF1C)  +
         SRCFILE(QCLSRC)

CRTRPGPGM PGM(library/DUPUSPFR)  +
          SRCFILE(QRPGSRC)

Azubike Oguine is an associate analyst with Chevron Nigeria, Ltd., in Lagos, Nigeria. You can reach him by e-mail at azub@chevron.com; by phone at (234) 12600600, extension 8047; or by fax at (234) 12600395.

ProVIP Sponsors

ProVIP Sponsors