In this post
you can see a use case for OmniFaces <o:tree>. This is a versatile
component that allows us to put almost anything in a tree structure (e.g. see
the editable tree). Next, we want to obtain a tree with the following features:
·
render tree as a folder tree style
·
collapse/expand folders by clicking on folder's
icons (AJAX based)
·
select files by click the file name (AJAX based)
First, we
write a simple class to encapsulate information about each file/folder. This
class is named ItemEntity
and is listed below (in order to list folder first, you need to define a custom
compareTo()):
package
beans;
import
java.io.Serializable;
import
java.util.Objects;
public class
ItemEntity implements Serializable, Comparable {
private static final long serialVersionUID =
1L;
private String path; // the absolute path of the folder/file
private String name; // the file/folder name
private String size; // the file size in bytes
private String type; // the artifact type: folder or file
private boolean visible; // specific to files for indicating
visibility
private boolean expanded; // specific to
folders for indicating collapse/expand
public ItemEntity() {
}
// for a folder
public ItemEntity(String path, String name,
String type, boolean expanded, boolean visible) {
this.path = path;
this.expanded = expanded;
this.visible = visible;
this.name = name;
this.type = type;
}
// for a file
public ItemEntity(String path, String name,
String type, String size, boolean visible) {
this.path = path;
this.visible = visible;
this.name = name;
this.type = type;
this.size = size;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSize() {
return size;
}
public
void setSize(String size) {
this.size = size;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public int hashCode() {
int
hash = 7;
hash = 29 * hash +
Objects.hashCode(this.name);
return hash;
}
@Override
public int compareTo(Object o) {
ItemEntity it = (ItemEntity) o;
if
(it.getType().equals("folder")) {
return 1;
} else {
return -1;
}
}
@Override
public boolean equals(Object obj) {
if
(obj == null) {
return false;
}
if
(getClass() != obj.getClass()) {
return false;
}
final
ItemEntity other = (ItemEntity) obj;
if
(!Objects.equals(this.name, other.name)) {
return false;
}
return
true;
}
@Override
public String toString() {
return
name + "(" + size + ")";
}
}
Next, we can
use a recursive approach to traverse each folder/file of the given path. Each
file/folder will become an instance of ItemEntity and it will be added in a SortedTreeModel
(one of the TreeModel
implementations). In addition, we need a method responsible to show/hide a
folder content when the user expand (default)/collapse a folder. So, next, we
have a write a bean (TreeBean) that uses the ItemEntity for representing
each artifact obtained via a recursive method (simple folder traversal in a
recursive approach). Each ItemEntity is placed in the SortedTreeModel.
Moreover the showHideItems()
methods is responsabile to show/hide a folder content (node tree children):
package
beans;
import
java.io.File;
import
java.io.Serializable;
import
javax.annotation.PostConstruct;
import
javax.faces.view.ViewScoped;
import
javax.inject.Named;
import
org.omnifaces.model.tree.SortedTreeModel;
import
org.omnifaces.model.tree.TreeModel;
import
org.omnifaces.util.Faces;
@Named
@ViewScoped
public class
TreeBean implements Serializable {
private static final long serialVersionUID =
1L;
private TreeModel<ItemEntity> tree;
private String selected = "none";
@PostConstruct
public void init() {
tree = new SortedTreeModel<>();
// current application folder
//walk(Faces.getRealPath("."), tree);
//
some local folder
walk("D:\\Omnifaces\\blog", tree);
}
public
TreeModel<ItemEntity> getTree() {
return
tree;
}
public void showHideItems(TreeModel<ItemEntity> node) {
ItemEntity folderData =
node.getData();
for (TreeModel<ItemEntity>
children : node.getChildren()) {
ItemEntity fileData =
children.getData();
fileData.setVisible(!folderData.isExpanded());
}
folderData.setExpanded(!folderData.isExpanded());
}
public void selectedFile(String selected){
this.selected = selected;
}
public String getSelected() {
return selected;
}
private void walk(String path, TreeModel<ItemEntity> treem) {
File
root = new File(path);
File[] list = root.listFiles();
if (list == null) {
return;
}
for (File f : list) {
if (f.isDirectory()) {
System.out.println("Directory: " + f.getName());
walk(f.getAbsolutePath(),treem.addChild(new ItemEntity(f.getAbsolutePath(), f.getName(),"folder",true,true)));
} else {
treem.addChild(new
ItemEntity(f.getAbsolutePath(),f.getName(),"file"," (" +
String.valueOf(f.length())+" bytes)", true));
System.out.println("File:
" + f.getName());
}
}
}
}
Finally, the
JSF page uses <o:tree>
to reveal the SortedTreeModel:
<?xml
version='1.0' encoding='UTF-8' ?>
<!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:o="http://omnifaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title></title>
</h:head>
<h:body>
<h3>Selected file: <h:outputText
id="selectedFile"
value="#{treeBean.selected}"/></h3>
<h:panelGroup
id="pathTree">
<h:form id="form">
<o:tree
value="#{treeBean.tree}" var="t"
varNode="node">
<o:treeNode>
<ul type="none">
<o:treeNodeItem>
<li>
<h:panelGroup
rendered="#{t.type eq 'file' and t.visible}">
<h:graphicImage
library="default" name="icons/file.png"
title="#{t.path}" alt="#{t.path}"/>
<h:commandLink value="#{t.name}" action="#{treeBean.selectedFile(t.path)}">
<h:commandLink value="#{t.name}" action="#{treeBean.selectedFile(t.path)}">
<f:ajax
execute="@form" render=":selectedFile"/>
</h:commandLink>
#{t.size}
</h:panelGroup>
<h:panelGroup
rendered="#{t.type eq 'folder' and t.visible}">
<h:commandButton image="resources/default/icons/#{t.expanded ? 'folder_open':'folder_close'}.png"
action="#{treeBean.showHideItems(node)}">
<h:commandButton image="resources/default/icons/#{t.expanded ? 'folder_open':'folder_close'}.png"
action="#{treeBean.showHideItems(node)}">
<f:ajax
execute="@form" render="@form" />
</h:commandButton>
#{t.name}
<o:treeInsertChildren
/>
</h:panelGroup>
</li>
</o:treeNodeItem>
</ul>
</o:treeNode>
</o:tree>
</h:form>
</h:panelGroup>
</h:body>
</html>
Complete
code on GitHub.
You may be also interested in:
Use OmniFaces Tree to render JSON
Building dynamic responsive multi-level menus with plain HTML and OmniFaces by Oleg Varaksin
You may be also interested in:
Use OmniFaces Tree to render JSON
Building dynamic responsive multi-level menus with plain HTML and OmniFaces by Oleg Varaksin
Niciun comentariu :
Trimiteți un comentariu