/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.web.wicket;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.projectforge.common.MyBeanComparator;
import org.projectforge.core.BaseDao;
import org.projectforge.core.IdObject;
/**
* Stores list of result sets (id's) for pagination and provides iterator of data-base objects on demand.
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class MyListPageSortableDataProvider<T extends IdObject< ? >> extends SortableDataProvider<T, String>
{
private static final long serialVersionUID = 1517715565769991765L;
/**
* Complete list is needed every time the sort parameters or filter settings were changed.
*/
private List<T> completeList;
/**
* Stores only the id's of the result set.
*/
private List<Serializable> idList;
private Long first, count;
private SortParam<String> sortParam;
private SortParam<String> secondSortParam;
private final AbstractListPage< ? , ? , T> listPage;
public MyListPageSortableDataProvider(final SortParam<String> sortParam, final SortParam<String> secondSortParam,
final AbstractListPage< ? , ? , T> listPage)
{
this.listPage = listPage;
// set default sort
if (sortParam != null) {
setSort(sortParam);
} else {
setSort("NOSORT", SortOrder.ASCENDING);
}
}
public MyListPageSortableDataProvider<T> setCompleteList(final List<T> completeList)
{
this.completeList = completeList;
this.idList = new LinkedList<Serializable>();
if (this.completeList != null) {
sortList(this.completeList);
for (final T entry : completeList) {
this.idList.add(entry.getId());
}
}
return this;
}
/**
* @see org.apache.wicket.markup.repeater.data.IDataProvider#iterator(int, int)
*/
@SuppressWarnings("unchecked")
@Override
public Iterator<T> iterator(final long first, final long count)
{
if ((this.first != null && this.first != first) || (this.count != null && this.count != count)) {
this.completeList = null; // Force to load all elements from data-base (avoid lazy initialization exceptions).
}
final SortParam<String> sp = getSort();
if (ObjectUtils.equals(sortParam, sp) == false) {
// The sort parameters were changed, force reload from data-base:
reloadList();
}
this.first = first;
this.count = count;
if (idList == null) {
return null;
}
List<T> result;
int fromIndex = (int) first;
if (fromIndex < 0) {
fromIndex = 0;
}
int toIndex = (int) (first + count);
if (this.completeList != null) {
// The completeList is already load, don't need to load objects from data-base:
result = completeList;
if (toIndex > idList.size()) {
toIndex = idList.size();
}
result = new LinkedList<T>();
for (final T entry : completeList.subList(fromIndex, toIndex)) {
result.add(entry);
}
this.completeList = null; // Don't store the complete list on the server anymore.
return result.iterator();
} else {
if (toIndex > idList.size()) {
toIndex = idList.size();
}
final Object baseDao = listPage.getBaseDao();
if (baseDao instanceof BaseDao) {
final List<T> list = (List<T>) ((BaseDao< ? >) baseDao).internalLoad(idList.subList(fromIndex, toIndex));
sortList(list);
return list.iterator();
} else {
// Can't load objects from BaseDao, have to load complete list from scratch:
reloadList();
result = completeList;
if (toIndex > idList.size()) {
toIndex = idList.size();
}
return result.subList(fromIndex, toIndex).iterator();
}
}
}
protected Comparator<T> getComparator(final SortParam<String> sortParam, final SortParam<String> secondSortParam)
{
final String sortProperty = sortParam != null ? sortParam.getProperty() : null;
final boolean ascending = sortParam != null ? sortParam.isAscending() : true;
final String secondSortProperty = secondSortParam != null ? secondSortParam.getProperty() : null;
final boolean secondAscending = secondSortParam != null ? secondSortParam.isAscending() : true;
return new MyBeanComparator<T>(sortProperty, ascending, secondSortProperty, secondAscending);
}
/**
* @see org.apache.wicket.markup.repeater.data.IDataProvider#size()
*/
@Override
public long size()
{
if (idList == null) {
reloadList();
}
return this.idList != null ? this.idList.size() : 0;
}
private void reloadList()
{
final List<T> list = listPage.getList();
setCompleteList(list);
}
private void sortList(final List<T> list)
{
final SortParam<String> sp = getSort();
if (sp != null && "NOSORT".equals(sp.getProperty()) == false) {
if (this.sortParam != null && StringUtils.equals(this.sortParam.getProperty(), sp.getProperty()) == false) {
this.secondSortParam = this.sortParam;
}
final Comparator<T> comp = getComparator(sp, secondSortParam);
Collections.sort(list, comp);
}
this.sortParam = sp;
}
/**
* @see org.apache.wicket.markup.repeater.data.IDataProvider#model(java.lang.Object)
*/
@Override
public IModel<T> model(final T object)
{
return new Model<T>(object);
}
/**
* @see ISortableDataProvider#detach()
*/
@Override
public void detach()
{
this.completeList = null;
}
}