RichTree not repsonsive - have no clue
patrickmadden Apr 12, 2007 4:03 AMHi,
I am using JBoss Seam 1.2.1 GA and JBoss 4.0.5.GA. I have a lot of things working but for some reason I can't get my tree to function at all. I've been grabbing most of the snapshot jars nightly of RichRaces but it doesn't seem to matter at all.
I am using TreeNodeImpl class directly and pass in as a data object a class that represents my own tree data.
I'm wrapping a javax.swing.TreeModel implementation with the RichFaces tree implementation. My ITreeNode interface seen below actually extends javax.swing.tree.TreeNode interface.
public interface IWebTreeData { public String getText(); public String getType(); }
public class WebTreeData implements IWebTreeData, Serializable { /** * */ private static final long serialVersionUID = 1L; String text; String type; public WebTreeData(String text, String type) { this.text = text; this.type = type; } /* * (non-Javadoc) * @see com.clooster.web.model.tree.IWebTreeData#getText() */ public String getText() { return this.text; } /* * (non-Javadoc) * @see com.clooster.web.model.tree.IWebTreeData#getType() */ public String getType() { return this.type; } }
I honestly believe my tree is built correctly on the backing side due to some debug code that I've written as follows:
private void dumpRichTreeModel() { TreeNodeImpl root = this.getRootNode(); StringBuffer outputBuffer = new StringBuffer(((IWebTreeData) root.getData()).getText()); dumpRichChildren(root, 0, outputBuffer); log.info(outputBuffer.toString()); } private void dumpRichChildren(TreeNodeImpl parent, int tabCount, StringBuffer outputBuffer) { outputBuffer.append('\n'); Iterator iter = parent.getChildren(); tabCount++; StringBuffer buf = new StringBuffer(); for (int i = 0; i < tabCount; i++) { buf.append('\t'); } String tabs = buf.toString(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); //ITreeNode identifier = (ITreeNode) entry.getKey(); TreeNodeImpl child = (TreeNodeImpl) entry.getValue(); outputBuffer.append(tabs); outputBuffer.append(((IWebTreeData)child.getData()).getText()); dumpRichChildren(child, tabCount, outputBuffer); } }
After running this code when the tree if finalized, I get the exact tree dumped to the log as I would expect. I get my root, with all children and their children etc dumped to the log using tabs to identify the parent/sibling/child relationships.
Here is my snippet of code that renders the tree:
<rich:panel styleClass="searchTreeSidebar"> <f:facet name="header">#{messages['documents.mysearches']}</f:facet> <rich:tree switchType="ajax" style="width:30%;float:left" value="#{webDocumentTreeModel.rootNode}" var="item" nodeFace="#{item.type}" changeExpandListener="#{webDocumentTreeModel.onExpand}" nodeSelectListener="#{webDocumentTreeModel.onSelect}" binding="#{webDocumentTreeModel.tree}"> <rich:treeNode type="documentMgr"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="document"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="cluster"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="web"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="news"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="image"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="video"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="shopping"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="desktop"> <h:outputText value="#{item.text}" /> </rich:treeNode> <rich:treeNode type="advert"> <h:outputText value="#{item.text}" /> </rich:treeNode> </rich:tree> </rich:panel>
The root tree node doesn't show up but its first children do. However, when I click on the arrow to expand a non leaf node nothing happens.
Here is my backing bean impl. I don't expect you to study the whole thing but much of it is grabbed from demo code.
/** * */ package com.clooster.web.ejb.session; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.ejb.Remove; import javax.ejb.Stateful; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.event.FacesEvent; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Destroy; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.contexts.Contexts; import org.richfaces.component.TreeNode; import org.richfaces.component.TreeNodeImpl; import org.richfaces.component.UITree; import org.richfaces.component.UITreeNode; import org.richfaces.component.events.NodeExpandedEvent; import org.richfaces.component.events.NodeSelectedEvent; //import org.richfaces.component.html.HtmlTree; import com.clooster.web.context.ISessionController; import com.clooster.web.context.SessionController; import com.clooster.web.model.WebDocument; import com.clooster.web.model.WebDocumentManager; import com.clooster.web.model.tree.IWebTreeData; import com.clooster.web.model.tree.WebDocumentManagerTreeModel; import com.clooster.web.model.tree.WebNavigationTreeController; import com.clooster.web.model.tree.WebRichFacesTreeNode; import com.clooster.web.model.tree.WebTreeData; import com.clooster.xjava.app.document.IDocument; import com.clooster.xjava.app.document.IDocumentTreeNode; import com.clooster.xjava.app.document.event.DocumentEvent; import com.clooster.xjava.app.document.event.DocumentListenerAdaptor; import com.clooster.xjava.common.model.tree.ITreeController; import com.clooster.xjava.common.model.tree.ITreeNode; import com.clooster.xjava.util.IXList; import com.clooster.xtss.app.document.IXTSSGraphManagerDocument; import com.clooster.xtss.model.IXTSSGraph; import com.clooster.xtss.model.IXTSSGraphManager; import com.clooster.xtss.model.tree.DocumentManagerTreeModel; import com.clooster.xtss.model.tree.DocumentManagerTreeNode; /** * @author pmadden * */ @Stateful @Name("webDocumentTreeModel") @Scope(ScopeType.SESSION) public class WebDocumentTreeModelBean implements WebDocumentTreeModel { static Log log = LogFactory.getLog(WebDocumentTreeModelBean.class); protected TreeNodeImpl selectedNode; protected UITree tree; protected transient DocumentListenerAdaptor documentListenerAdaptor; protected transient Map<IWebTreeData, TreeNodeTuple> identifierToTreeNodeMap = new HashMap<IWebTreeData, TreeNodeTuple>(); public WebDocumentTreeModelBean() { } /** * This method is called after this component has been successfully * instantiated by the Seam framework */ @Create public void create() { log.info("WebDocumentTreeModelBean create method called"); if (Contexts.isSessionContextActive()) { // bootstrap the document tree model so it listens to events. getDocumentManagerTreeModel(); // create our own document manager listener as well createDocumentListener(); } else { log.info("SessionContext is still not active after component creation event"); } } @Destroy @Remove public void destroy() { WebDocumentManager docMgr = this.getDocumentManager(getSessionController()); if (docMgr != null) docMgr.removeDocumentListener(this.documentListenerAdaptor); } public DocumentManagerTreeModel getDocumentManagerTreeModel() { DocumentManagerTreeModel documentManagerTreeModel; if (Contexts.isSessionContextActive()) { documentManagerTreeModel = (DocumentManagerTreeModel) Contexts.getSessionContext(). get("DocumentManagerTreeModel"); if (documentManagerTreeModel == null) { documentManagerTreeModel = new WebDocumentManagerTreeModel(this.getSessionController()); Contexts.getSessionContext().set("DocumentManagerTreeModel", documentManagerTreeModel); } } else { log.info("Session Context is not active"); documentManagerTreeModel = null; } return documentManagerTreeModel; } public TreeNodeImpl getRootNode() { DocumentManagerTreeNode docRoot = getDocumentManagerTreeModel().getRootNode(); TreeNodeTuple tuple = getTreeNodeTuple(docRoot.getUserObject()); if (tuple == null) { this.createRichFacesNode(docRoot); tuple = getTreeNodeTuple(docRoot.getUserObject()); } TreeNodeImpl richFacesNode = tuple.richNode; log.info("In getRootNode returning rich faces node " + richFacesNode); return richFacesNode; } public TreeNodeImpl getSelectedNode() { return this.selectedNode; } public UIComponent getTree() { /* if (this.tree == null) { this.tree = new HtmlTree(); } */ return this.tree; } public void onExpand(NodeExpandedEvent event) { UITree tree = getUITree(event); log.info("Node " + (tree.isExpanded() ? "expanded" : "collapsed") + " " + tree.getRowKey()); } public void onSelect(NodeSelectedEvent event) { log.info("Node selected: " + getUITree(event).getRowKey()); TreeNode treeNode = getUITree(event).getTreeNode(); if (treeNode != null) { selectedNode = (TreeNodeImpl) treeNode; //initData(); } } public void setSelectedNode(TreeNodeImpl treeNode) { this.selectedNode = treeNode; } private UITree getUITree(FacesEvent event) { UIComponent component = event.getComponent(); if (component instanceof UITree) { return ((UITree) component); } if (component instanceof UITreeNode) { return ((UITree) component.getParent()); } return null; } public void setTree(UIComponent component) { this.tree = (UITree) component; } public String collapseAll() throws IOException { if (this.tree != null) this.tree.queueCollapseAll(); return null; } public String expandAll() { try { if (this.tree != null) this.tree.queueExpandAll(); } catch (IOException e) { e.printStackTrace(); } return null; } protected HttpServletRequest getHttpServletRequest() { Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest(); if (request instanceof HttpServletRequest) { return ((HttpServletRequest) request); } else { return null; } } public ISessionController getSessionController() { ISessionController controller; if (Contexts.isSessionContextActive()) { controller = (ISessionController) Contexts.getSessionContext().get("ISessionController"); if (controller == null) { HttpServletRequest request = this.getHttpServletRequest(); if (request != null) { controller = SessionController.getInstance(request.getSession().getId()); Contexts.getSessionContext().set("ISessionController", controller); } else { log.warn("getSessionController - HttpServletRequest is null"); } } } else { log.warn("getSessionController - session context is not active"); controller = null; } return controller; } public void setRichFacesUserObject(ITreeNode treeNode) { Object userObject = treeNode.getUserObject(); if (userObject == null) createRichFacesNode(treeNode); } protected TreeNodeImpl createRichFacesNode(ITreeNode treeNode) { WebTreeData identifier = new WebTreeData(WebRichFacesTreeNode.calculateText(treeNode), WebRichFacesTreeNode.calculateType(treeNode)); treeNode.setUserObject(identifier); TreeNodeImpl facesNode = new TreeNodeImpl(); facesNode.setData(identifier); this.identifierToTreeNodeMap.put(identifier, new TreeNodeTuple(treeNode, facesNode)); return facesNode; } /** * * @return WebDocumentManager */ public WebDocumentManager getDocumentManager( ISessionController sessionController) { return (WebDocumentManager) sessionController .getDocumentManager(); } public WebNavigationTreeController getTreeController( IDocument document) { WebDocumentManager docMgr = getDocumentManager(getSessionController()); ITreeController treeController = docMgr != null ? docMgr .getTreeController(document) : null; return (WebNavigationTreeController) treeController; } /** * Called when a search finishes up and its time to rebuild the tree * from the document node down. * * @param sessionController * @param document */ public void buildTree(ISessionController sessionController, WebDocument document) { WebNavigationTreeController treeController = this .getTreeController(document); // this is a HACK for now to see if it works - pvm ensureControllers(document); IDocumentTreeNode docRoot = treeController .getDocumentTreeNode(document); if (docRoot == null) docRoot = treeController.createDocumentTreeNode(document); this.setRichFacesUserObject(docRoot); // this rebuilds clooster internal tree model from this // graphManager down, not the entire tree. treeController.rebuildTree(); // now update the Java Server Faces tree model updateWebUITreeModel(sessionController, document, docRoot); dumpRichTreeModel(); } private void dumpRichTreeModel() { TreeNodeImpl root = this.getRootNode(); StringBuffer outputBuffer = new StringBuffer(((IWebTreeData) root.getData()).getText()); dumpRichChildren(root, 0, outputBuffer); log.info(outputBuffer.toString()); } private void dumpRichChildren(TreeNodeImpl parent, int tabCount, StringBuffer outputBuffer) { outputBuffer.append('\n'); Iterator iter = parent.getChildren(); tabCount++; StringBuffer buf = new StringBuffer(); for (int i = 0; i < tabCount; i++) { buf.append('\t'); } String tabs = buf.toString(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); //ITreeNode identifier = (ITreeNode) entry.getKey(); TreeNodeImpl child = (TreeNodeImpl) entry.getValue(); outputBuffer.append(tabs); outputBuffer.append(((IWebTreeData)child.getData()).getText()); dumpRichChildren(child, tabCount, outputBuffer); } } /** * updateWebUITreeModel * @param sessionController ISessionController * @param document WebDocument * @param docRoot IDocumentTreeNode */ protected void updateWebUITreeModel(ISessionController sessionController, WebDocument document, IDocumentTreeNode docRoot) { this.getRootNode().removeChild(docRoot); docRoot.setUserObject(null); TreeNodeImpl uiDocumentTreeNode = this.createRichFacesNode(docRoot); this.getRootNode().addChild(docRoot.getUserObject(), uiDocumentTreeNode); IXList<ITreeNode> children = docRoot.getChildren(); for (ITreeNode cloosterTreeNode : children) { createChildRichFacesTreeNode(sessionController, document, uiDocumentTreeNode, docRoot, cloosterTreeNode); } } /** * @param sessionController2 * @param document * @param parentUIDocumentTreeNode * @param parent * @param child */ protected void createChildRichFacesTreeNode(ISessionController sessionController, WebDocument document, TreeNodeImpl parentUIDocumentTreeNode, ITreeNode parent, ITreeNode child) { TreeNodeImpl childUITreeNode = this.createRichFacesNode(child); parentUIDocumentTreeNode.addChild(child.getUserObject(), childUITreeNode); // Children here are actually Clooster ITreeNode objects which are Swing TreeNodes IXList<ITreeNode> children = child.getChildren(); // recursive call here for (ITreeNode cloosterTreeNode : children) { createChildRichFacesTreeNode(sessionController, document, childUITreeNode, child, cloosterTreeNode); } } /** * This is a HACK for now to see if it works - pvm * * @param document */ protected void ensureControllers(IXTSSGraphManagerDocument document) { IXTSSGraphManager graphMgr = document.getGraphManager(); if (graphMgr.getController() == null) { log.warn("Graph Manager does not have a controller set - setting it now"); graphMgr.setController(getSessionController()); } List graphs = graphMgr.graphs(); for (Object graph : graphs) { if (graph instanceof IXTSSGraph) { IXTSSGraph xGraph = (IXTSSGraph) graph; if (xGraph.getController() == null) { if (log.isDebugEnabled()) log.warn("IXTSSGraph does not have a controller set - setting it now"); xGraph.setController(getSessionController()); } } else { log.warn("GRAPH IS NOT A IXTSSGRAPH - THIS IS FATAL"); } } // END HACK - pvm } /** * * */ protected void createDocumentListener() { if (Contexts.isSessionContextActive()) { documentListenerAdaptor = new WebDocumentListener(this.getSessionController()); this.getDocumentManager(getSessionController()).addDocumentListener(documentListenerAdaptor); } else { log.warn("Session Context is not active in createDocumentListener"); } } protected class WebDocumentListener extends DocumentListenerAdaptor { public WebDocumentListener(ISessionController controller) { super(controller); } public void documentCreated(DocumentEvent event) { IDocument doc = event.getDocument(); if (doc instanceof WebDocument) buildTree(getSessionController(), (WebDocument) doc); } } public ITreeNode getITreeNode(TreeNodeImpl richNode) { TreeNodeTuple tuple = this.identifierToTreeNodeMap.get(richNode.getData()); return tuple.iTreeNode; } public TreeNodeTuple getTreeNodeTuple(Object id) { TreeNodeTuple tuple = this.identifierToTreeNodeMap.get(id); return tuple; } public class TreeNodeTuple { public TreeNodeTuple(ITreeNode iTreeNode, TreeNodeImpl richNode) { this.iTreeNode = iTreeNode; this.richNode = richNode; } ITreeNode iTreeNode; TreeNodeImpl richNode; } }
When you see things like DocumentManagerTreeModel and DocumentManagerTreeNode those are actually Swing TreeModel and TreeNode instances. We have a shared model where our java applications, applets and web share a lot of code. I'm just wrapping these objects inside of RichFaces TreeNodeImpl classes. Hope that makes sense.
Hope I didn't give too much information but I'm really hoping someone can help me as I'm dead in the water unless the tree works.
Many thanks in advance!!!
PVM