TreeGrid will now show hierarchy

I’ve built my first TreeGrid component and I can’t get TreeGrid to display the hierarchy. The table is rendered flat without any tree structure.

The debug in my container class indicates the items are added with the proper hierarchy.

I’m using TreeGrid 0.7.4 and Vaadin 7.7.7.

Here’s my table class:

[code]
mport java.util.List;

import org.vaadin.treegrid.TreeGrid;

import com.magnicomp.model.Group;
import com.magnicomp.vaadin.model.container.GroupContainer;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Grid;

@SuppressWarnings(“serial”)
public class GroupTable extends TreeGrid {
private List<? extends Group> groups;

public GroupTable(List<? extends Group> items) {
    setGroups(items);
    init();
}

private void init() {
    setContainerDataSource(createContainer());
    setSelectionMode(Grid.SelectionMode.SINGLE);
    setColumnReorderingAllowed(true);
    setHierarchyColumn(GroupContainer.PROP_NAME);
    setColumns(GroupContainer.PROP_NAME, GroupContainer.PROP_DESC);
}

private IndexedContainer createContainer() {
    List<? extends Group> items = getGroups();
    GroupContainer container = new GroupContainer(items);
    return container;
}

protected List<? extends Group> getGroups() {
    return groups;
}
protected void setGroups(List<? extends Group> groups) {
    this.groups = groups;
}

}
[/code]Here is my container class:

import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import org.vaadin.treegrid.container.Measurable;

import com.magnicomp.common.Validate;
import com.magnicomp.except.OperationFailedException;
import com.magnicomp.except.RecursionException;
import com.magnicomp.model.Group;
import com.magnicomp.model.GroupType;
import com.magnicomp.model.Origin;
import com.magnicomp.trace.Trace;
import com.magnicomp.trace.TraceFactory;
import com.magnicomp.ui.container.GroupContainerBuilder;
import com.magnicomp.ui.property.GroupPropertyManager;
import com.magnicomp.vaadin.model.container.GroupContainer;
import com.vaadin.data.Collapsible;
import com.vaadin.data.Item;
import com.vaadin.data.util.HierarchicalContainer;

@SuppressWarnings("serial")
public class GroupContainer extends HierarchicalContainer implements Collapsible, Measurable {
    private Trace                        log = TraceFactory.create(this);
    private List<? extends Group>        groups;
    private HashMap<Group,Object>        entityToItemId = new HashMap<>();
    private HashMap<Object,Group>        itemIdToEntity = new HashMap<>();
    private HashMap<Object,Boolean>        expandedNodes = new HashMap<>();
    
    /*
     * Use property name values which match the Hibernate entity names.
     */
    public final static String PROP_OBJECT = GroupContainerBuilder.PROP_OBJECT;
    public final static String PROP_NAME = GroupPropertyManager.ID_NAME;
    public final static String PROP_DN = GroupPropertyManager.ID_DISTINGUISHEDNAME;
    public final static String PROP_LABEL = GroupPropertyManager.ID_LABEL;
    public final static String PROP_DESC = GroupPropertyManager.ID_DESCRIPTION;
    public final static String PROP_PARENT_NAME = GroupPropertyManager.ID_PARENT;
    public final static String PROP_CANONICALSOURCE = GroupPropertyManager.ID_CANONICALSOURCE;
    public final static String PROP_ID = GroupPropertyManager.ID_ID;
    public final static String PROP_ORIGIN = GroupPropertyManager.ID_ORIGIN;
    public final static String PROP_TYPE = GroupPropertyManager.ID_TYPE;
    
    public GroupContainer(List<? extends Group> groups) {
        this.groups = groups;
        init();
    }
    
