1 /*******************************************************************************
2 * Copyright (c) 2012 Original authors and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * Original authors and others - initial API and implementation
10 ******************************************************************************/
11 package org.simantics.browsing.ui.nattable.override;
13 import java.util.ArrayList;
14 import java.util.Collection;
16 import org.eclipse.nebula.widgets.nattable.coordinate.Range;
17 import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform;
18 import org.eclipse.nebula.widgets.nattable.layer.ILayer;
19 import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
20 import org.eclipse.nebula.widgets.nattable.layer.LayerUtil;
21 import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
22 import org.eclipse.nebula.widgets.nattable.layer.event.IStructuralChangeEvent;
23 import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent;
25 import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
26 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
29 * AbstractRowHideShowLayer implementation with FastUtils hashmaps.
31 * @see org.eclipse.nebula.widgets.nattable.hideshow.AbstractRowHideShowLayer
36 public abstract class AbstractRowHideShowLayer2 extends AbstractLayerTransform implements IUniqueIndexLayer {
38 private Int2IntOpenHashMap cachedVisibleRowIndexOrder;
39 private Int2IntOpenHashMap cachedVisibleRowPositionOrder;
41 private Int2IntOpenHashMap cachedHiddenRowIndexToPositionMap;
43 protected final Int2IntOpenHashMap startYCache = new Int2IntOpenHashMap();
46 public AbstractRowHideShowLayer2(IUniqueIndexLayer underlyingLayer) {
47 super(underlyingLayer);
51 public void handleLayerEvent(ILayerEvent event) {
52 if (event instanceof IStructuralChangeEvent) {
53 IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event;
54 if (structuralChangeEvent.isVerticalStructureChanged()) {
55 // vertical structure has changed, update cached row information
58 } else if (event instanceof VisualRefreshEvent) {
59 // visual change, e.g. font change, the startYCache needs to be
60 // cleared in order to re-render correctly
61 this.startYCache.clear();
63 super.handleLayerEvent(event);
66 // Horizontal features
71 public int getColumnPositionByIndex(int columnIndex) {
72 return ((IUniqueIndexLayer) getUnderlyingLayer()).getColumnPositionByIndex(columnIndex);
80 public int getRowCount() {
81 return getCachedVisibleRowIndexes().size();
85 public int getRowIndexByPosition(int rowPosition) {
86 if (rowPosition < 0 || rowPosition >= getRowCount()) {
89 return getCachedVisibleRowPositons().get(rowPosition);
93 public int getRowPositionByIndex(int rowIndex) {
94 return getCachedVisibleRowIndexes().get(rowIndex);
97 public Collection<Integer> getRowPositionsByIndexes(Collection<Integer> rowIndexes) {
98 IntOpenHashSet rowPositions = new IntOpenHashSet();
99 for (int rowIndex : rowIndexes) {
100 rowPositions.add(getRowPositionByIndex(rowIndex));
106 public int localToUnderlyingRowPosition(int localRowPosition) {
107 int rowIndex = getRowIndexByPosition(localRowPosition);
108 return ((IUniqueIndexLayer) getUnderlyingLayer()).getRowPositionByIndex(rowIndex);
112 public int underlyingToLocalRowPosition(ILayer sourceUnderlyingLayer, int underlyingRowPosition) {
113 int rowIndex = getUnderlyingLayer().getRowIndexByPosition(underlyingRowPosition);
114 int rowPosition = getRowPositionByIndex(rowIndex);
115 if (rowPosition >= 0) {
118 if (this.cachedHiddenRowIndexToPositionMap.containsKey(rowIndex)) {
119 return this.cachedHiddenRowIndexToPositionMap.get(rowIndex);
127 public Collection<Range> underlyingToLocalRowPositions(
128 ILayer sourceUnderlyingLayer, Collection<Range> underlyingRowPositionRanges) {
129 Collection<Range> localRowPositionRanges = new ArrayList<Range>();
131 for (Range underlyingRowPositionRange : underlyingRowPositionRanges) {
132 int startRowPosition = getAdjustedUnderlyingToLocalStartPosition(
133 sourceUnderlyingLayer,
134 underlyingRowPositionRange.start,
135 underlyingRowPositionRange.end);
136 int endRowPosition = getAdjustedUnderlyingToLocalEndPosition(
137 sourceUnderlyingLayer,
138 underlyingRowPositionRange.end,
139 underlyingRowPositionRange.start);
141 // teichstaedt: fixes the problem that ranges where added even if
142 // the corresponding startPosition weren't found in the underlying
143 // layer. Without that fix a bunch of ranges of kind Range [-1, 180]
144 // which causes strange behaviour in Freeze- and other Layers were
146 if (startRowPosition > -1) {
147 localRowPositionRanges.add(new Range(startRowPosition, endRowPosition));
151 return localRowPositionRanges;
154 private int getAdjustedUnderlyingToLocalStartPosition(
155 ILayer sourceUnderlyingLayer,
156 int startUnderlyingPosition,
157 int endUnderlyingPosition) {
158 int localStartRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition);
160 while (localStartRowPosition < 0
161 && (startUnderlyingPosition + offset < endUnderlyingPosition)) {
162 localStartRowPosition =
163 underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition + offset++);
165 return localStartRowPosition;
168 private int getAdjustedUnderlyingToLocalEndPosition(
169 ILayer sourceUnderlyingLayer,
170 int endUnderlyingPosition,
171 int startUnderlyingPosition) {
172 int localEndRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - 1);
174 while (localEndRowPosition < 0
175 && (endUnderlyingPosition - offset > startUnderlyingPosition)) {
176 localEndRowPosition =
177 underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - offset++);
179 return localEndRowPosition + 1;
185 public int getHeight() {
186 int lastRowPosition = getRowCount() - 1;
187 return getStartYOfRowPosition(lastRowPosition) + getRowHeightByPosition(lastRowPosition);
193 public int getRowPositionByY(int y) {
194 return LayerUtil.getRowPositionByY(this, y);
198 public int getStartYOfRowPosition(int localRowPosition) {
199 int index = this.startYCache.get(localRowPosition);
203 IUniqueIndexLayer underlyingLayer = (IUniqueIndexLayer) getUnderlyingLayer();
204 int underlyingPosition = localToUnderlyingRowPosition(localRowPosition);
205 if (underlyingPosition < 0) {
208 int underlyingStartY = underlyingLayer.getStartYOfRowPosition(underlyingPosition);
209 if (underlyingStartY < 0) {
213 for (Integer hiddenIndex : getHiddenRowIndexes()) {
214 int hiddenPosition = underlyingLayer.getRowPositionByIndex(hiddenIndex);
215 // if the hidden position is -1, it is hidden in the underlying
216 // layertherefore the underlying layer should handle the positioning
217 if (hiddenPosition >= 0 && hiddenPosition <= underlyingPosition) {
218 underlyingStartY -= underlyingLayer.getRowHeightByPosition(hiddenPosition);
222 this.startYCache.put(localRowPosition, underlyingStartY);
223 return underlyingStartY;
229 * Will check if the row at the specified index is hidden or not. Checks
230 * this layer and also the sublayers for the visibility.
233 * The row index of the row whose visibility state should be
235 * @return <code>true</code> if the row at the specified index is hidden,
236 * <code>false</code> if it is visible.
238 public abstract boolean isRowIndexHidden(int rowIndex);
241 * Will collect and return all indexes of the rows that are hidden in this
242 * layer. Note: It is not intended that it also collects the row indexes of
243 * underlying layers. This would cause issues on calculating positions as
244 * every layer is responsible for those calculations itself.
246 * @return Collection of all row indexes that are hidden in this layer.
248 public abstract Collection<Integer> getHiddenRowIndexes();
253 * Invalidate the cache to ensure that information is rebuild.
255 protected void invalidateCache() {
256 this.cachedVisibleRowIndexOrder = null;
257 this.cachedVisibleRowPositionOrder = null;
258 this.cachedHiddenRowIndexToPositionMap = null;
259 this.startYCache.clear();
262 private Int2IntOpenHashMap getCachedVisibleRowIndexes() {
263 if (this.cachedVisibleRowIndexOrder == null) {
264 cacheVisibleRowIndexes();
266 return this.cachedVisibleRowIndexOrder;
269 private Int2IntOpenHashMap getCachedVisibleRowPositons() {
270 if (this.cachedVisibleRowPositionOrder == null) {
271 cacheVisibleRowIndexes();
273 return this.cachedVisibleRowPositionOrder;
276 protected void cacheVisibleRowIndexes() {
277 this.cachedVisibleRowIndexOrder = new Int2IntOpenHashMap();
278 this.cachedVisibleRowPositionOrder = new Int2IntOpenHashMap();
279 this.cachedHiddenRowIndexToPositionMap = new Int2IntOpenHashMap();
280 this.startYCache.clear();
282 cachedVisibleRowPositionOrder.defaultReturnValue(-1);
283 cachedVisibleRowIndexOrder.defaultReturnValue(-1);
284 cachedHiddenRowIndexToPositionMap.defaultReturnValue(-1);
285 startYCache.defaultReturnValue(-1);
287 ILayer underlyingLayer = getUnderlyingLayer();
289 for (int parentRowPosition = 0; parentRowPosition < underlyingLayer.getRowCount(); parentRowPosition++) {
290 int rowIndex = underlyingLayer.getRowIndexByPosition(parentRowPosition);
292 if (!isRowIndexHidden(rowIndex)) {
293 this.cachedVisibleRowIndexOrder.put(rowIndex, rowPosition);
294 this.cachedVisibleRowPositionOrder.put(rowPosition, rowIndex);
297 this.cachedHiddenRowIndexToPositionMap.put(rowIndex, rowPosition);