/******************************************************************************
* Copyright (C) 2008 Low Heng Sin *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.adempiere.webui.component;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import org.compiere.model.MTree;
import org.compiere.model.MTreeNode;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.zkoss.lang.Objects;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.SimpleTreeNode;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treecol;
import org.zkoss.zul.Treecols;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.event.TreeDataEvent;
/**
*
* @author Low Heng Sin
*
*/
public class SimpleTreeModel extends org.zkoss.zul.SimpleTreeModel implements TreeitemRenderer, EventListener {
/**
*
*/
private static final long serialVersionUID = -4649471521757131755L;
private static final CLogger logger = CLogger.getCLogger(SimpleTreeModel.class);
private boolean itemDraggable;
private List<EventListener> onDropListners = new ArrayList<EventListener>();
public SimpleTreeModel(SimpleTreeNode root) {
super(root);
}
/**
* @param tree
* @param AD_Tree_ID
* @param windowNo
* @return SimpleTreeModel
*/
public static SimpleTreeModel initADTree(Tree tree, int AD_Tree_ID, int windowNo) {
return initADTree(tree, AD_Tree_ID, windowNo, true, null);
}
/**
* @param tree
* @param AD_Tree_ID
* @param windowNo
* @param editable
* @param trxName
* @return SimpleTreeModel
*/
public static SimpleTreeModel initADTree(Tree tree, int AD_Tree_ID, int windowNo, boolean editable, String trxName) {
MTree vTree = new MTree (Env.getCtx(), AD_Tree_ID, editable, true, trxName);
MTreeNode root = vTree.getRoot();
SimpleTreeModel treeModel = SimpleTreeModel.createFrom(root);
treeModel.setItemDraggable(true);
treeModel.addOnDropEventListener(new ADTreeOnDropListener(tree, treeModel, vTree, windowNo));
Treecols treeCols = new Treecols();
tree.appendChild(treeCols);
Treecol treeCol = new Treecol();
treeCols.appendChild(treeCol);
tree.setPageSize(-1);
try {
tree.setTreeitemRenderer(treeModel);
tree.setModel(treeModel);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to setup tree");
}
return treeModel;
}
/**
*
* @param root
* @return SimpleTreeModel
*/
public static SimpleTreeModel createFrom(MTreeNode root) {
SimpleTreeModel model = null;
Enumeration nodeEnum = root.children();
SimpleTreeNode stRoot = new SimpleTreeNode(root, new ArrayList());
while(nodeEnum.hasMoreElements()) {
MTreeNode childNode = (MTreeNode)nodeEnum.nextElement();
SimpleTreeNode stNode = new SimpleTreeNode(childNode, new ArrayList());
stRoot.getChildren().add(stNode);
if (childNode.getChildCount() > 0) {
populate(stNode, childNode);
}
}
model = new SimpleTreeModel(stRoot);
return model;
}
private static void populate(SimpleTreeNode stNode, MTreeNode root) {
Enumeration nodeEnum = root.children();
while(nodeEnum.hasMoreElements()) {
MTreeNode childNode = (MTreeNode)nodeEnum.nextElement();
SimpleTreeNode stChildNode = new SimpleTreeNode(childNode, new ArrayList());
stNode.getChildren().add(stChildNode);
if (childNode.getChildCount() > 0) {
populate(stChildNode, childNode);
}
}
}
/**
* @param ti
* @param node
*/
public void render(Treeitem ti, Object node) {
Treecell tc = new Treecell(Objects.toString(node));
Treerow tr = null;
if(ti.getTreerow()==null){
tr = new Treerow();
tr.setParent(ti);
if (isItemDraggable()) {
tr.setDraggable("true");
}
if (!onDropListners.isEmpty()) {
tr.setDroppable("true");
tr.addEventListener(Events.ON_DROP, this);
}
}else{
tr = ti.getTreerow();
tr.getChildren().clear();
}
tc.setParent(tr);
ti.setValue(node);
}
/**
* Add to root
* @param newNode
*/
public void addNode(SimpleTreeNode newNode) {
SimpleTreeNode root = (SimpleTreeNode) getRoot();
root.getChildren().add(newNode);
fireEvent(root, root.getChildCount() - 1, root.getChildCount() - 1, TreeDataEvent.INTERVAL_ADDED);
}
@Override
public SimpleTreeNode getRoot() {
return (SimpleTreeNode) super.getRoot();
}
@Override
public SimpleTreeNode getChild(Object parent, int index) {
return (SimpleTreeNode) super.getChild(parent, index);
}
/**
* @param treeNode
*/
public void removeNode(SimpleTreeNode treeNode) {
int path[] = this.getPath(getRoot(), treeNode);
if (path != null && path.length > 0) {
SimpleTreeNode parentNode = getRoot();
int index = path.length - 1;
for (int i = 0; i < index; i++) {
parentNode = getChild(parentNode, path[i]);
}
parentNode.getChildren().remove(path[index]);
fireEvent(parentNode, path[index], path[index], TreeDataEvent.INTERVAL_REMOVED);
}
}
/**
* @param b
*/
public void setItemDraggable(boolean b) {
itemDraggable = b;
}
/**
* @return boolean
*/
public boolean isItemDraggable() {
return itemDraggable;
}
/**
* @param listener
*/
public void addOnDropEventListener(EventListener listener) {
onDropListners.add(listener);
}
/**
* @param event
* @see EventListener#onEvent(Event)
*/
public void onEvent(Event event) throws Exception {
if (Events.ON_DROP.equals(event.getName())) {
for (EventListener listener : onDropListners) {
listener.onEvent(event);
}
}
}
/**
* @param treeNode
* @return SimpleTreeNode
*/
public SimpleTreeNode getParent(SimpleTreeNode treeNode) {
int path[] = this.getPath(getRoot(), treeNode);
if (path != null && path.length > 0) {
SimpleTreeNode parentNode = getRoot();
int index = path.length - 1;
for (int i = 0; i < index; i++) {
parentNode = getChild(parentNode, path[i]);
}
return parentNode;
}
return null;
}
/**
* @param newParent
* @param newNode
* @param index
*/
public void addNode(SimpleTreeNode newParent, SimpleTreeNode newNode,
int index) {
newParent.getChildren().add(index, newNode);
fireEvent(newParent, index, index, TreeDataEvent.INTERVAL_ADDED);
}
/**
* @param fromNode
* @param recordId
* @return SimpleTreeNode
*/
public SimpleTreeNode find(SimpleTreeNode fromNode, int recordId) {
if (fromNode == null)
fromNode = getRoot();
MTreeNode data = (MTreeNode) fromNode.getData();
if (data.getNode_ID() == recordId)
return fromNode;
if (isLeaf(fromNode))
return null;
int cnt = getChildCount(fromNode);
for(int i = 0; i < cnt; i++ ) {
SimpleTreeNode child = getChild(fromNode, i);
SimpleTreeNode treeNode = find(child, recordId);
if (treeNode != null)
return treeNode;
}
return null;
}
/**
* @param node
*/
public void nodeUpdated(SimpleTreeNode node) {
SimpleTreeNode parent = getParent(node);
if (parent != null) {
int i = parent.getChildren().indexOf(node);
fireEvent(parent, i, i, TreeDataEvent.CONTENTS_CHANGED);
}
}
}