かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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);
    }
}