cancel
Showing results for 
Search instead for 
Did you mean: 

changing the 'select a category' component

friedman30
Champ in-the-making
Champ in-the-making
Hi,

I need to do some changes in the look and feel (and logic) of the "Edit Categories" page.
The believe that the whole logic that i need to change is within the <r:categorySelector> component. (CategorySelectorTag ; CategorySelectorGenerator)
(am i right :shock: )

Still, i can't find where exactly this component is rendered.
for example: how does it change the look when it has a category and when it has not.

?  :?:  ?  :?:  ?  :?: 

thanks,

Dror
19 REPLIES 19

gcoleman
Champ in-the-making
Champ in-the-making
Thanks Dror,
          That  works a treat.

ribz33
Champ on-the-rise
Champ on-the-rise
Hi,

this is very interesting, im thinking also that original component is too hard to use !

is it possible to have some captures to give us idea of your change on this component ? Or maybe have you contribute it in forge or wiki ?

Thx in advance.

friedman30
Champ in-the-making
Champ in-the-making
Hi 'ribz33'

Just show me the way to add a screenshot and i will add it immediately.

:wink:

Dror

stevewickii
Champ in-the-making
Champ in-the-making
I can't get this to work in Alfresco 2.9.0B.

getStore() is not a valid method, and there are some missing required methods:

    protected Node getLinkResolvedNode()
    public Node getNode()
    protected String getPropertiesPanelId()
    public Map getTemplateModel()
Has anyone made this to work in Alfresco 2.9.0B?

stevewickii
Champ in-the-making
Champ in-the-making
I have implemented a solution for Alfresco 2.9.0B build 683 as well.  It is posted here: http://forums.alfresco.com/viewtopic.php?f=3&t=12018&p=40368#p40368

It modifies the out-of-the-box component to support multiple selection, just like the Category Selector on the Advanced Search page.

mesa2e
Champ in-the-making
Champ in-the-making
Dror's solution is exactly what I was investigating, because I also think category component is really complex.

I've tried Dror's solution for my Alfresco, but I get the following error:

javax.faces.FacesException: Could not retrieve value of component with path : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/dialog/document-details.jsp][Class: javax.faces.component.html.HtmlForm,Id: document-details][Class: javax.faces.component.html.HtmlOutputText,Id: _idJsp12]}
caused by:
org.apache.jasper.JasperException: Could not retrieve value of component with path : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/dialog/document-details.jsp][Class: javax.faces.component.html.HtmlForm,Id: document-details][Class: javax.faces.component.html.HtmlOutputText,Id: _idJsp12]}
caused by:
javax.faces.FacesException: Could not retrieve value of component with path : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/dialog/document-details.jsp][Class: javax.faces.component.html.HtmlForm,Id: document-details][Class: javax.faces.component.html.HtmlOutputText,Id: _idJsp12]}
caused by:
javax.faces.el.PropertyNotFoundException: Bean: org.alfresco.web.bean.AddCategoryBean, property: lockService


Please, any ideas about what I am forgetting?

Thanks in advance!!

mesa2e
Champ in-the-making
Champ in-the-making
I've achieved to fix the problem before, and now I can select the categories properly.
The problem is when I click on "OK Button" to save the categories. The application gets me the following error:

Failed to update category due to system errorSmiley Surprisedrg.alfresco.repo.transaction.RetryingTransactionHelper


Any ideas???

Thanks in advance,
Elena.

mesa2e
Champ in-the-making
Champ in-the-making
I finally got the solution and it works successfully!!! I had to make some modifications on Dror's code.
Here you have all my modifications:

Extend the class DocumentDetailsBean:

package org.alfresco.web.bean;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.faces.component.UIData;
import javax.faces.component.UISelectBoolean;
import javax.faces.context.FacesContext;
import javax.transaction.UserTransaction;

import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;


public class AddCategoryBean extends DocumentDetailsBean
{

   private FacesContext context = FacesContext.getCurrentInstance();
   private List categories;
   private Stack parentCategories;
   private ArrayList rootCategories;
   private Collection childRefs;
   private List categoryItems;
   private UIData categoriesTable;
   private static final String MSG_ERROR_UPDATE_CATEGORY = "error_update_category";
  
   //default constructor
   public Logesta_DocumentDetailsBean()
   {
       super();

      categories = (List)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("savedCategories");
      if(categories == null)
         categories = new ArrayList();
      parentCategories = new Stack();
      categoryItems = new ArrayList();
      getRootChildren(context);
   }
  
   /**
    * get top level categories
    */
   private void getRootChildren(FacesContext context)
   {
      childRefs = getCategoryService().getCategories(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, CategoryService.Depth.IMMEDIATE);
      updateTableModel();
   }
  
