blob: 3576e952b295427b997e7e7c8f5d0da91285dd7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2020 Dirk Fauth and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.nebula.widgets.nattable.reorder.event;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.collections.api.list.primitive.MutableIntList;
import org.eclipse.collections.impl.factory.primitive.IntLists;
import org.eclipse.nebula.widgets.nattable.coordinate.PositionUtil;
import org.eclipse.nebula.widgets.nattable.coordinate.Range;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.event.RowStructuralChangeEvent;
import org.eclipse.nebula.widgets.nattable.layer.event.StructuralDiff;
import org.eclipse.nebula.widgets.nattable.layer.event.StructuralDiff.DiffTypeEnum;
import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
/**
* Event indicating that one or multiple rows are moved to a new position.
*/
public class RowReorderEvent extends RowStructuralChangeEvent {
private ILayer beforeLayer;
private Collection<Range> beforeFromRowPositionRanges;
private MutableIntList beforeFromRowIndexes;
private int beforeToRowPosition;
private int beforeToRowIndex;
private boolean reorderToTopEdge;
/**
*
* @param layer
* The layer to which the row positions match.
* @param beforeFromRowPosition
* The row position that was reordered, before the reorder
* operation was performed.
* @param beforeFromRowIndex
* The index of the reordered position.
* @param beforeToRowPosition
* The position of the row to which the reorder operation was
* performed, before the reorder operation was performed
* @param beforeToRowIndex
* The index of the row to which the reorder operation was
* performed.
* @param reorderToTopEdge
* whether the reorder operation was performed to the top or the
* bottom edge.
*
* @since 1.6
*/
public RowReorderEvent(ILayer layer,
int beforeFromRowPosition,
int beforeFromRowIndex,
int beforeToRowPosition,
int beforeToRowIndex,
boolean reorderToTopEdge) {
this(layer,
new int[] { beforeFromRowPosition },
new int[] { beforeFromRowIndex },
beforeToRowPosition,
beforeToRowIndex,
reorderToTopEdge);
}
/**
*
* @param layer
* The layer to which the row positions match.
* @param beforeFromRowPositions
* The row positions that were reordered, before the reorder
* operation was performed.
* @param beforeFromRowIndexes
* The indexes of the reordered positions.
* @param beforeToRowPosition
* The position of the row to which the reorder operation was
* performed, before the reorder operation was performed
* @param beforeToRowIndex
* The index of the row to which the reorder operation was
* performed.
* @param reorderToTopEdge
* whether the reorder operation was performed to the top or the
* bottom edge.
*
* @since 1.6
*/
public RowReorderEvent(ILayer layer,
List<Integer> beforeFromRowPositions,
List<Integer> beforeFromRowIndexes,
int beforeToRowPosition,
int beforeToRowIndex,
boolean reorderToTopEdge) {
this(layer,
beforeFromRowPositions.stream().mapToInt(Integer::intValue).toArray(),
beforeFromRowIndexes.stream().mapToInt(Integer::intValue).toArray(),
beforeToRowPosition,
beforeToRowIndex,
reorderToTopEdge);
}
/**
*
* @param layer
* The layer to which the row positions match.
* @param beforeFromRowPositions
* The row positions that were reordered, before the reorder
* operation was performed.
* @param beforeFromRowIndexes
* The indexes of the reordered positions.
* @param beforeToRowPosition
* The position of the row to which the reorder operation was
* performed, before the reorder operation was performed
* @param beforeToRowIndex
* The index of the row to which the reorder operation was
* performed.
* @param reorderToTopEdge
* whether the reorder operation was performed to the top or the
* bottom edge.
*
* @since 2.0
*/
public RowReorderEvent(ILayer layer,
int[] beforeFromRowPositions,
int[] beforeFromRowIndexes,
int beforeToRowPosition,
int beforeToRowIndex,
boolean reorderToTopEdge) {
super(layer);
this.beforeLayer = layer;
this.beforeFromRowPositionRanges = PositionUtil.getRanges(beforeFromRowPositions);
this.beforeFromRowIndexes = IntLists.mutable.of(beforeFromRowIndexes);
this.beforeToRowPosition = beforeToRowPosition;
this.beforeToRowIndex = beforeToRowIndex;
this.reorderToTopEdge = reorderToTopEdge;
MutableIntList allColumnPositions = IntLists.mutable.of(beforeFromRowPositions);
allColumnPositions.add(beforeToRowPosition);
setRowPositionRanges(PositionUtil.getRanges(allColumnPositions.toSortedArray()));
}
/**
* Constructor for internal use to clone this event.
*
* @param event
* The event out of which the new one should be created
*/
public RowReorderEvent(RowReorderEvent event) {
super(event);
this.beforeLayer = event.beforeLayer;
this.beforeFromRowPositionRanges = event.beforeFromRowPositionRanges;
this.beforeFromRowIndexes = IntLists.mutable.ofAll(event.beforeFromRowIndexes);
this.beforeToRowPosition = event.beforeToRowPosition;
this.beforeToRowIndex = event.beforeToRowIndex;
this.reorderToTopEdge = event.reorderToTopEdge;
}
/**
*
* @return The indexes of the reordered rows.
* @since 1.6
*/
public Collection<Integer> getBeforeFromRowIndexes() {
return ArrayUtil.asIntegerList(this.beforeFromRowIndexes.toSortedArray());
}
/**
*
* @return The indexes of the reordered rows.
* @since 2.0
*/
public int[] getBeforeFromRowIndexesArray() {
return this.beforeFromRowIndexes.toSortedArray();
}
/**
*
* @return The position ranges of the reordered rows.
*/
public Collection<Range> getBeforeFromRowPositionRanges() {
return this.beforeFromRowPositionRanges;
}
/**
*
* @return The position of the row to which the reorder operation was
* performed.
*/
public int getBeforeToRowPosition() {
return this.beforeToRowPosition;
}
/**
*
* @return The index of the row to which the reorder operation was
* performed.
* @since 1.6
*/
public int getBeforeToRowIndex() {
return this.beforeToRowIndex;
}
/**
* Setter for the beforeToRowIndex that needs to be called used in case a
* reorder operation was performed to a hidden row.
*
* @param beforeIndex
* The index of the row to which the reorder operation was
* performed.
* @since 1.6
*/
public void setBeforeToRowIndex(int beforeIndex) {
this.beforeToRowIndex = beforeIndex;
}
/**
*
* @return <code>true</code> if the rows were reordered to the top edge of
* the toRowPosition, <code>false</code> if the reorder operation
* was performed on the bottom edge (e.g. at the end of a table)
*/
public boolean isReorderToTopEdge() {
return this.reorderToTopEdge;
}
@Override
public Collection<StructuralDiff> getRowDiffs() {
Collection<StructuralDiff> rowDiffs = new ArrayList<>();
Collection<Range> beforeFromRowPositionRanges = getBeforeFromRowPositionRanges();
final int beforeToRowPosition = (this.reorderToTopEdge)
? this.beforeToRowPosition
: (this.beforeToRowPosition + 1);
int afterAddRowPosition = beforeToRowPosition;
for (Range beforeFromRowPositionRange : beforeFromRowPositionRanges) {
if (beforeFromRowPositionRange.start < beforeToRowPosition) {
afterAddRowPosition -=
Math.min(beforeFromRowPositionRange.end, beforeToRowPosition) - beforeFromRowPositionRange.start;
} else {
break;
}
}
int cumulativeAddSize = 0;
for (Range beforeFromRowPositionRange : beforeFromRowPositionRanges) {
cumulativeAddSize += beforeFromRowPositionRange.size();
}
int offset = 0;
for (Range beforeFromRowPositionRange : beforeFromRowPositionRanges) {
int afterDeleteRowPosition = beforeFromRowPositionRange.start - offset;
if (afterAddRowPosition < afterDeleteRowPosition) {
afterDeleteRowPosition += cumulativeAddSize;
}
rowDiffs.add(new StructuralDiff(
DiffTypeEnum.DELETE,
beforeFromRowPositionRange,
new Range(afterDeleteRowPosition, afterDeleteRowPosition)));
offset += beforeFromRowPositionRange.size();
}
Range beforeAddRange = new Range(beforeToRowPosition, beforeToRowPosition);
offset = 0;
for (Range beforeFromRowPositionRange : beforeFromRowPositionRanges) {
int size = beforeFromRowPositionRange.size();
rowDiffs.add(new StructuralDiff(
DiffTypeEnum.ADD,
beforeAddRange,
new Range(afterAddRowPosition + offset, afterAddRowPosition + offset + size)));
offset += size;
}
return rowDiffs;
}
/**
* This method is intended to be used for position conversion of the before
* positions. The locally stored before positions are the positions of the
* reordered row positions <b>before</b> the reorder is applied. Needed in
* case the conversion needs to be done before other states in the given
* layer are updated, and therefore the local before position cannot be
* determined anymore.
*
* @param layer
* The layer that performed the conversion of the before
* positions.
* @param fromRowPositionRanges
* The converted row position ranges that were reordered before
* the reorder happened.
* @param toRowPosition
* The converted row position to which a reorder happened before
* the reordering was performed.
*
* @since 1.6
*/
public void setConvertedBeforePositions(ILayer layer, Collection<Range> fromRowPositionRanges, int toRowPosition) {
this.beforeLayer = layer;
this.beforeFromRowPositionRanges = fromRowPositionRanges;
this.beforeToRowPosition = toRowPosition;
}
@Override
public boolean convertToLocal(ILayer targetLayer) {
// if the conversion was done before, e.g. by an
// AbstractRowHideShowLayer, we don't need to perform the conversion
// again
if (this.beforeLayer != targetLayer) {
this.beforeFromRowPositionRanges =
targetLayer.underlyingToLocalRowPositions(getLayer(), this.beforeFromRowPositionRanges);
this.beforeToRowPosition =
targetLayer.underlyingToLocalRowPosition(getLayer(), this.beforeToRowPosition);
this.beforeLayer = targetLayer;
}
if (this.beforeToRowPosition >= 0) {
return super.convertToLocal(targetLayer);
} else {
return false;
}
}
@Override
public RowReorderEvent cloneEvent() {
return new RowReorderEvent(this);
}
}