かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

RichFaces4.xのTreeコントロールで選択中の要素を取得する

とりあえずメモメモ。
xhtmlでのポイントは、ajaxでやりたいからselectionTypeをajaxにしているところと、選択結果をレンダリングするためのrenderをoutpanelにしているところです。
outpanelは、ただのoutputTextです。

その他の、toggleTypeをajaxにしたりtreeModelRecursiveAdapterは、ここの本質的な内容じゃないです。

<h:form>
    <h:panelGrid columns="2" columnClasses="col1,col2">
        <rich:tree var="item" toggleType="ajax" selectionType="ajax"
                   render="outpanel"
                   selectionChangeListener="#{indexPage.selectionChange}">
            <rich:treeNode>
                <h:outputText value="#{item.name}" />
            </rich:treeNode>
            <rich:treeModelRecursiveAdaptor 
                roots="#{indexPage.roots}" 
                nodes="#{item.items}" 
                leaf="#{item.leaf}" />
        </rich:tree>
        <rich:panel>
            <h:outputText id="outpanel" value="#{indexPage.selectedItem.name}" />
        </rich:panel>
    </h:panelGrid>
</h:form>

Javaのほうは、Treeに表示するためのデータのItemクラス。延々と子要素を持つツリー構造のデータです。

package sample.mavenproject2;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

public class Item implements Serializable {

    private static Random RANDOM = new Random();
    private List<Item> items;
    private UUID id;
    private String name;
    private boolean leaf;

    public Item() {
        this.id = UUID.randomUUID();
        this.items = new ArrayList<>();
        leaf = RANDOM.nextBoolean();
    }

    public Item(String name) {
        this();
        this.name = name;
    }

    public List<Item> getItems() {
        if (this.isLeaf()) {
            return items;
        }
        
        if (this.items.isEmpty()) {
            for (int i = 0; i < 10; i++) {
                this.items.add(new Item(this.getName() + "-" + i));
            }
        }
        
        return items;
    }

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isLeaf() {
        return leaf;
    }
}

initで、適当なデータを作るメソッドはおいといて、ポイントはselectionChangeメソッドです。このメソッドがrich:treeタグでselectionChangeListenerに設定したメソッドです。
引数に、TreeSelectionChangeEventを持つ点がUIコンポーネントに依存しそうなのが個人的に嫌な感じです。
あとは、rowkeyを一時的に差し替えてgetRowDataメソッドで選択中のデータを取得しています。ここらへんハック的な感じがするので個人的に嫌ですね・・・。
ここらへんは、UITreeUtilsクラスにあるように何処かにかくしてしまいたいですね。

package sample.mavenproject2;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.richfaces.component.UITree;
import org.richfaces.event.TreeSelectionChangeEvent;

@ManagedBean
@ViewScoped
public class IndexPage implements Serializable {

    private static final long serialVersionUID = 1L;
    private List<Item> roots;
    private Item selectedItem;

    @PostConstruct
    public void init() {
        this.roots = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            this.roots.add(new Item("Item-" + i));
        }
    }

    public void selectionChange(TreeSelectionChangeEvent event) {
        this.setSelectedItem(UITreeUtils.getSelectedData(Item.class, event));
    }

    public List<Item> getRoots() {
        return roots;
    }

    public void setRoots(List<Item> roots) {
        this.roots = roots;
    }

    public Item getSelectedItem() {
        return selectedItem;
    }

    public void setSelectedItem(Item selectedItem) {
        this.selectedItem = selectedItem;
    }
}

class UITreeUtils {
    public static <T> T getSelectedData(Class<T> clazz, TreeSelectionChangeEvent event) {
        UITree tree = (UITree) event.getComponent();
        List<Object> selection = new ArrayList<>(event.getNewSelection());
        if (selection.isEmpty()) {
            return null;
        }
        
        Object rowKey = tree.getRowKey();
        tree.setRowKey(selection.get(0));
        Object result = tree.getRowData();
        tree.setRowKey(rowKey);
        return clazz.cast(result);
    }
}