   /**
    * get categories by nodeRef
    * the nodeRef comes from the selected row
    */
   public String getChildrenForNode()
      {
         ChildAssociationRef assocRef = ((AddCategoryItem)categoriesTable.getRowData()).getChildRef();
         NodeRef nodeRef = new NodeRef(Repository.getStoreRef(), assocRef.getChildRef().getId());
         childRefs = getCategoryService().getChildren(nodeRef,
               CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.IMMEDIATE);
         addCheckedRows();
         updateTableModel();
         ChildAssociationRef parentRef = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getNodeService().getPrimaryParent(nodeRef);
         parentCategories.push(parentRef.getParentRef());
         UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
         return "success";
      }
  
   /**
    * get categories by nodeRef.
    * the nodeRef comes from the stack that holds the parent reference.
    * this method is used to navigate one level up.
    */
   public String getLevelUpChildrenForNode()
      {
         if ( !parentCategories.isEmpty())
         {
            NodeRef parentRef = (NodeRef)this.parentCategories.pop();
            childRefs = getCategoryService().getChildren(parentRef,
                   CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.IMMEDIATE);
            addCheckedRows();
            updateTableModel();
            UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
           
         }        
         return "success";
      }
  
   /**
    * update table model with new values
    */
   public void updateTableModel()
   {
      categoryItems.clear();
      AddCategoryItem categoryItem = null;
    
      Iterator i = childRefs.iterator();
      do
      {
          if(!i.hasNext())
              break;
          ChildAssociationRef ref = (ChildAssociationRef)i.next();
          categoryItem = new AddCategoryItem();
          categoryItem.setChildRef(ref);
          if(categories.contains(ref.getChildRef()))
          {
             categoryItem.setSelected(true);
          }
         
          categoryItems.add(categoryItem);

     } while(true);

   }
     
   /**
   * Use Spring JSF integration to return the category service bean instance
   *
   * @param context    FacesContext
   * @return category service bean instance or throws runtime exception if not found
   */
   private CategoryService getCategoryService()
   {
      CategoryService service = Repository.getServiceRegistry(context).getCategoryService();
      if (service == null)
      {
         throw new IllegalStateException("Unable to obtain CategoryService bean reference.");
      }     
      return service;
   }
  
   /**
    * add selected rows to the "categories" collection
    * the method will remove rows that have been disselected from the "categories" collection!
    */
   private void addCheckedRows()
   {
      for (int i=0; i < categoriesTable.getRowCount(); i++)
      {  
         categoriesTable.setRowIndex(i);
         UISelectBoolean box =  (UISelectBoolean)categoriesTable.findComponent("categoryCheckbox");
         boolean isSelected = box.isSelected();
        
         ChildAssociationRef assocRef = ((AddCategoryItem)categoriesTable.getRowData()).getChildRef();
         NodeRef currentRowRef = assocRef.getChildRef();
         if((categories.contains(currentRowRef)) && !(isSelected))
         {
            categories.remove(currentRowRef);
         }
         if((isSelected) && !(categories.contains(currentRowRef)))
         {
            categories.add(currentRowRef);
         }
      }
   }
  
   /**
    * Updates the categories for the current document
    * 
    * @return The outcome
    */
public String saveCategories()
   {
      addCheckedRows();
        String outcome = "cancel";
       
        UserTransaction  tx = null;
        System.out.println("Dentro de saveCategories");
        try
        {
           FacesContext context = FacesContext.getCurrentInstance();
           tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
           tx.begin();
          
           // firstly retrieve all the properties for the current node
           Map updateProps = nodeService.getProperties(getDocument().getNodeRef());
          
           // create a node ref representation of the selected id and set the new properties
           updateProps.put(ContentModel.PROP_CATEGORIES, (Serializable )this.categories);
          
           // set the properties on the node
           this.nodeService.setProperties(getDocument().getNodeRef(), updateProps);
          
           // commit the transaction
           tx.commit();
          
           // reset the state of the current document so it reflects the changes just made
           getDocument().reset();
         
           outcome = "finish";
        }
        catch(Throwable e)
        {
            Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), "error_update_category"), new Object[] {
                e.getMessage()
            }), e);
        }
        return outcome;
    }



  
   public Node getNode()
   {
       return browseBean.getDocument();
   }
  
  public UIData getCategoriesTable(){
     
     return categoriesTable;
  }
 
  public void setCategoriesTable(UIData categoriesTable){
     
     this.categoriesTable = categoriesTable;
  }
 
  public List getCategoryItems(){
     
     return categoryItems;
  }
 
  public void setCategoryItems(List categoryItems){
     
     this.categoryItems = categoryItems;
  }

/* (non-Javadoc)
* @see org.alfresco.web.bean.BaseDetailsBean#getLinkResolvedNode()
*/
   protected Node getLinkResolvedNode()
   {
       Node document = getDocument();
       if(ApplicationModel.TYPE_FILELINK.equals(document.getType()))
       {
           NodeRef destRef = (NodeRef)document.getProperties().get(ContentModel.PROP_LINK_DESTINATION);
           if(nodeService.exists(destRef))
               document = new Node(destRef);
       }
       return document;
   }
  
   public Node getDocument()
   {
       return getNode();
   }
  


