Welcome!

PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder

PowerBuilder: Article

PowerBuilder - The ClassDefinition Object

...or how to create a simple object browser - Part 2

In the first article we presented a some theories about the ClassDefinition object and were able to show the libraries of a PB application in a treeview control. This month we'll read the objects from the libraries and inspect their content.

When a user expands an entry in the treeview, we check to see if it was expanded once already. If it was, we don't take any action. We code this in the itemexpanding event of the treeview control, where we get the clicked treeviewitem by calling This.GetItem.

If it wasn't expanded already, we check to see if the level of the treeviewitem is equal to two, which means we're expanding a library name. We could create an NVO to include all the logic for parsing, but for demonstration purposes, I want to keep things simple. We define all the functions we need on the window itself, but use arguments to refer to the controls. This will let you move the logic to an NVO quite easily later.

The next function we create is called of_ShowLibraryItems. It's used to read the PB objects from a PBL. I use the function LibraryDirectoryEx to extract the objects. Compared to the function LibraryDirectory, it provides the date/time modified and the comment as well as the name and type of the objects. Since I want the objects sorted, I use a DataWindow with an external datasource. See Figure 1 for the definition of a DataWindow. Set the sorting to the column objtype and save it as d_libobj.

The string returned byLibrary-DirectoryEx will be imported into the datastore by the ImportString. After sorting the data, the script loops through the objects and adds them to the treeview. You can find the code for this function in Listing 1. Call the of_ShowLibraryItems function in the itemexpanding event of the treeview control when the level is 2, whereas the ll_TviCurrent is the treeviewitem identified by the handle argument.

Parent.of_ShowLibraryItems( This, handle, ltvi_Current.Data )

On to Class Details
The application so far shows the libraries and the PB objects located in them. Now it's time for the classdefinitionobject object and its descendants. As you saw last month, we'll display the information in various child entries. The first part is called Variables where we list all the variables of this object. In the second section we have the scripts and in the third section the nested classes. Finally the last section includes a reference to the ancestor of the class. The idea behind the functions we create is that they can be called recursive and be used for each type of PB object.

It's impossible to loop through the variable list of the ClassDefinition object of a PB object and display all the information about it nicely. So the next step is creating two helper functions. The first is called of_ValueString and translates the enumerated values to strings (see Listing 2). The arguments of this function are the type of a variable (e.g., Cardinality or InitialValue) and the value itself. It returns both as a readable string. Converting the value to a string is simple with, say, Boolean values; however if we have enumerated data types we have to handle them individually. If the variable is an enumerated datatype we use the FindTypeDefinition get all the possible enumerations of this datatype.

The second function is called of_FormatInfo (See Listing 3) and takes a classdefinitionobject as its argument. Its purpose is to create a formatted string out of the classdefinitionobject information. The argument is a classdefinitionobject type, which lets us pass variables of type classdefinition, scriptdefinition, and variabledefinition.

Display the Information about a Class
Having set up the helper functions, let's go back to the treeview. When we expand a PB object in the treeview, we have to call the function of_ShowClassDefinition. The definition of the function is available online in Listing 4. It takes three arguments: the treeview control, the handle of the clicked item, and a ClassDefinition object. For the first level of information the ClassDefinition object is determined by a call to the FindClassDefinition function where the argument equals the label of the treeview item. Here is the code in the itemexpanding event of the treeview when the level is greater than two. The variable lcd_Temp is a ClassDefinition type and ll_Child is a long type:

ll_Child = This.FindItem( ChildTreeItem!, handle )
IF ll_Child = -1 THEN // No children yet
    lcd_Temp= FindClassDefinition (&
      ltvi_Current.Label,il_LibList )
    IF NOT IsNull(lcd_Temp) THEN
      Parent.of_ShowClassDefinition(&
        tv_1,handle,lcd_Temp)
    END IF

END IF
The variable section is filled by looping through the VariableList property of the ClassDefinition, using the IsControl properties to prevent adding controls and IsUserDefined to set the picture of the treeviewitem. For each variable the of_ShowVarible function (see Listing 5) is called to fill the variable information into the data property of the treeviewitem. After handling the variables, the function goes on to the scripts. For each entry in the ScriptList property of the ClassDefinition, the function of_ShowScript (Listing 6) is called. Here we use the properties IsLocallyScripted and IsScripted to set the picture of the treeviewitem. The data property of the treeviewitem is used for general information about the script. For each script we add, there is an entry Source (saving the source of the script) called ArgumentList and another one called LocalVariableList. We add each argument variable and each local variable including their definitions under the appropriate entry by calling the function of_ShowVariable with each variable. To compile you have to define of_ShowVariableFirst, then of_ShowScript, and then of_ShowClassDefinition.

Then the nested classes are shown. The naming convention of a nested class is objectname`nestedclassname. We need the whole name to find more information about the nested class when calling FindClassDefinition. For nested classes we check the property ParentClass. If this is null we don't add the class. Further the NestedClassList returns not only the controls on an object, but also the controls on the ancestor of the object. We prevent showing ancestor data by comparing the name of the ParentClass of the NestedClass with the name of the current object. If they don't match, the control is inherited from the ancestor. At the end of this list we add an entry for the ancestor object if there is one.

To display the additional information stored in the data property of the treeview items you have to put the following code in the selectionchanged event of the treeview:

treeviewitem ltvi_Current

This.Getitem(newhandle,ltvi_Current)
IF ClassName(ltvi_Current.data)="string"THEN
      mle_1.Text=ltvi_Current.Data
ELSE
      mle_1.Text=""
END IF
RETURN

When running the application and expanding a library entry, all the information of the entry itself is loaded at once. We don't parse information about nested classes and no information about possible ancestors is retrieved (except its name). On large objects this might take some time. To drill down on an entry you have to expand the item in the treeview. If it's a nested class or ancestor class and the data isn't loaded, the ClassDefinition object of the chosen entry is retrieved by FindClassDefiniton and the function of_ShowClassDefinition is called, passing the ClassDefinition object as an argument. Since the ClassDefinition object is available to all PB classes, no further coding is required and our application is ready to browse. Browsing PFC-based applications is quite interesting and lets you drill down many levels.

You can download the source code of the application from the PBDJ Web site or from the download section of the CATsoft Web site at www.catsoft.ch.

Conclusion
I hope this gives you a basic understanding of the ClassDefinition object and related objects. Creating a browser for PB objects is one possible use of these objects. Maybe you can make use of it in an application, where you need to get information about an object's inheritance or the availability of a certain function (see the function FindMatchingFunction). Another possible use might be the dynamic creation of WSDL files for a Web Service.

More Stories By Arthur Hefti

Arthur Hefti is CEO of CATsoft Development GmbH in Zurich. He has been working with PowerBuilder since version 3 and taught dozens of PowerBuilder training classes. He and his team create custom-made client/server and Web applications using XML, Web Services, and encryption.

Comments (1) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
PBDJ News Desk 05/19/06 10:42:08 AM EDT

In the first article we presented a some theories about the ClassDefinition object and were able to show the libraries of a PB application in a treeview control. This month we'll read the objects from the libraries and inspect their content. When a user expands an entry in the treeview, we check to see if it was expanded once already. If it was, we don't take any action.