[richfaces-issues] [JBoss JIRA] Created: (RF-4283) Rich:datascroller does not show the correct number of pages when used with ExtendedDataModel

Hristo Mitkov (JIRA) jira-events at lists.jboss.org
Mon Aug 25 04:18:38 EDT 2008


Rich:datascroller does not show the correct number of pages when used with ExtendedDataModel
--------------------------------------------------------------------------------------------

                 Key: RF-4283
                 URL: https://jira.jboss.org/jira/browse/RF-4283
             Project: RichFaces
          Issue Type: Bug
    Affects Versions: 3.0.0
            Reporter: Hristo Mitkov
            Priority: Critical


Rich:datascroller cannnot be set to show the correct number of pages when using an ExtendedDataModel. The reason for this is that ListSequenceDataModel is used for calculating the number of pages instead of ExtendedDataModel.
I have TestDataModel class which extends SerializableDataModel where in wrappedData I return just 10 elements but my getRowCount method returns the number of all records in the database which is 500. The datascroller though shows that there is only one page.
I debug the richfaces code to see how the datascroller is rendered.
This is done mainly in DatascrollerTemplate and DataScrollerRenderer in package org.richfaces.renderkit.html. As expected the datascroller uses the DataModel of the DataTable to calculate the number of pages:
org.richfaces.component.UIDatascroller.getRowCount(UIData data)
and after:
UIDataAdapter.getRowCount(){
... return getExtendedDataModel().getRowCount();
}

Here getExtendedDataModel() returns an instance of ModifiableModel which field "originalModel" contains my custom TestDataModel. So modifiableModel.getOriginalModel.getRowCount will return 500 as I need. But look at the implementation of modifiableModel.getRowCount:

public int getRowCount() {
return delegate.getRowCount();
}

!!!???
delegate is an instance of ListSequenceDataModel which contains the list wrappedKeys. So getRowCount() returns wrappedKeys.size() which is 10 so the datascroller renders with only one page.
The correct implementation of modifiableModel.getRowCount should be:

public int getRowCount() {
return originalModel.getRowCount();
}

At the time of rendering the dataTable when the model is created () both fields: modifiableModel.originalModel and modifiableModel.delegate are set to TestDataModel. But at some point delegate is set to ListSequenceDataModel and returns the size of the list.
Another thing is that there is no way to set the number of pages directly to the UIDatascroller component either by an attribute or by the API 

Here is an example code:

This is the datamodel class:

@Name("testDataModel")
@Scope(ScopeType.SESSION)
public class TestDataModel extends SerializableDataModel {

	private Integer currentPk;

	private boolean detached = false;
	private boolean descending;
	private List<Integer> wrappedKeys = null;
	private final Map<Integer, Container> wrappedData = new HashMap<Integer, Container>();
	private int rowCount=0;

	@Override
	public Object getRowKey() {
		return currentPk;
	}
	@Override
	public void setRowKey(Object key) {
		this.currentPk = (Integer) key;
	}
	@In(create = true)
	private ContainerService containerManager;

	@Override
	public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
		if (detached){
			for (Integer key : wrappedKeys) {
				setRowKey(key);
				visitor.process(context, key, argument);
			}
		} else {
			int firstRow = ((SequenceRange) range).getFirstRow();
			int numberOfRows = 10;// ((SequenceRange) range).getRows();
			wrappedKeys = new ArrayList<Integer>();

			for (Container container : containerManager.findContainersPaged(firstRow, numberOfRows, null, null)) {
				wrappedKeys.add(container.getId());
				wrappedData.put(container.getId(), container);
				visitor.process(context, container.getId(), argument);
			}
		}
	}
	@Override
	public SerializableDataModel getSerializableModel(Range range) {
		if (wrappedKeys != null) {
			detached = true;
			return this;
		}
		return null;
	}

	@Override
	public void update() {
		detached = false;
	}
	
	@Override
	public int getRowCount() {
			if(rowCount==0){
				rowCount=containerManager.countContainers();
			}
             // Here for test and debug purposes you can comment the code above and just do: 
             // return 500;

		return rowCount;
	}

	@Override
	public Object getRowData() {
		
		if (currentPk == null) {
			return null;
		} else {
			Container container = wrappedData.get(currentPk);
			if (container == null) {
				container = containerManager.getContainerById(currentPk);
				wrappedData.put(currentPk, container);
			}
			return container;
		}
	}
	@Override
	public boolean isRowAvailable() {
		if (currentPk == null) {
			return false;
		}
		if (wrappedKeys.contains(currentPk)) {
			return true;
		}
		if (wrappedData.entrySet().contains(currentPk)) {
			return true;
		}
		if (containerManager.getContainerById(currentPk) != null) {
			return true;
		}
		return false;
	}
	@Override
	public void setRowIndex(int index) {
	}

	@Override
	public int getRowIndex() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Object getWrappedData() {
		throw new UnsupportedOperationException();
	}

	@Override
	public void setWrappedData(java.lang.Object data) {
		throw new UnsupportedOperationException();
	}

}

Thisis the seam managed bean. It can be any kind of jsf managed bean:

@Stateful
@Name("containerManager")
public class ContainerManager  implements ContainerService {

        public Integer countContainers() {
              //For test and debug purposes you can comment the following code and just: return 500;
		Session session = (Session) entityManager.getDelegate();
		Criteria criteria = session.createCriteria(Container.class).setProjection(Projections.rowCount());
	        Integer containerCount = (Integer) criteria.uniqueResult();
		return containerCount;
	  }

	public List<Container> findContainersPaged(int firstRow, int numberOfRows, String sortField, boolean descending) {
		List<Container> container = entityManager.createQuery("select c from Container c ").setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
		return container;
	}
	public Container getContainerById(Integer id) {
		return entityManager.find(Container.class, id);
	}
 }

This is the page

<rich:dataTable id="containerList" rows="10"  var="c" value="#{testDataModel}">

					<rich:column>
						<f:facet name="header">
							<h:outputText value="Name" />
						</f:facet>
						<h:outputText value="#{c.name}"  />
					</rich:column>
</rich:dataTable>
<rich:datascroller align="left" for="containerList" maxPages="10" rendered="true" />

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the richfaces-issues mailing list