Wednesday, January 11, 2012

Build your Own Standard set controller

Standard set controller can be used for many objects . Recently i found that it cannot be used with activity objects(Open activity and activity history). Also there are many other Restrictions placed on these objects. You cannot query on these objects directly. It has to be a nested SOQL within an object using a relationship name.

So coming back to my requirement i needed to roll up related list for all the activities in the account hierarchy for the topmost parent. For other related list i achieved it through standardset controller. But for activity alone i created a class which would behave like a standard set controller.

public class SetActivityClass {
        public integer pagenumber{get;set;}
        public integer totalpages{get;set;}
        public integer pagesize{get;set;}
        public list<sobject> sobjectList{get;set;}       
 public SetActivityClass(list<sobject> sobjectList){
        pagenumber =1;
        pagesize = 60;
        this.sobjectList=sobjectList;
        totalpages= Integer.valueof(math.ceil((double)sobjectList.size()/(double)pagesize ));
        }
        public boolean gethasprevious(){
          return (pagenumber != 1);
        }
        public boolean gethasnext(){
            return (pagenumber != totalpages);
        }
        public pagereference Previous(){
        if(gethasprevious())
            pagenumber--;
            return null;
        }
        public pagereference next(){
        if(gethasnext())
            pagenumber++;
            return null;
        }
        public list<sobject> getRecords(){
        list<sobject> Sactivity = new list<sobject>();       
            for(integer counter2=(pagenumber-1)*pagesize;counter2<(math.min(pagenumber*pagesize,sobjectList.size()));counter2++){
                Sactivity.add(sobjectList.get(counter2));
            }
            return Sactivity;
        }
          
    } 

oActivityHistory= new SetActivityClass(ActivityHistoryList);
        oOpenActivity= new SetActivityClass(OpenActivityList); 


public List<OpenActivity> getGoToListOpenActivities() {
    return oOpenActivity.getRecords();       
    }

public List<ActivityHistory> getGoToListActivityHistories() {
    return oActivityHistory.getRecords();       
    }

Just like the standard set controller, this SetActivityClass has methods to return next set or previous set of records. These can be added to command links as they are pagereference method. Also Hasprevious and Hasnext can be called from the page to check if the previous or next set of records exist.Pagenumber denotes the current page number. Pagesize determines no of records to be displayed in the page. I would recommend a size of 40 -60 in a page for better readability by Users(I have hardcoded it as 60). Total pages is calculated based on this pagesize.

Also note that getRecord function accepts and returns generic sobject. I used the same class for both activityhistory and openactivity.This Class can be slightly tweaked to handle list of objects of your custom class  as well.

Here is how i would display it in the page

<apex:panelGrid columns="2">                 
 <apex:commandLink action="{!oOpenActivity.previous}" rendered={!oOpenActivity.hasPrevious}"> Previous </apex:commandLink>
  <apex:commandLink action="{!oOpenActivity.next}" rendered="{!oOpenActivity.hasNext}" >Next </apex:commandLink>           
  </apex:panelGrid>

<apex:pageBlockTable id="tableMasterAccountOpenActivities" var="openact"  value="{!GoToListOpenActivities}">
 <apex:column .....
.......
</apex:pageblocktable>

And whenever the next and previous is click make sure atleast the pageblock tabele is rerendered if not the whole page based on your logic. I  have shown the VF for openactivity. similarly u can use it for activity history. Also you can use the same logic in building your own custom class wrapper object standard set controller this way.