Additional Blogs by Members
cancel
Showing results forย 
Search instead forย 
Did you mean:ย 
Former Member
0 Kudos

UPDATE: Intorspector example has been updated to support SP12

...or should I say "The Lord Of The Columns" ๐Ÿ˜‰

This blog entry tries to answer one of the most popular questions on SDN WebDynpro forum: how to use new SP11 TreeTable UI control. To be exact, it is same old Table UI control with extremely useful addition – TreeByNestingTableColumn (Master Column). However, usage of this control requires special techniques for populating related context nodes and handling row selection

Here are several real-life examples of hierarchical context you probably want to display using TreeTable:

  1. Organizational structure – this type of structure could be described as whole organization (root) with divisions (direct children of root) with following organization units.
  2. File system and alike – hierarchy of folders and files; entry on every level may have sub-folder entries (sub-nodes) as well as file entries (leaves)
  3. Categorized list – list of materials with grouping by vendor; list of bugs grouped by severity etc.
  4. Grouped relations. Consider you have a list of software products. There are also 3 lists related to every product: enhancements requests, bug reports and compatibility issues. All of the related lists have common attributes' set: title, author, brief description and date posted. You'd like to display list of products (root) with the following item categories repeated for every product (enhancements, bugs, compatibility issues) and nested items as leaves.

So, the requirement to display nested (hierarchical) structures within Table UI control is quite common. However, before SP11 developers had to resort to Tree + Table combination as workaround. Or develop some complex solutions like CAF FlexTree UI Pattern (probably, I will discuss it in my next posts). Fortunately, SP11 address this issue, but it was not accompanied with introductory article about new functionality. So let us fill this gap.

As far as this post is accompanied with sample project I don't spend a lot of time describing every mouse click, only the major points are highlighted. I'm currently using NW SP12, therefore my sample will not work with previous versions. However, you may download another sample that I has posted on WebDynpro forum. It is a server's file system viewer application that displays folders structure using Tree & TreeTable UI controls side-by-side. I can safely confirm that this sample is self-explanatory – more then 10 SDN members try it out and found usable with (almost) no additional questions.

New example represent another “useful” tool - we will create Java class introspector, that outlines class methods and recursively iterates over inheritance chain via all implemented interfaces and super-classes starting from the given class.

First of all we have to create and populate recursive context node while table itself should be bound to recursive node. Recursive node is quite special beast in WD world. First, you have to declare regular node in context (it could be either Value or Model node). Second, you have to add Recursion node right after the node you'd like to be repeated, and set its “recursiveNode” property to parent node. See image below:

image

Image 1. Context structure of Component Controller.

Here is one important point to note. As far as our recursive node will represent properties for classes as well as methods, we have to include union of all properties for both of them. Therefore you will see that node contains Signature attribute that is valid for methods but not valid for classes. Also we need a way to differentiate between 2 type of entries. Signature is a good candidate itself, but here we will use Clazz attribute of type java.lang.Class. Any class entry will have this attribute set – this allows us to discover (a) super-class or super-interfaces and (b) declared methods in supply function. Any entry that relates to method will have null for Clazz attribute.

Here is the code to populate Entries node:

