Skip to Content

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

To report this post you need to login first.

13 Comments

You must be Logged on to comment or reply to a post.

  1. Hi ,

    As i was also one of those who used your first TreeByNestingTable column application i can say that both have been very very informative and very useful !

    The application has been designed wonderfully ! Learnt a lot from that !

    Thanks
    Bharathwaj

    (0) 
    1. Valery Silaev Post author
      Thanks for kind feedback.
      Stay tuned, there are 2 other articles on this topic: handling selection and synchronizing view selection plus automatic categorization.

      VS

      (0) 
      1. pradeep bondla
        Hi VS,
        Great blog useful after soo many years also…
        We have implemented it and its working very well. but I need one more functionality in this, I want the text also to have link and when clicked on text it should show the child nodes same as it behaves when clicked on arrow image.
        How to achieve this?
        (0) 
  2. Ivan Belic
    Hi Valery,

    great example you showed us on SDN.

    I have 3 questions (well, one problem and two questions :):

    1. I’m getting this error when trying to build component (I’m using sp12)
    Web Dynpro Generation: Metadata constraint of Component TreeTable is violated: ViewElementAggregation “//WebDynpro/View:com.sap.sdn.samples.moc.components.views.TreeTableCV/RootUIElementContainer/Child:tblEntries/OutgoingAggregation:GroupedColumns”, Role “Definition”: A minimum of 1 object(s) is required       TreeTable.wdcomponent   SDN_TREE_TABLE/src/packages/com/sap/sdn/samples/moc/components

    2. how did you managed to get parameter from url into your app?

    p.s. it looks like you have some xApps libraries in your java build path, I hope they are not relevant for the project so they can be removed?

    Tnx in advance!

    BR, Ivan

    (0) 
    1. Valery Silaev Post author
      From simple to complex:
      a. I do not have any xApps dependencies on build path, could you enumerate entries that looks like xApps ones?
      b. Check TreeTableCWInterfaceView[.wdcontroller] method onPlugDefault and relevant init method in component controller for URL parameters processing
      c. Hmm… I really don’t know whats going wrong etadata. Btw, what version + build id reports yours IDE “About…” dialog?

      Also it is not a best advise from code author, but could you re-create view table from scratch?

      Thanks for feedback,
      VS

      (0) 
      1. Ivan Belic
        a)
        ‘C:ProgramFiles/SAP/JDT/eclipse/plugins/com.sap.sld.client/lib/sldclient.jar’
        ‘C:ProgramFiles/SAP/JDT/eclipse/plugins/com.sap.tc.webdynpro.runtime/lib/_webdynpro_portal.jar’
        ‘C:ProgramFiles/SAP/JDT/eclipse/plugins/com.sap.tc.webdynpro.runtime/lib/cache_api.jar’
        ‘C:ProgramFiles/SAP/JDT/eclipse/plugins/com.sap.tc.webdynpro.runtime/lib/cache_plugins.jar’
        ‘C:ProgramFiles/SAP/JDT/eclipse/plugins/com.sap.tc.webdynpro.runtime/lib/cachemgmt.jar’

        b) tnx 🙂

        c) Version: 2.0.12
        Build id: 200505090134

        I’ll try to re-create table, and get back with results.

        p.s. name.surname@companyname.com doesn’t work 🙁

        BR, Ivan

        (0) 
        1. Valery Silaev Post author
          oooppssss!
          My IDE:
          Version 7.0.0
          200503310418

          Plugins mentioned are not part of xApps, they are standard… in 7.0… :))

          I try to re-build project with SP12 and update example project

          vsilaev AT gmail DOT com

          VS

          (0) 
            1. Valery Silaev Post author
              Yes, if volonteer tester is a priviledged role 😉
              BTW, I have updated example application — not it really works with SP12

              VS

              (0) 
  3. Konstantin Momchev
    Hi Valeri,

    Thanks for the helpful article!

    I have one little problem. In my master column, when user clicks on some tree node, it has to be selected, i.e. the tree selection to be moved.

    Instead, the node is only expanded or collapsed, without any selection change.

    I am using SP15, but it is the same for the previous versions.

    Is it possible to configure master column like this?

    Thanks in advance
    Konstantin

    (0) 
    1. Valery Silaev Post author
      Konstantin,

      Please read this post [New Web Dynpro Sample available – Enhancing Table Performance] by Bertram Ganz.

      Pay special attention to matrix in related PDF that describes when lead selection in table is changing (depending on compatability mode, read-only property and click area)

      If it doesn’t help, then (again, using Bertram’s article) you may set cell editor in master column to link2action and handle onAction to move selection manually.

      VS

      (0) 

Leave a Reply