/* * 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 java.util.ArrayList; import java.util.List; import org.cruxframework.crux.core.client.collection.Array; import org.cruxframework.crux.core.client.collection.CollectionFactory; import org.cruxframework.crux.core.client.dataprovider.DataProviderRecord.DataProviderRecordState; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; /** * @author Thiago da Rosa de Bustamante */ class StreamingDataProviderOperations<T> { protected List<DataProviderRecord<T>> changedRecords = new ArrayList<DataProviderRecord<T>>(); protected StreamingDataProvider<T> dataProvider; protected List<DataProviderRecord<T>> newRecords = new ArrayList<DataProviderRecord<T>>(); protected List<DataProviderRecord<T>> removedRecords = new ArrayList<DataProviderRecord<T>>(); protected List<DataProviderRecord<T>> selectedRecords = new ArrayList<DataProviderRecord<T>>(); protected Array<DataProviderRecord<T>> transactionOriginalData = null; StreamingDataProviderOperations(StreamingDataProvider<T> dataProvider) { this.dataProvider = dataProvider; } void beginTransaction(int recordIndex) { if(transactionOriginalData == null) { int firstRecordToLock = dataProvider.lockRecordForEdition(recordIndex); this.transactionOriginalData = dataProvider.getTransactionRecords(); dataProvider.fireTransactionStartEvent(firstRecordToLock); } } void commit() { for(DataProviderRecord<T> newRecord : newRecords) { newRecord.setCreated(false); newRecord.setDirty(false); } for(DataProviderRecord<T> changedRecord : changedRecords) { changedRecord.setCreated(false); changedRecord.setDirty(false); } dataProvider.fireTransactionEndEvent(true); endTransaction(); } void endTransaction() { newRecords.clear(); removedRecords.clear(); changedRecords.clear(); this.transactionOriginalData = null; } Array<DataProviderRecord<T>> getCurrentPageRecords(boolean cleanRecordsChanges) { Array<DataProviderRecord<T>> currentPageRecordsArray = CollectionFactory.createArray(); int start = this.dataProvider.getPageStartRecord(); int end = this.dataProvider.getLoadedPageEndRecord(); for (int i = start; i <= end; i++) { DataProviderRecord<T> record = dataProvider.data.get(i); currentPageRecordsArray.add(record); if(cleanRecordsChanges) { record.setCreated(false); record.setDirty(false); } } return currentPageRecordsArray; } @SuppressWarnings("unchecked") DataProviderRecord<T>[] getNewRecords() { return newRecords.toArray(new DataProviderRecord[newRecords.size()]); } int getNewRecordsCount() { return newRecords.size(); } int getRecordIndex(T boundObject) { for(int i = 0; i < this.dataProvider.data.size(); i++) { if(this.dataProvider.data.get(i).recordObject.equals(boundObject)) { return i; } } return -1; } @SuppressWarnings("unchecked") DataProviderRecord<T>[] getRemovedRecords() { return removedRecords.toArray(new DataProviderRecord[removedRecords.size()]); } int getRemovedRecordsCount() { return removedRecords.size(); } @SuppressWarnings("unchecked") DataProviderRecord<T>[] getSelectedRecords() { return selectedRecords.toArray(new DataProviderRecord[selectedRecords.size()]); } @SuppressWarnings("unchecked") DataProviderRecord<T>[] getUpdatedRecords() { return changedRecords.toArray(new DataProviderRecord[changedRecords.size()]); } DataProviderRecord<T> insertRecord(int index, T object) { beginTransaction(index); this.dataProvider.ensureCurrentPageLoaded(); checkRange(index, true); DataProviderRecord<T> record = new DataProviderRecord<T>(this.dataProvider); record.setCreated(true); record.set(object); this.dataProvider.data.insert(index, record); newRecords.add(record); this.dataProvider.fireDataChangedEvent(record, index); return record; } DataProviderRecord<T> insertRecord(T object) { int index = this.dataProvider.data.size()-1; if (index < 0) { index = 0; } return insertRecord(index, object); } boolean isDirty() { return (newRecords.size() > 0) || (removedRecords.size() > 0) || (changedRecords.size() > 0); } DataProviderRecord<T> removeRecord(int index) { this.dataProvider.ensureCurrentPageLoaded(); checkRange(index, false); beginTransaction(index); DataProviderRecord<T> record = this.dataProvider.data.get(index); DataProviderRecordState previousState = record.getCurrentState(); if (previousState.isReadOnly()) { throw new DataProviderException("Can not update a read only information");//TODO i18n } record.setRemoved(true); this.dataProvider.data.remove(index); updateState(record, previousState); this.dataProvider.fireDataChangedEvent(record, index); return record; } void reset() { newRecords.clear(); removedRecords.clear(); changedRecords.clear(); selectedRecords.clear(); } void rollback() { if(transactionOriginalData != null) { dataProvider.fireTransactionEndEvent(false); dataProvider.replaceTransactionData(this.transactionOriginalData); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { dataProvider.unselectAllRecords(); } }); endTransaction(); } } void selectAllRecords(boolean selected) { Array<DataProviderRecord<T>> changedRecords = CollectionFactory.createArray();; for(int i = 0; i < this.dataProvider.data.size(); i++) { DataProviderRecord<T> record = this.dataProvider.data.get(i); if(record != null && record.isSelected() != selected) { changedRecords.add(record); record.state.setSelected(selected); if (selected) { selectedRecords.add(record); } else { selectedRecords.remove(record); } } } if (changedRecords.size() > 0) { dataProvider.fireDataSelectionEvent(changedRecords); } } DataProviderRecord<T> selectRecord(int index, boolean selected, boolean fireEvents) { checkRange(index, false); DataProviderRecord<T> record = this.dataProvider.data.get(index); record.setSelected(selected, fireEvents); return record; } DataProviderRecord<T> setReadOnly(int index, boolean readOnly) { checkRange(index, false); DataProviderRecord<T> record = this.dataProvider.data.get(index); record.setReadOnly(readOnly); return record; } DataProviderRecord<T> updateRecord(int index, T object) { beginTransaction(index); this.dataProvider.ensureCurrentPageLoaded(); checkRange(index, false); DataProviderRecord<T> record = this.dataProvider.data.get(index); if (record != null) { if (record.isReadOnly()) { throw new DataProviderException("Can not update a read only information");//TODO i18n } record.set(object); } this.dataProvider.fireDataChangedEvent(record, index); return record; } void updateState(DataProviderRecord<T> record, DataProviderRecordState previousState) { this.dataProvider.ensureLoaded(); if (record.isCreated()) { if (record.isRemoved()) { newRecords.remove(record); } } else if (record.isRemoved()) { if (!previousState.isRemoved()) { removedRecords.add(record); if (previousState.isDirty()) { changedRecords.remove(record); } if (previousState.isSelected()) { selectedRecords.remove(record); } } } else if (record.isDirty() && !previousState.isDirty()) { changedRecords.add(record); } if (record.isSelected() && !previousState.isSelected() && !record.isRemoved()) { selectedRecords.add(record); } else if (!record.isSelected() && previousState.isSelected()) { selectedRecords.remove(record); } } private void checkRange(int index, boolean mayExpand) { if (index < 0 || index > this.dataProvider.data.size()) { throw new IndexOutOfBoundsException(); } if (!mayExpand && index == this.dataProvider.data.size()) { throw new IndexOutOfBoundsException(); } } }