public void supplyEntries(IPrivateTreeTable.IEntriesNode node, com.sap.tc.webdynpro.progmodel.api.IWDNodeElement parentElement) { //@@begin supplyEntries(IWDNode,IWDNodeElement) if ( parentElement == wdContext.currentContextElement() ) { /* Create root entry and return */ newClassEntry( _clazz, node ); return; } final Class clazz = (Class)parentElement.getAttributeValue("Clazz"); /* * During recursive roll-out we will reach methods * For method entry class is null and hence * we will not drill down deeper * */ if ( null == clazz ) return; final List parents = new ArrayList( Arrays.asList(clazz.getInterfaces()) ); if ( null != clazz.getSuperclass() ) parents.add(0, clazz.getSuperclass() ); for (final Iterator i = parents.iterator(); i.hasNext(); ) { newClassEntry( (Class)i.next(), node ); } final Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; final IPublicTreeTable.IEntriesElement elEntry = node.createEntriesElement(); elEntry.setName( method.getName() ); elEntry.setIsLeaf( true ); elEntry.setSignature( method.toString() ); elEntry.setModifiers( method.getModifiers() ); elEntry.setIsChildrenLoaded( true ); node.addElement( elEntry ); } //@@end } //@@begin others private void newClassEntry(final Class clazz, final IPublicTreeTable.IEntriesNode node) { final IPublicTreeTable.IEntriesElement elEntry = node.createEntriesElement(); elEntry.setClazz( clazz ); elEntry.setName( clazz.getName() ); elEntry.setModifiers( clazz.getModifiers() ); node.addElement( elEntry ); } /* Pre-setup with some valid sample */ private Class _clazz = ObjectInputStream.class; //@@end


So far we have created recursive node Entries (+ recursion node SubEntries) in context of Component Controller. I always prefer to locate business logic in non-visual controllers (either Component Controller or Custom Controllers). You may consider this habit as one of “best practices” while in case of enhancements context and methods of these controllers could be shared between several views (and it is impossible to reuse View Controllers). Also data-retrieval logic is not polluted with display logic.

Next we have to develop our view. First of all we add Component Controller usage via Required Controllers on Properties tab for corresponding view. Next task is to map view context to component controller context. Note, that you are unable to map recursion node itself, so you have to re-create it in view controller context (you may name it as you whish, however it is better to keep names in both controllers the same for readability) and set recursiveNode property.

You may note that not all attributes are mapped – some of them are created in view context. The most important is IsExpanded (boolean). It is required for TreeByNestingTableColumn UI control. Other attributes (EntryIcon & AccessIcon) convert Modifiers flag to corresponding icons.

image

Image 2. Context of view Controller


Next task is to create Table UI control and add Master Column:

image

Image 3. Insert Master Column

I have to mention one subtle difference between file system viewer and introspector samples. When I wrote the former, I do not pay attention that I may add cell editor directly to Master Column. That's why I create a separate column for file / folder name. To be fair, result looks pretty ugly. So in Introspector sample we add Caption editor directly to Master Column and enjoy professionally looking design ๐Ÿ™‚

After adding MasterColumn to table you have to map it properties to attributes of Entries context node (childrenLoaded, expanded, isLeaf). Adding the rest of columns is trivial.

image

Image 4. Setup Master Column

We are almost done here. The only thing left is to add LoadChildren action handler to view. Why wee need this handler at all? The answer is quite interesting.

I admit an important variation in TreeTable behavior between SP11 and SP12. If no LoadChildren action was defined for TreeTable in SP11, then control force validation of all recursive nodes, hence load time was significant (especially with file system example). SP12 handles loading differently (and more developer-friendly) even when LoadChildren is undefined: if childrenLoaded property for corresponding element returns true, no subsequent requests are sent, if it is false then request is sent lazily only when level is being expanded for first time. So if you want to port this sample to SP11 you need such action handler (or at least it is better to know it exists).

Another reason is that I'm adjusting IsLeaf attribute in this handler. Initially only method entries marked as leaves. But in Java certain interfaces are just markers (java.io.Serializable, java.lang.Cloneable etc.) with no methods / super-interfaces. Instead of verifying their nesting structure in supply function, I perform check only on demand. You might see the same behavior in Windows Explorer.

So first we create Action (pay attention to class of parent parameter and be ready to type it manually -- NetWeaver IDE does not allow to select inner class in corresponding dialog):
image

Image 5. Adding LoadChildren action

And the related code:

1. This one for wdDoModifyView

if ( firstTime ) { final IWDTreeByNestingTableColumn master = (IWDTreeByNestingTableColumn)view.getElement("mcEntries"); master.mappingOfOnLoadChildren().addSourceMapping ( /* IWDAbstractMasterTableColumn.IWDOnLoadChildren.PATH */ "path", "parent" ); }

2. And this one for action handler:

if ( parent.getIsChildrenLoaded() ) return; parent.setIsLeaf( parent.nodeSubEntries().size() == 0); parent.setIsChildrenLoaded( true );

I don't know what the hell happens with my IDE, but it doesn't see IWDAbstractMasterTableColumn.IWDOnLoadChildren type any more. Hence corresponding reference is commented out and string contstant used instead.

Done. Well, almost done ๐Ÿ˜‰ Bundled example contains logic to accept class name via URL parameter and use this class for introspection. Actual invocation URL looks like http://localhost:50000/webdynpro/dispatcher/local/SDN_TREE_TABLE/Introspect?clazz=java.util.Calendar. Sure you may use other existing class as parameter to check its' internals.

Download projects mentioned here:
File System Viewer
Class Introspector

Till next time when we discuss how to handle row selection in TreeTable and selecting specific row from code.

image

Image 6. Introspecting java.lang.String class

13 Comments