/* (non-Javadoc)
* @see org.alfresco.web.bean.BaseDetailsBean#getTemplateModel()
*/
   public Map getTemplateModel()
   {
       Map model = new HashMap(2, 1.0F);
       model.put("document", getDocument().getNodeRef());
       model.put("space", navigator.getCurrentNode().getNodeRef());
       model.put("imageresolver", imageResolver);
       return model;
   }
  

/* (non-Javadoc)
* @see org.alfresco.web.bean.BaseDetailsBean#getPropertiesPanelId()
*/
   protected String getPropertiesPanelId()
   {
       return "document-props";
   }
  
  

}

Create AddCategoryItem:


package org.alfresco.web.bean;

import org.alfresco.service.cmr.repository.ChildAssociationRef;


public class AddCategoryItem
{
   private ChildAssociationRef childRef;
   private boolean selected = false;
  
   public ChildAssociationRef getChildRef() {
      return childRef;
   }
   public void setChildRef(ChildAssociationRef childRef) {
      this.childRef = childRef;
   }
   public boolean isSelected() {
      return selected;
   }
   public void setSelected(boolean selected) {
      this.selected = selected;
   }
   public String getLocalName()
   {
      if(childRef != null)
      {
         return childRef.getQName().getLocalName();
      }
      return "";
   }
}


Replace multivalueSelector on edit_details.jsp:

<h:commandButton image="/images/icons/up.gif" action="#{DocumentDetailsBean.getLevelUpChildrenForNode}" immediate="true">
</h:commandButton>
<h:dataTable id="categoriesTable" border="0" binding="#{DocumentDetailsBean.categoriesTable}" value="#{DocumentDetailsBean.categoryItems}" var="line">
     <h:column>
        <h:selectBooleanCheckbox value="#{line.selected}" id="categoryCheckbox"  immediate="true"/>
     </h:column>
     <h:column>
      <h:commandLink id="cmd-link" action="#{DocumentDetailsBean.getChildrenForNode}" immediate="true">
         <h:outputText id="output-text" value="#{line.localName}"/>
      </h:commandLink>
    </h:column>  
</h:dataTable>


Add the following code on faces-config-custom.xml:

  <managed-bean>
      <description>
         Backing bean used by the document details dialog
      </description>
      <managed-bean-name>DocumentDetailsBean</managed-bean-name>
      <managed-bean-class>org.alfresco.web.bean.Logesta_DocumentDetailsBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      <managed-property>
         <property-name>browseBean</property-name>
         <value>#{BrowseBean}</value>
      </managed-property>
      <managed-property>
         <property-name>nodeService</property-name>
         <value>#{NodeService}</value>
      </managed-property>
      <managed-property>
         <property-name>lockService</property-name>
         <value>#{LockService}</value>
      </managed-property>
      <managed-property>
         <property-name>versionService</property-name>
         <value>#{VersionService}</value>
      </managed-property>
      <managed-property>
         <property-name>copyService</property-name>
         <value>#{CopyService}</value>
      </managed-property>
      <managed-property>
         <property-name>ownableService</property-name>
         <value>#{OwnableService}</value>
      </managed-property>
      <managed-property>
         <property-name>checkOutCheckInService</property-name>
         <value>#{CheckoutCheckinService}</value>
      </managed-property>
      <managed-property>
         <property-name>navigator</property-name>
         <value>#{NavigationBean}</value>
      </managed-property>
     <managed-property>
         <property-name>multilingualContentService</property-name>
         <value>#{MultilingualContentService}</value>
      </managed-property>
      <managed-property>
         <property-name>contentFilterLanguagesService</property-name>
         <value>#{ContentFilterLanguagesService}</value>
      </managed-property>
      <managed-property>
         <property-name>editionService</property-name>
         <value>#{EditionService}</value>
      </managed-property>
      <managed-property>
         <property-name>permissionService</property-name>
         <value>#{PermissionService}</value>
      </managed-property>
   </managed-bean>

mesa2e
Champ in-the-making
Champ in-the-making
Please help!!!

After doing this customization, I've detected a problem.

If I modify the category's name, the 'select category' panel shows the old name, no the newer.

Any ideas, please?

Thanks in advance,
Elena.

cbosdonnat
Champ in-the-making
Champ in-the-making
Hi Elena,

If I modify the category's name, the 'select category' panel shows the old name, no the newer.

You should change the implementation of the public getCategoriesTable() method to compute the table every time it is called and not make it rely on a private member. This is a bit less performant, but it should work fine. Otherwise, I've tried another approach which is explained here:

http://cedric.bosdonnat.free.fr/wordpress/?p=83&lang_view=en

HTH