package com.gwt.ui.client.masterview;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/**
*
* @author ibouakl
*
*/
public class DataSource {
public static final int DEFAULT_PAGE_SIZE = 10;
protected int pageSize;
protected int currentPageNumber;
private boolean enabledPagination = true;
protected String propertyToSort;
protected String sortType = SortConstants.NO_SORTING;
private int currentPageCount;
public String getPropertyToSort() {
return propertyToSort;
}
public void setPropertyToSort(String propertyToSort) {
this.propertyToSort = propertyToSort;
refreshDisplayData();
}
public String getSortType() {
return sortType;
}
public void setSortType(String sortType) {
this.sortType = sortType;
refreshDisplayData();
}
/**
* <p>
* The list of dataSource listeners.
* </p>
*/
@SuppressWarnings("unchecked")
protected List dataSourceListeners = new ArrayList();
/**
* <p>
* The list of filters.
* </p>
*/
@SuppressWarnings("unchecked")
protected List filters = new ArrayList();
/**
* <p>
* Filtered, paged and sorted data - ready to be displayed.
* </p>
*/
@SuppressWarnings("unchecked")
protected List displayData = new ArrayList();
/**
* <p>
* Original data that is not affected by filters, sorting and pagination.
* </p>
*/
@SuppressWarnings("unchecked")
protected List initialData = new ArrayList();
/**
* <p>
* The mapper that can be used to get values of the bean's fields by names of these fields (it's used instead of reflection that is not
* supported in GWT JRE).
* </p>
* <p/>
* <p>
* It's generated by MasterViewGenerator in compile-time based on the class of the beans that would be keeped in datasource.
* </p>
*/
protected PropertyMapper propertyMapper;
/**
* <p>
* Adds a datasource listener to a list of listeners. Later it will be notifyed then the data will change.
* <p>
*
* @param dataSourceListener a listener to add.
*/
@SuppressWarnings("unchecked")
public void addDataSourceListener(DataSourceListener dataSourceListener) {
if (!dataSourceListeners.contains(dataSourceListener)) {
dataSourceListeners.add(dataSourceListener);
}
}
/**
* <p>
* Removes a datasource listener from the list of listeners.
* </p>
*
* @param dataSourceListener a listener to remove.
*/
public void removeDataSourceListener(DataSourceListener dataSourceListener) {
if (dataSourceListeners.contains(dataSourceListener)) {
dataSourceListeners.remove(dataSourceListener);
}
}
/**
* Gets property mapper. The property mapper is the object that can be used to get values of the bean's fields by names of these fields
* (it's used instead of reflection that is not supported in GWT JRE).
*
* @return
*/
public PropertyMapper getPropertyMapper() {
return propertyMapper;
}
public void setPropertyMapper(PropertyMapper propertyMapper) {
this.propertyMapper = propertyMapper;
}
public DataSource() {
this.currentPageNumber = 0;
this.pageSize = DEFAULT_PAGE_SIZE;
}
public DataSource(boolean enabledPagination) {
this.enabledPagination = enabledPagination;
this.currentPageNumber = 0;
this.pageSize = DEFAULT_PAGE_SIZE;
}
@SuppressWarnings("unchecked")
public DataSource(List data) {
this.currentPageNumber = 0;
this.pageSize = DEFAULT_PAGE_SIZE;
setInitialData(data);
/*setDisplayData(data);*/
}
public void clearData() {
initialData = null;
}
@SuppressWarnings("unchecked")
public void addFilter(Filter filter) {
if (!filters.contains(filter)) {
filters.add(filter);
}
refreshDisplayData();
}
public void removeFilter(Filter filter) {
if (filters.contains(filter)) {
filters.remove(filter);
}
refreshDisplayData();
}
public void clearFilters(Filter filter) {
filters.clear();
refreshDisplayData();
}
public void clearFiltersByProperty(String propertyName) {
for (int i = 0; i < filters.size(); i++) {
if (!(filters.get(i) instanceof Filter)) {
continue;
}
Filter filter = (Filter) filters.get(i);
if (filter.getPropertyName().equals(propertyName)) {
filters.remove(filter);
}
}
refreshDisplayData();
}
@SuppressWarnings("unchecked")
public void setInitialData(List initialData) {
this.initialData = initialData;
refreshDisplayData();
}
@SuppressWarnings("unchecked")
public void setDisplayData(List displayData) {
this.displayData = displayData;
notifyDataSourceListeners(displayData.size(), initialData.size());
}
@SuppressWarnings("unchecked")
public List getDisplayData() {
return displayData;
}
protected void notifyDataSourceListeners(int readItemsCount, int allItemsCount) {
for (int i = 0; i < dataSourceListeners.size(); i++) {
if (dataSourceListeners.get(i) instanceof DataSourceListener) {
DataSourceListener dataSourceListener = (DataSourceListener) dataSourceListeners.get(i);
dataSourceListener.onDataChanged(readItemsCount, allItemsCount);
}
}
}
/**
* Filters the data with a list of assigned filtes.
*/
@SuppressWarnings("unchecked")
protected List filterData(List dataToFilter) {
List filteredData = new ArrayList();
for (int i = 0; i < getInitialData().size(); i++) {
filteredData.add(getInitialData().get(i));
}
for (int i = 0; i < filters.size(); i++) {
Filter filter = (Filter) filters.get(i);
Validator validator = ValidatorBuilder.buildFromFilterExpression(filter.getExpression());
List toBeRemovedObjects = new ArrayList();
for (int j = 0; j < filteredData.size(); j++) {
Object objectToTest = filteredData.get(j);
Object propertyValueToTest = propertyMapper.getProperty(objectToTest, filter.getPropertyName());
if (!validator.isValid(propertyValueToTest)) {
toBeRemovedObjects.add(objectToTest);
}
}
for (int j = 0; j < toBeRemovedObjects.size(); j++) {
filteredData.remove(toBeRemovedObjects.get(j));
}
}
return filteredData;
}
@SuppressWarnings("unchecked")
protected List sortData(List dataToSort) {
if (sortType.equals(SortConstants.NO_SORTING)) {
return dataToSort;
}
final Comparator comparator;
Object propertyValue = propertyMapper.getProperty(initialData.get(0), getPropertyToSort());
if (propertyValue instanceof Date) {
comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Date d1 = (Date) o1;
Date d2 = (Date) o2;
return d1.before(d2) ? -1 : 1;
}
};
} else if ((propertyValue instanceof Integer) || (propertyValue instanceof Long) || (propertyValue instanceof Byte) || (propertyValue instanceof Double) || (propertyValue instanceof Float)) {
comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Double) {
return ((Double) o1).compareTo(((Double) o2));
} else if (o1 instanceof Long) {
return ((Long) o1).compareTo(((Long) o2));
} else if (o1 instanceof Integer) {
return ((Integer) o1).compareTo(((Integer) o2));
} else {
return -1;
}
}
};
} else {
comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
}
};
}
Collections.sort(dataToSort, new Comparator() {
public int compare(Object firstBean, Object secondBbean) {
Object firstObject = propertyMapper.getProperty(firstBean, propertyToSort);
Object secondObject = propertyMapper.getProperty(secondBbean, propertyToSort);
return comparator.compare(firstObject, secondObject);
}
});
if (sortType.equals(SortConstants.SORT_DESC)) {
Collections.reverse(dataToSort);
}
return dataToSort;
}
@SuppressWarnings("unchecked")
protected List paginateData(List dataToPaginate) {
int firstEntityNumber = getPageSize() * getCurrentPageNumber();
if (firstEntityNumber >= dataToPaginate.size()) {
/*throw new EmptyDataSourceException("");*/
}
int lastEntityNumber = firstEntityNumber + pageSize;
if (lastEntityNumber >= dataToPaginate.size()) {
lastEntityNumber = dataToPaginate.size();
}
if (lastEntityNumber == firstEntityNumber) {
/*throw new EmptyDataSourceException("");*/
}
List resultData = new ArrayList();
for (int i = firstEntityNumber; i < lastEntityNumber; i++) {
resultData.add(dataToPaginate.get(i));
}
return resultData;
}
public int getPageCount() {
return currentPageCount;
}
@SuppressWarnings("unchecked")
public void refreshDisplayData() {
if (initialData == null || initialData.isEmpty()) {
return;
}
List dataToBeDisplayed = new ArrayList();
for (int i = 0; i < getInitialData().size(); i++) {
dataToBeDisplayed.add(getInitialData().get(i));
}
dataToBeDisplayed = filterData(dataToBeDisplayed);
dataToBeDisplayed = sortData(dataToBeDisplayed);
currentPageCount = dataToBeDisplayed.size() / getPageSize() + 1;
adjustCurrentPage();
if (enabledPagination) {
dataToBeDisplayed = paginateData(dataToBeDisplayed);
}
setDisplayData(dataToBeDisplayed);
}
@SuppressWarnings("unchecked")
public List getInitialData() {
return initialData;
}
public boolean isEmpty() {
return initialData.isEmpty();
}
public int getCurrentPageNumber() {
return currentPageNumber;
}
public void setCurrentPageNumber(int currentPageNumber) {
if (getInitialData() == null) {
setCurrentPageNumber(getLastPageNumber());
} else if (currentPageNumber > getLastPageNumber()) {
setCurrentPageNumber(getLastPageNumber());
} else {
this.currentPageNumber = currentPageNumber;
}
refreshDisplayData();
}
private int getLastPageNumber() {
int lastPageNumber = getInitialData().size() / getPageSize();
return lastPageNumber;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
refreshDisplayData();
}
public void toPreviousPage() {
setCurrentPageNumber(getCurrentPageNumber() - 1);
refreshDisplayData();
}
public void toNextPage() {
setCurrentPageNumber(getCurrentPageNumber() + 1);
refreshDisplayData();
}
public void toFirstPage() {
setCurrentPageNumber(0);
refreshDisplayData();
}
public void toLastPage() {
setCurrentPageNumber(getPageCount() - 1);
refreshDisplayData();
}
public void adjustCurrentPage() {
if (getCurrentPageNumber() >= getPageCount()) {
setCurrentPageNumber(getPageCount() - 1);
}
}
}