nodeFace and node selection problem
blabno May 30, 2008 5:51 AMHello ! I have strange problem. I have a tree and I want to have this behaviour :
-when I click first time on a node the processSelection method should be called and node should be selected.
-when I click again on this node then again processSelection should be fired and node should be deselected.
Depending on my getNodeFace method implementation this works or not.
@Stateful @Name("categoryManager") public class CategoryManagerBean implements CategoryManagerLocal { private int childrenIdSequence = 1; @In private EntityManager em; @Logger private Log log; @DataModel private List<OfferCategory> rootCategories; @DataModel private List<Class> categoryClasses; @DataModelSelection("categoryClasses") private Class categoryClass; @Out(required = false) private UITree systemTree; @Out(required = false) private UITree externalTree; private TreeNode systemRootNode; private TreeNode externalRootNode; private TreeNode selectedSystemNode; private TreeNode selectedExternalNode; private TreeNode selectedRootNode; @In private FacesMessages facesMessages; @In(required = false) @Out(required = false) private String categoryName; private UITree selectedTree; @Out(required = false) private OfferCategory selectedCategory; private Map<OfferCategory, TreeNode> categoriesNodes = new HashMap<OfferCategory, TreeNode>(); @Factory(value = "rootCategories") public void loadRootCategories() { rootCategories = em.createNamedQuery(OfferCategory.GET_ROOT_CATEGORIES_QUERY).getResultList(); } @Factory(value = "categoryClasses") public void loadCategoryClasses() { categoryClasses = new ArrayList<Class>(); categoryClasses.add(AllegroOfferCategory.class); categoryClasses.add(SystemOfferCategory.class); log.debug("categoryClasses.size() : #0", categoryClasses.size()); } @Begin(pageflow = "addRootCategory", flushMode = FlushModeType.MANUAL) public void addRootCategory() { } public void prepareTrees() { if (categoryClass == null) { return; } if (!categoryClass.equals(SystemOfferCategory.class)) { externalTree = getTree(categoryClass); } systemTree = getTree(SystemOfferCategory.class); } @Remove public void remove() { } private MyTreeNodeImpl asTreeNode(OfferCategory category) { MyTreeNodeImpl node = new MyTreeNodeImpl(childrenIdSequence++); node.setData(category); categoriesNodes.put(category, node); log.debug("added TreeNode with id #0 containing category #1, hashCode=#2", node.getId(), category, category.hashCode()); for (OfferCategory subCategory : category.getSubcategories()) { node.addChild(asTreeNode(subCategory)); } return node; } private TreeNode getSelectedNode() { if (selectedRootNode == null) { return null; } return systemRootNode.equals(selectedRootNode) ? selectedSystemNode : selectedExternalNode; } private UITree getTree(Class<? extends OfferCategory> aClass) { for (OfferCategory category : rootCategories) { if (category.getClass().equals(aClass)) { UITree tree = new HtmlTree(); TreeNode node = asTreeNode(category); if (category.getClass().equals(SystemOfferCategory.class)) { systemRootNode = node; } else { externalRootNode = node; } tree.setValue(node); return tree; } } return null; } public void processSelection(NodeSelectedEvent e) { log.debug("processSelection"); selectedTree = (UITree) e.getComponent(); selectedCategory = null; try { if (selectedTree.getRowKey() == null) { selectedCategory = null; categoryName = ""; } else { selectedCategory = (OfferCategory) selectedTree.getRowData(); categoryName = selectedCategory.getName(); } } catch (IllegalStateException ex) { log.debug(ex, ex); return; } // if (selectedCategory.getRoot().equals(systemRootNode.getData())) { if (selectedTree.equals(systemTree)) { selectedSystemNode = selectedCategory != null ? selectedTree.getTreeNode() : null; selectedTree = systemTree; selectedRootNode = systemRootNode; } else { selectedExternalNode = selectedCategory != null ? selectedTree.getTreeNode() : null; selectedTree = externalTree; selectedRootNode = externalRootNode; } log.debug("processSelection done"); } public void addCategory() { if (selectedRootNode == null) { facesMessages.addFromResourceBundle("selectTreeFirst"); return; } TreeNode selectedNode = systemRootNode.equals(selectedRootNode) ? selectedSystemNode : selectedExternalNode; if (selectedNode == null) { selectedNode = selectedRootNode; } selectedCategory = (OfferCategory) selectedNode.getData(); OfferCategory newCategory = null; try { newCategory = selectedCategory.getClass().newInstance(); } catch (Exception e) { log.error(e); } newCategory.setName(categoryName); newCategory.setParent(selectedCategory); MyTreeNodeImpl newNode = new MyTreeNodeImpl(childrenIdSequence++); newNode.setData(newCategory); selectedNode.addChild(newNode.getId(), newNode); expandNode(selectedTree, selectedNode); categoriesNodes.put(newCategory, newNode); log.debug("added TreeNode with id #0 containing category #1, hashCode=#2", newNode.getId(), newCategory, newCategory.hashCode()); } public void saveCategory() { if (selectedCategory == null) { facesMessages.addFromResourceBundle("selectCategoryFirst"); return; } if (categoryName == null || categoryName.trim().equals("")) { facesMessages.addFromResourceBundle("enterCategoryNameFirst"); return; } TreeNode selectedNode = categoriesNodes.remove(selectedCategory); selectedCategory.setName(categoryName); categoriesNodes.put(selectedCategory, selectedNode); } public void removeCategory() { if (selectedCategory == null) { facesMessages.addFromResourceBundle("selectCategoryFirst"); return; } MyTreeNodeImpl selectedNode = (MyTreeNodeImpl) categoriesNodes.remove(selectedCategory); if (selectedNode != null) { selectedNode.getParent().removeChild(selectedNode.getId()); } /** * category cannot be modified before node is retrived from map, since modifications change hashCode */ selectedCategory.setParent(null); selectedCategory = null; if (selectedNode.equals(selectedSystemNode)) { selectedSystemNode = null; } else { selectedExternalNode = null; } } public void mapCategory() { if (selectedSystemNode == null || selectedExternalNode == null) { facesMessages.addFromResourceBundle("selectTowNodesFirst"); return; } SystemOfferCategory systemCategory = (SystemOfferCategory) selectedSystemNode.getData(); ExternalOfferCategory externalCategory = (ExternalOfferCategory) selectedExternalNode.getData(); externalCategory.getMapping().add(systemCategory); } public String getNodeFace(OfferCategory category) { // if (category instanceof ExternalOfferCategory) { // ExternalOfferCategory externalCategory = (ExternalOfferCategory) category; // return externalCategory.getMapping().isEmpty() ? "notMapped" : "mapped"; // } else { // return ""; // } if (category instanceof SystemOfferCategory) { if (selectedExternalNode == null) { return ""; } else { return ((ExternalOfferCategory) selectedExternalNode.getData()).getMapping().contains(category) ? "mapped" : ""; } } if (category == null || getSelectedNode() == null) { return "normal"; } ExternalOfferCategory externalCategory = (ExternalOfferCategory) category; return externalCategory.getMapping().isEmpty() ? "notMapped" : "mapped"; } private void expandNode(UITree tree, TreeNode node) { List<Object> path = new ArrayList<Object>(); while (node != null) { path.add(((MyTreeNodeImpl) node).getId()); node = node.getParent(); } Collections.reverse(path); path.remove(0); // dont expand rootnode, it is not displayed TreeState state = (TreeState) tree.getComponentState(); for (int i = 0; i < path.size(); i++) { List<Object> list = new ArrayList<Object>(); for (int n = 0; n <= i; n++) { list.add(path.get(n)); } ListRowKey key = new ListRowKey(list); try { state.expandNode(tree, key); } catch (Exception e) { log.error(e.getMessage(), e); } } ListRowKey key = new ListRowKey(path); state.setSelected(key); } public Boolean adviseNodeSelected(UITree tree) { return tree.getTreeNode().equals(getSelectedNode()); } public static class MyTreeNodeImpl extends TreeNodeImpl { private Object id; public Object getId() { return id; } public void setId(Object id) { this.id = id; } public MyTreeNodeImpl() { } public MyTreeNodeImpl(Object id) { setId(id); } public void addChild(MyTreeNodeImpl node) { addChild(node.getId(), node); } } }
<h:form id="editOfferCategory"> <a4j:outputPanel id="trees"> <a4j:outputPanel ajaxRendered="true"> <h:messages/> </a4j:outputPanel> <a4j:status startText="Request in progress..." stopText="Request finished"/> <table> <tr> <td> #{systemTree.value.data.name} <rich:tree id="systemTree" nodeSelectListener="#{categoryManager.processSelection}" ajaxSubmitSelection="true" switchType="ajax" binding="#{systemTree}" var="item" reRender="lalala" adviseNodeSelected="#{categoryManager.adviseNodeSelected}" > <rich:treeNode>#{item.name}</rich:treeNode> </rich:tree> </td> <td class="buttons"> <a4j:commandButton value="#{messages.map}" action="#{categoryManager.mapCategory}" reRender="trees"/> <br /> <h:outputLink value="#" onmouseup="showButton('addButton')"> #{messages.add} <rich:componentControl for="categoryProperties" operation="show" event="onclick"/> </h:outputLink> <br /> <h:commandLink action="#{categoryManager.removeCategory()}">#{messages.remove}</h:commandLink> </td> <td> #{externalTree.value.data.name} <rich:tree id="externalTree" nodeSelectListener="#{categoryManager.processSelection}" ajaxSubmitSelection="true" switchType="ajax" binding="#{externalTree}" var="item" nodeFace="#{categoryManager.getNodeFace(item)}" reRender="lalala" adviseNodeSelected="#{categoryManager.adviseNodeSelected}" > <rich:treeNode type="normal" onmouseup="showButton('saveButton')"> normal #{item.name} <rich:componentControl for="categoryProperties" operation="show" event="ondblclick"/> </rich:treeNode> <rich:treeNode type="notMapped" nodeClass="notMapped" onmouseup="showButton('saveButton')"> notMapped #{item.name} <rich:componentControl for="categoryProperties" operation="show" event="ondblclick"/> </rich:treeNode> <rich:treeNode type="mapped" nodeClass="mapped" onmouseup="showButton('saveButton')"> mapped #{item.name} <rich:componentControl for="categoryProperties" operation="show" event="ondblclick"/> </rich:treeNode> </rich:tree> </td> </tr> </table> </a4j:outputPanel> <a4j:outputPanel ajaxRendered="true"> <h:outputText value="Selected category : #{categoryName}" id="lalala"/> </a4j:outputPanel> </h:form>
Now depending on my getNodeFace second click fires processSelection or not.
Following works, but nodeFace does not get changed properly (it stays the same) :
public String getNodeFace(OfferCategory category) { if (category == null || getSelectedNode() == null) { return "normal"; } if (category instanceof ExternalOfferCategory) { ExternalOfferCategory externalCategory = (ExternalOfferCategory) category; return externalCategory.getMapping().isEmpty() ? "notMapped" : "mapped"; } }
This does not work since second click does not trigger processSelection.
public String getNodeFace(OfferCategory category) { if (category instanceof ExternalOfferCategory) { ExternalOfferCategory externalCategory = (ExternalOfferCategory) category; return externalCategory.getMapping().isEmpty() ? "notMapped" : "mapped"; } else { return ""; } }
Which brings me to a conclusion that if the nodeFace is not changed then processSelection is not fired, is it right ?
The working implementation is wrong from my business point of view and I would like to use the second one. What shall I do or where is my mistake ?