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

dhalupa
Champ on-the-rise
Champ on-the-rise
Rendering is taken care of in the abstract super class AbstractItemSelector

Kind regards,

Denis

friedman30
Champ in-the-making
Champ in-the-making
thanks Denis!

but yet, i still don't know where to perform the changes in to this component…  :roll: 

I don't understand why the logic for adding a category is so complex…
I could not even find where this component gets the "categories" model from. (query? session?)

can anyone try to explain this logic?

I just try to simplify the UI - so that adding a category to a space won't require so many steps…
:idea:

thanks,

Dror

dhalupa
Champ on-the-rise
Champ on-the-rise
Try to do some reading on JSF and custom component development, there are plenty of books and tutorials around. Once you get to understand underlying technology, you will find that Alfresco components are not that complicated after all

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

I do know JSF custom component development, and still i think that Alfresco's logic for adding categories is too complex and the component that's hadling it is a major part of this problem.

anyways, i've found a way arround this

Thanks again!   :wink: 

Dror

dhalupa
Champ on-the-rise
Champ on-the-rise
Great, I'm glad you made it

gcoleman
Champ in-the-making
Champ in-the-making
Hi Dror,
          I wonder if you would mind sharing your solution?

Cheers

Greg.

friedman30
Champ in-the-making
Champ in-the-making
The solution was not to use the component that Alfresco is using for adding categories…

I've modified the jsp and added my own backing beans and logic to create a much simpler way for adding categories.

Greg - if you want me to be more specific, please write  :wink:

best regards,

Dror

gcoleman
Champ in-the-making
Champ in-the-making
Hi Dror,
         Just to clarify, are you talking about the page where you associate a category with a document? If you are then this is exactly what I want to change. It is a little tedious and I am sure my users will not like it.

         If it is not too much bother, I would appreciate it if you shared your source code with me.

         Let me know if I can return the favour. I have been working on a modification to the simple search. It finds relevant documents if you type the name of a category.

Regards

Greg.

friedman30
Champ in-the-making
Champ in-the-making
Hi Greg.

I've added this code to edit-space-category.jsp (replaced Alfresco's <r:multiValueSelector> component):

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

this is the backing bean: (don't forget to add setter and getter methods)

public class AddCategoryBean extends BaseDetailsBean 
{

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

      categories = (List<NodeRef>)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("savedCategories");
      if(categories == null)
         categories = new ArrayList<NodeRef>();
      parentCategories = new Stack<NodeRef>();
      categoryItems = new ArrayList<AddCategoryItem>();
      getRootChildren(context);
   }
   
   /**
    * get top level categories
    */
   private void getRootChildren(FacesContext context)
   {
      childRefs = getCategoryService().getCategories(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, 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;
      for(ChildAssociationRef ref: childRefs)
      {
         categoryItem = new AddCategoryItem();
         categoryItem.setChildRef(ref);
         if(categories.contains(ref.getChildRef()))
         {
            categoryItem.setSelected(true);
         }
         
         categoryItems.add(categoryItem);
      }   
   }
      
   /**
   * 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()
   {
      String outcome = "cancel";    
      UserTransaction tx = null;
     
      addCheckedRows();
      try
      {
         tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
         tx.begin();
         NodeService nodeService =  Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getNodeService();
         // firstly retrieve all the properties for the current node
         Map<QName, Serializable> updateProps = nodeService.getProperties(
               getSpace().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(getSpace().getNodeRef(), updateProps);
        
         // commit the transaction
         tx.commit();
        
         // reset the state of the current document so it reflects the changes just made
         getSpace().reset();
        
         outcome = "finish";
      }
      catch (Throwable e)
      {
         try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE_CATEGORY), e.getMessage()), e);
      }
     
      return outcome;
   }  
}

the one last thing you need is a model class that holds the model for one row in the table:

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 "";
   }
}

you will need to register the backing bean in faces-config-beans.xml, and add some lines to the properties file that stores the msg (messages) for all Alfresco's jsp files

😎
enjoy.

Dror