    private void init() {
        String        m = "init";
        int            d = 0;
        
        log.debug(m, d, "Initializing");
        
        addContainerProperty(PROP_OBJECT, Group.class, null);
        addContainerProperty(PROP_NAME, String.class, "");
        addContainerProperty(PROP_PARENT_NAME, String.class, "");
        addContainerProperty(PROP_DESC, String.class, "");
        addContainerProperty(PROP_DN, String.class, "");
        addContainerProperty(PROP_LABEL, String.class, "");
        addContainerProperty(PROP_CANONICALSOURCE, String.class, "");
        addContainerProperty(PROP_ID, String.class, "");
        addContainerProperty(PROP_ORIGIN, Origin.class, null);
        addContainerProperty(PROP_TYPE, GroupType.class, null);
                
        populateItems();
    
        showDebugTree();
//        log.debug(m, d+1, "Sorting container");
//        boolean ascending = true;
//        sort(new Object [] { PROP_NAME }, new boolean []
 { ascending });
    }
     
    private void showDebugTree() {
        String    m = "showDebugTree";
        int        d = 0;
        
        for (Object itemId : getItemIds()) {
            Group group = itemIdToEntity.get(itemId);
            log.debug(m, d, "ITEM Group: \"%s\" ID: %s", group.getName(), itemId);
            Collection<?> childrenIds = getChildren(itemId);
            if (childrenIds != null && childrenIds.size() > 0) {
                for (Object childId : childrenIds) {
                    Group child = itemIdToEntity.get(childId);
                    log.debug(m, d+1, "CHILD Group: \"%s\" ID: %s", child.getName(), itemId);
                }
            }
        }
    }
    
    private void populateItems() {
        String    m = "populateItems";
        int        d = 0;
        
        log.debug(m, d, "Populating Entity data");
        
        for (Group group : groups) {
            if (entityToItemId.get(group) != null)
                continue;
            
            populateItem(group, 0);
        }
    }
    
    /***
     * -RECURSE-
     * Populate the given item in the container.
     * @param group
     * @param depth
     * @return
     */
    @SuppressWarnings("unchecked")
    private Object populateItem(Group group, int depth) {
        String        m = "populateItem";
        int            d = depth;

        if (depth >= 100)
            throw new RecursionException("Recursion problem at depth " + depth);
        
        // Sanity check
        if (group == null || group.getName() == null)
            return null;

        log.debug(m, d, "Group: \"%s\" dbID: %s", 
                group.getName(), group.getDbID());

        Group parent = group.getParent();
        Object parentId = null;
        if (parent != null) {
            log.debug(m, d+1, "Parent is \"%s\"", parent.getName());
            parentId = entityToItemId.get(parent);
            if (parentId == null) {
                /*
                 * -DESCEND-
                 * Parent has not yet been added so do so now
                 */
                log.debug(m, d+1, "Add parent first");
                parentId = populateItem(parent, d+1);
                Validate.notNull(parentId, "PopulateItem for parent failed to return parent ID: " + parent);
                log.debug(m, d+1, "Added parent with ID: %s", parentId);
            }
        }
        
        Object itemId = null;
        if (parentId != null)
            itemId = addItemAfter(parentId);
        else
            itemId = addItem();
        log.debug(m, d+1, "Adding itemId: %s (%s)", itemId, group.getName());
        Item item = getItem(itemId);
        if (item == null)
            throw new OperationFailedException("Group addItem %s failed", itemId);
        
        item.getItemProperty(PROP_OBJECT).setValue(group);
        item.getItemProperty(PROP_NAME).setValue(group.getName());
        item.getItemProperty(PROP_DESC).setValue(group.getDescription());
        // Always set the PARENT property even if null
        item.getItemProperty(PROP_PARENT_NAME).setValue((parent != null) ? parent.getName() : null);
        item.getItemProperty(PROP_DN).setValue(group.getDistinguishedName());
        item.getItemProperty(PROP_LABEL).setValue(group.getLabel());
        item.getItemProperty(PROP_CANONICALSOURCE).setValue(group.getCanonicalSource());
        item.getItemProperty(PROP_ID).setValue(group.getID());
        item.getItemProperty(PROP_ORIGIN).setValue(group.getOrigin());
        item.getItemProperty(PROP_TYPE).setValue(group.getType());

        if (parentId != null) {
            log.debug(m, d+2, "Set itemID %s parent to %s (%s)", 
                    itemId, parentId, (parent != null) ? parent.getName() : null);
            setParent(itemId, parentId);
        }

        boolean childrenAllowed = (group.getChildren() != null && group.getChildren().size() > 0) ? true : false;
//        setChildrenAllowed(itemId, childrenAllowed);
        setChildrenAllowed(itemId, true);
        
        entityToItemId.put(group, itemId);
        itemIdToEntity.put(itemId, group);
        
        return itemId;
    }

    @Override 
    public int getDepth(Object itemId) { 
        String    m = "getDepth";
        int        d = 0;

        int depth = 0; 
        while (!isRoot(itemId)) { 
            depth ++; 
            itemId = getParent(itemId); 
        } 
        log.debug(m, d, "ItemID: %s Depth: %s", itemId, depth);
        return depth; 
    }
    
    @Override 
    public boolean hasChildren(Object itemId) {
        Group group = itemIdToEntity.get(itemId);
        Validate.notNull(group, "Unable to find group for itemID: " + itemId);
        boolean value = (group.getChildren() != null && group.getChildren().size() > 0) ? true : false;
        return value;
    } 

    @Override
    public void setCollapsed(Object itemId, boolean collapsed) {
        String    m = "setCollapsed";
        int        d = 0;
        
        log.debug(m, d, "Set collapsed itemID: %s Collapsed: %s", itemId, collapsed);
        expandedNodes.put(itemId, !collapsed);
    }

    @Override
    public boolean isCollapsed(Object itemId) {
        Boolean collapsed = expandedNodes.get(itemId);
        if (collapsed == null)
            return false;
        return collapsed;
    }

}

Hi Mike,

Make sure that you are calling
super()
in
GroupTable
's constructor.
TreeGrid
's constructor is adding important extensions such as the hierarchy generator to the component.

Adam

If I debug and step through I do see that my app goes through this:

    public TreeGrid() {
        super();

        // Replace GridServerRpc with custom one to fix column reorder issue (#6).
        swapServerRpc();

        // Attaches hierarchy data to the row
        HierarchyDataGenerator.extend(this);

        // Override keyboard navigation
        NavigationExtension.extend(this);
    }

I used the extend TreeGrid in my example by mistake actually. My actual application doesn’t extend TreeGrid but creates it separately and adds it to my layout:

TreeGrid grid = new TreeGrid();
layout.add(grid);

In both the example and actual application I see the TreeGrid() code above called.

Hi Mike,

I have the same issue. Did you find a solution or a workarround ?

Thanks

No, I never found a solution. I exchanged a few emails with the developer and opened a bug but it’s not been fixed as far as I know.

Thank you Mike.

Hi Mike,

I managed to solve my issue by adding @include treegrid; in addon.scss (you can check the scss files in the demo example). I also added in my project WidgetSet.

Hope this will help you.

Please run
mvn clean install
to add both
@include treegrid;
to the
addons.scss
and

to your projects
gwt.xml
automatically, in case you have the right configuration in your
pom.xml
, which should be right if you built your project form an archetype.

The indivitual job for adding the inheritance for the scss is
vaadin:update-theme
, while adding the for the widgetset is
vaadin:update-widgetset
. Try running these to include all what you need and rebuild.

You might also be interested in Vaadin Framework 8.1 which adds support for hierarchical data, TreeGrid and Tree.

Hi,
I have requirement in tree grid, once the click on row the child is also another grid based on the parent row value.Is it possible to load another grid component as tree grid child node?

Regards
saju philip