/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cyclop.web.components.iterablegrid;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.markup.repeater.data.IDataProvider;
/** @author Maciej Miklas */
public abstract class IterableDataProvider<E> implements IDataProvider<E> {
private NavigableIterator<E> iterator;
private long itemsPerPage;
private long lastPage = 0;
private long currentPage = 0;
/**
* max amount of elements read from iterator. This prevents out of memory for large iterators.
*/
private int elementsLimit = Integer.MAX_VALUE;
protected IterableDataProvider(long itemsPerPage) {
this.itemsPerPage = itemsPerPage;
replaceModel();
}
public void setElementsLimit(int elementsLimit) {
this.elementsLimit = elementsLimit;
}
@Override
public final long size() {
long size;
// user goes back on pager, like now he is on page 5 and clicks on 3
// OR
// there is no more data to be read - we are on last page
if (lastPage > currentPage || !iterator.hasMoreData()) {
size = iterator.maxSize();
// user is now on page 2 and clicks on next page - 3. Pager will show
// link for page 4, but not for
// page 5 - this will first happen when user clicks on page 4. In
// order to show link for only
// following page we have to calculate size right. This is the
// amount of elements up to current page (3) plus element that can be displayed on next page.
// If the current page is last page, the link for next page must not
// be shown - this is handled by iterateToIndex(...) - it narrows calculated size to maximum
// allowed value.
} else {
size = iterator.readSize() + itemsPerPage + 1;
size = iterator.iterateToIndex((int) size + 1) - 1;
}
return size;
}
void reset() {
lastPage = 0;
currentPage = 0;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void replaceModel() {
iterator = new NavigableIterator(iterator(), elementsLimit, createElementsCache());
reset();
}
@Override
public final Iterator<E> iterator(long first, long count) {
iterator.prepare((int) first, (int) count);
lastPage = currentPage;
return iterator;
}
void setItemsPerPage(long itemsPerPage) {
this.itemsPerPage = itemsPerPage;
reset();
}
public boolean hasMoreData() {
return iterator.hasMoreData();
}
void setCurrentPage(long currentPage) {
this.currentPage = currentPage;
}
protected abstract Iterator<E> iterator();
/**
* Use this method to replace iterator cache with something else. This can be useful, it you need to display results
* of iterators containing large data amounts (BigList, HugeCollections or BigCollections).
*/
protected List<E> createElementsCache() {
return new ArrayList<>();
}
}