| package org.eclipse.nebula.widgets.nattable.core.layer.axis.impl.hideshow |
| |
| import java.io.Serializable |
| import java.math.BigDecimal |
| import java.util.HashMap |
| import java.util.TreeMap |
| import org.eclipse.nebula.widgets.nattable.core.layer.axis.Axis |
| import org.eclipse.nebula.widgets.nattable.core.layer.axis.impl.AbstractAxis |
| |
| import static extension org.eclipse.nebula.widgets.nattable.core.layer.axis.AxisInvariants.* |
| import static extension org.eclipse.nebula.widgets.nattable.core.math.BigDecimalExtensions.* |
| |
| /** |
| * An axis that allows segments to be hidden and later shown again. |
| * <p> |
| * NOTE: This axis implementation is not performant for large numbers (e.g. thousands) of segments. |
| */ |
| class HideShowAxis extends AbstractAxis { |
| |
| val hiddenSegmentPositionToIdMap = new TreeMap<Long, Serializable> |
| val segmentPositionToStartPixelMap = new HashMap<Long, BigDecimal> |
| |
| Axis underlyingAxis |
| |
| new() {} |
| |
| new(Axis underlyingAxis) { |
| setUnderlyingAxis(underlyingAxis) |
| } |
| |
| def void setUnderlyingAxis(Axis underlyingAxis) { |
| this.underlyingAxis = underlyingAxis |
| } |
| |
| // Axis interface |
| |
| override getSegmentCount() { |
| underlyingAxis.segmentCount - hiddenSegmentPositionToIdMap.size |
| } |
| |
| override getStartPixelOfSegmentPosition(long segmentPosition) { |
| val startPixel = segmentPositionToStartPixelMap.get(segmentPosition) |
| if (startPixel != null) |
| return startPixel |
| else { |
| var aggregateSize = new BigDecimal(0.0) |
| |
| for (position : 0 ..< segmentPosition) { |
| val segmentId = getIdOfSegmentPosition(position) |
| val underlyingSegmentPosition = underlyingAxis.getSegmentPositionOfId(segmentId) |
| aggregateSize = aggregateSize + underlyingAxis.getPixelSizeOfSegmentPosition(underlyingSegmentPosition) |
| } |
| |
| segmentPositionToStartPixelMap.put(segmentPosition, aggregateSize) |
| return aggregateSize |
| } |
| } |
| |
| override getSegmentPositionOfPixelLocation(BigDecimal pixelLocation) { |
| if (pixelLocation < new BigDecimal(0)) return -1 |
| |
| for (segmentPosition : 0 .. segmentCount) { |
| val startPixel = getStartPixelOfSegmentPosition(segmentPosition) |
| if (startPixel > pixelLocation) |
| return segmentPosition - 1 |
| } |
| |
| return segmentCount |
| } |
| |
| // TODO Optimize. Cache? |
| override getIdOfSegmentPosition(long segmentPosition) { |
| var numHiddenSegments = 0L |
| var fromPosition = 0L |
| var toPosition = segmentPosition |
| |
| while (toPosition < underlyingAxis.segmentCount) { |
| var numHiddenSegmentsAtOrBeforeToPosition = hiddenSegmentPositionToIdMap.subMap(fromPosition, toPosition + 1).size |
| if (numHiddenSegmentsAtOrBeforeToPosition == 0) |
| return underlyingAxis.getIdOfSegmentPosition(segmentPosition + numHiddenSegments) |
| else { |
| numHiddenSegments = numHiddenSegments + numHiddenSegmentsAtOrBeforeToPosition |
| fromPosition = toPosition + 1 |
| toPosition = toPosition + numHiddenSegmentsAtOrBeforeToPosition |
| } |
| } |
| |
| null |
| } |
| |
| override getSegmentPositionOfId(Serializable segmentId) { |
| val underlyingSegmentPosition = underlyingAxis.getSegmentPositionOfId(segmentId) |
| underlyingSegmentPosition - hiddenSegmentPositionToIdMap.subMap(0L, underlyingSegmentPosition).size |
| } |
| |
| // |
| |
| def hideSegmentId(Serializable segmentId) { |
| val underlyingSegmentPosition = underlyingAxis.getSegmentPositionOfId(segmentId) |
| if (underlyingAxis.containsSegmentPosition(underlyingSegmentPosition)) { |
| hiddenSegmentPositionToIdMap.put(underlyingSegmentPosition, segmentId) |
| segmentPositionToStartPixelMap.clear |
| } |
| } |
| |
| def showSegmentId(Serializable segmentId) { |
| val underlyingSegmentPosition = underlyingAxis.getSegmentPositionOfId(segmentId) |
| if (underlyingAxis.containsSegmentPosition(underlyingSegmentPosition)) { |
| val mapping = hiddenSegmentPositionToIdMap.remove(underlyingSegmentPosition) |
| if (mapping != null) |
| segmentPositionToStartPixelMap.clear |
| } |
| } |
| |
| } |