/*
* Copyright 2014 cruxframework.org.
*
* Licensed 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.cruxframework.crux.core.client.dataprovider;
import org.cruxframework.crux.core.client.collection.Array;
import org.cruxframework.crux.core.client.collection.CollectionFactory;
import com.google.gwt.event.shared.HandlerRegistration;
/**
* @author Thiago da Rosa de Bustamante
*/
abstract class AbstractPagedDataProvider<E> extends AbstractScrollableDataProvider<E>
implements MeasurablePagedProvider<E>
{
protected int currentPage = 0;
protected Array<PageLoadedHandler> pageLoadedHandlers;
protected Array<PageRequestedHandler> pageRequestedHandlers;
protected int pageSize = 10;
protected int previousPage = -1;
public AbstractPagedDataProvider()
{
}
public AbstractPagedDataProvider(DataProvider.EditionDataHandler<E> handler)
{
super(handler);
}
@Override
public DataProviderRecord<E> add(E object)
{
int index = getPageEndRecord()+1;
return operations.insertRecord(index, object);
}
@Override
public HandlerRegistration addPageLoadedHandler(final PageLoadedHandler handler)
{
if (pageLoadedHandlers == null)
{
pageLoadedHandlers = CollectionFactory.createArray();
}
pageLoadedHandlers.add(handler);
return new HandlerRegistration()
{
@Override
public void removeHandler()
{
int index = pageLoadedHandlers.indexOf(handler);
if (index >= 0)
{
pageLoadedHandlers.remove(index);
}
}
};
}
@Override
public HandlerRegistration addPageRequestedHandler(final PageRequestedHandler handler)
{
if (pageRequestedHandlers == null)
{
pageRequestedHandlers = CollectionFactory.createArray();
}
pageRequestedHandlers.add(handler);
return new HandlerRegistration()
{
@Override
public void removeHandler()
{
int index = pageRequestedHandlers.indexOf(handler);
if (index >= 0)
{
pageRequestedHandlers.remove(index);
}
}
};
}
@Override
public void firstOnPage()
{
int pageStartRecord = getPageStartRecord();
if (pageStartRecord != currentRecord)
{
ensureLoaded();
currentRecord = pageStartRecord;
}
}
@Override
public int getCurrentPage()
{
return currentPage;
}
@Override
public int getCurrentPageSize()
{
int pageEndRecord = getPageEndRecord();
if (pageEndRecord < 0)
{
return 0;
}
return pageEndRecord - getPageStartRecord() + 1;
}
@Override
public int getCurrentPageStartRecord()
{
return getPageStartRecord();
}
@Override
public int getPageCount()
{
int numRecords = size();
int pageSize = getPageSize();
return (numRecords / pageSize) + (numRecords%pageSize==0?0:1);
}
@Override
public int getPageSize()
{
return pageSize;
}
@Override
public boolean hasNext()
{
return isRecordOnPage(currentRecord+1);
}
@Override
public boolean hasNextPage()
{
ensureLoaded();
return (currentPage < getPageCount());
}
@Override
public boolean hasPrevious()
{
return isRecordOnPage(currentRecord-1);
}
@Override
public boolean hasPreviousPage()
{
ensureLoaded();
return (currentPage > 1 );
}
@Override
public void last()
{
ensureLoaded();
currentRecord = getPageEndRecord();
}
@Override
public boolean nextPage()
{
ensureNotDirty();
if (hasNextPage())
{
previousPage = currentPage;
currentPage++;
updateCurrentRecord();
firePageRequestedEvent(currentPage);
return true;
}
return false;
}
@Override
public boolean previousPage()
{
ensureNotDirty();
if (hasPreviousPage())
{
previousPage = currentPage;
currentPage--;
updateCurrentRecord();
firePageRequestedEvent(currentPage);
return true;
}
return false;
}
@Override
public void reset()
{
super.reset();
previousPage = -1;
currentPage = 0;
}
@Override
public boolean setCurrentPage(int pageNumber)
{
return setCurrentPage(pageNumber, true);
}
@Override
public void setPageSize(int pageSize)
{
ensureNotDirty();
if (pageSize < 1)
{
pageSize = 1;
}
this.pageSize = pageSize;
if (this.isLoaded())
{
updateCurrentRecord();
firePageRequestedEvent(currentPage);
}
}
@Override
protected void changePositionAfterSorting()
{
firstOnPage();
}
protected void firePageLoadedEvent(int start, int end)
{
if (pageLoadedHandlers != null)
{
PageLoadedEvent event = new PageLoadedEvent(this, start, end, previousPage, currentPage);
for (int i = 0; i< pageLoadedHandlers.size(); i++)
{
pageLoadedHandlers.get(i).onPageLoaded(event);
}
}
}
protected void firePageRequestedEvent(int pageNumber)
{
if (pageRequestedHandlers != null)
{
PageRequestedEvent event = new PageRequestedEvent(this, pageNumber);
for (int i = 0; i< pageRequestedHandlers.size(); i++)
{
pageRequestedHandlers.get(i).onPageRequested(event);
}
}
}
protected int getPageEndRecord()
{
return getPageEndRecord(currentPage);
}
protected int getPageEndRecord(int page)
{
int pageEndRecord = (page * pageSize) - 1;
if (page == currentPage)
{
pageEndRecord += operations.getNewRecordsCount() - operations.getRemovedRecordsCount();
}
if (pageEndRecord >= this.data.size())
{
pageEndRecord = this.data.size()-1;
}
return pageEndRecord;
}
protected int getPageForRecord(int recordNumber, boolean mayExpand)
{
int pageSize = getPageSize();
int index = recordNumber + 1;
int result = (index / pageSize) + (index%pageSize==0?0:1);
if (!mayExpand && result > getPageCount())
{
throw new DataProviderException("Invalid record. Out of bounds");
}
return result;
}
protected int getPageStartRecord()
{
return getPageStartRecord(currentPage);
}
protected int getPageStartRecord(int page)
{
return (page - 1) * pageSize;
}
@Override
protected Array<DataProviderRecord<E>> getTransactionRecords()
{
Array<DataProviderRecord<E>> currentPageRecordsArray = CollectionFactory.createArray();
int start = getPageStartRecord();
int end = getPageEndRecord();
for (int i = start; i <= end; i++)
{
DataProviderRecord<E> record = data.get(i);
currentPageRecordsArray.add(record.clone());
}
return currentPageRecordsArray;
}
protected boolean isRecordOnPage(int record)
{
ensureLoaded();
if (data == null)
{
return false;
}
int startPageRecord = getPageStartRecord();
int endPageRescord = getPageEndRecord();
return (record >= startPageRecord && record <= endPageRescord);
}
@Override
protected int lockRecordForEdition(int recordIndex)
{
int pageForRecord = getPageForRecord(recordIndex, true);
setCurrentPage(pageForRecord, false);
return getPageStartRecord(pageForRecord);
}
@Override
protected void replaceTransactionData(Array<DataProviderRecord<E>> transactionRecords)
{
int start = getPageStartRecord();
int end = getPageEndRecord();
int count = end-start+1;
if (count > 0)
{
data.remove(start, count);
}
for (int i=0; i<transactionRecords.size(); i++)
{
data.insert(start+i, transactionRecords.get(i));
}
}
protected boolean setCurrentPage(int pageNumber, boolean fireEvents)
{
ensureLoaded();
ensureNotDirty();
if (pageNumber > 0 && pageNumber <= getPageCount())
{
previousPage = currentPage;
currentPage = pageNumber;
updateCurrentRecord();
if (fireEvents)
{
firePageRequestedEvent(currentPage);
}
return true;
}
return false;
}
@Override
protected void setFirstPosition(boolean fireEvents)
{
if (currentPage == 0 || hasPreviousPage())
{
setCurrentPage(1, fireEvents);
}
else
{
firstOnPage();
}
}
protected void updateCurrentRecord()
{
currentRecord = getPageStartRecord();
}
}