0 Replies Latest reply on May 30, 2008 5:51 AM by Bernard Labno

    nodeFace and node selection problem

    Bernard Labno Master

      Hello ! 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 ?