]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/override/AbstractRowHideShowLayer2.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.browsing.ui.nattable / src / org / simantics / browsing / ui / nattable / override / AbstractRowHideShowLayer2.java
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
7  * 
8  * Contributors:
9  *     Original authors and others - initial API and implementation
10  ******************************************************************************/
11 package org.simantics.browsing.ui.nattable.override;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15
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;
24
25 import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
26 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
27
28 /**
29  * AbstractRowHideShowLayer implementation with FastUtils hashmaps.
30  * 
31  * @see org.eclipse.nebula.widgets.nattable.hideshow.AbstractRowHideShowLayer
32  * 
33  * @author MLMARKO
34  *
35  */
36 public abstract class AbstractRowHideShowLayer2 extends AbstractLayerTransform implements IUniqueIndexLayer {
37
38         private Int2IntOpenHashMap cachedVisibleRowIndexOrder;
39         private Int2IntOpenHashMap cachedVisibleRowPositionOrder;
40         
41         private Int2IntOpenHashMap cachedHiddenRowIndexToPositionMap;
42
43         protected final Int2IntOpenHashMap startYCache = new Int2IntOpenHashMap();      
44         
45         
46         public AbstractRowHideShowLayer2(IUniqueIndexLayer underlyingLayer) {
47                 super(underlyingLayer);
48         }
49         
50          @Override
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
56                         invalidateCache();
57                     }
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();
62                 }
63                 super.handleLayerEvent(event);
64             }
65
66             // Horizontal features
67
68             // Columns
69
70             @Override
71             public int getColumnPositionByIndex(int columnIndex) {
72                 return ((IUniqueIndexLayer) getUnderlyingLayer()).getColumnPositionByIndex(columnIndex);
73             }
74
75             // Vertical features
76
77             // Rows
78
79             @Override
80             public int getRowCount() {
81                 return getCachedVisibleRowIndexes().size();
82             }
83
84             @Override
85             public int getRowIndexByPosition(int rowPosition) {
86                 if (rowPosition < 0 || rowPosition >= getRowCount()) {
87                     return -1;
88                 }
89                 return getCachedVisibleRowPositons().get(rowPosition);
90             }
91
92             @Override
93             public int getRowPositionByIndex(int rowIndex) {
94                 return getCachedVisibleRowIndexes().get(rowIndex);
95             }
96
97             public Collection<Integer> getRowPositionsByIndexes(Collection<Integer> rowIndexes) {
98                 IntOpenHashSet rowPositions = new IntOpenHashSet();
99                 for (int rowIndex : rowIndexes) {
100                     rowPositions.add(getRowPositionByIndex(rowIndex));
101                 }
102                 return rowPositions;
103             }
104
105             @Override
106             public int localToUnderlyingRowPosition(int localRowPosition) {
107                 int rowIndex = getRowIndexByPosition(localRowPosition);
108                 return ((IUniqueIndexLayer) getUnderlyingLayer()).getRowPositionByIndex(rowIndex);
109             }
110
111             @Override
112             public int underlyingToLocalRowPosition(ILayer sourceUnderlyingLayer, int underlyingRowPosition) {
113                 int rowIndex = getUnderlyingLayer().getRowIndexByPosition(underlyingRowPosition);
114                 int rowPosition = getRowPositionByIndex(rowIndex);
115                 if (rowPosition >= 0) {
116                     return rowPosition;
117                 } else {
118                         if (this.cachedHiddenRowIndexToPositionMap.containsKey(rowIndex)) {
119                       return this.cachedHiddenRowIndexToPositionMap.get(rowIndex);
120                     } else {
121                         return -1;
122                     }
123                 }
124             }
125
126             @Override
127             public Collection<Range> underlyingToLocalRowPositions(
128                     ILayer sourceUnderlyingLayer, Collection<Range> underlyingRowPositionRanges) {
129                 Collection<Range> localRowPositionRanges = new ArrayList<Range>();
130
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);
140
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
145                     // returned.
146                     if (startRowPosition > -1) {
147                         localRowPositionRanges.add(new Range(startRowPosition, endRowPosition));
148                     }
149                 }
150
151                 return localRowPositionRanges;
152             }
153
154             private int getAdjustedUnderlyingToLocalStartPosition(
155                     ILayer sourceUnderlyingLayer,
156                     int startUnderlyingPosition,
157                     int endUnderlyingPosition) {
158                 int localStartRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition);
159                 int offset = 0;
160                 while (localStartRowPosition < 0
161                         && (startUnderlyingPosition + offset < endUnderlyingPosition)) {
162                     localStartRowPosition =
163                             underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition + offset++);
164                 }
165                 return localStartRowPosition;
166             }
167
168             private int getAdjustedUnderlyingToLocalEndPosition(
169                     ILayer sourceUnderlyingLayer,
170                     int endUnderlyingPosition,
171                     int startUnderlyingPosition) {
172                 int localEndRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - 1);
173                 int offset = 0;
174                 while (localEndRowPosition < 0
175                         && (endUnderlyingPosition - offset > startUnderlyingPosition)) {
176                     localEndRowPosition =
177                             underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - offset++);
178                 }
179                 return localEndRowPosition + 1;
180             }
181
182             // Height
183
184             @Override
185             public int getHeight() {
186                 int lastRowPosition = getRowCount() - 1;
187                 return getStartYOfRowPosition(lastRowPosition) + getRowHeightByPosition(lastRowPosition);
188             }
189
190             // Y
191
192             @Override
193             public int getRowPositionByY(int y) {
194                 return LayerUtil.getRowPositionByY(this, y);
195             }
196
197             @Override
198             public int getStartYOfRowPosition(int localRowPosition) {
199                 int index = this.startYCache.get(localRowPosition);
200                 if (index >= 0)
201                         return index;
202
203                 IUniqueIndexLayer underlyingLayer = (IUniqueIndexLayer) getUnderlyingLayer();
204                 int underlyingPosition = localToUnderlyingRowPosition(localRowPosition);
205                 if (underlyingPosition < 0) {
206                     return -1;
207                 }
208                 int underlyingStartY = underlyingLayer.getStartYOfRowPosition(underlyingPosition);
209                 if (underlyingStartY < 0) {
210                     return -1;
211                 }
212
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);
219                     }
220                 }
221
222                 this.startYCache.put(localRowPosition, underlyingStartY);
223                 return underlyingStartY;
224             }
225
226             // Hide/show
227
228             /**
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.
231              *
232              * @param rowIndex
233              *            The row index of the row whose visibility state should be
234              *            checked.
235              * @return <code>true</code> if the row at the specified index is hidden,
236              *         <code>false</code> if it is visible.
237              */
238             public abstract boolean isRowIndexHidden(int rowIndex);
239
240             /**
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.
245              *
246              * @return Collection of all row indexes that are hidden in this layer.
247              */
248             public abstract Collection<Integer> getHiddenRowIndexes();
249
250             // Cache
251
252             /**
253              * Invalidate the cache to ensure that information is rebuild.
254              */
255             protected void invalidateCache() {
256                 this.cachedVisibleRowIndexOrder = null;
257                 this.cachedVisibleRowPositionOrder = null;
258                 this.cachedHiddenRowIndexToPositionMap = null;
259                 this.startYCache.clear();
260             }
261
262             private Int2IntOpenHashMap getCachedVisibleRowIndexes() {
263                 if (this.cachedVisibleRowIndexOrder == null) {
264                     cacheVisibleRowIndexes();
265                 }
266                 return this.cachedVisibleRowIndexOrder;
267             }
268
269             private Int2IntOpenHashMap getCachedVisibleRowPositons() {
270                 if (this.cachedVisibleRowPositionOrder == null) {
271                     cacheVisibleRowIndexes();
272                 }
273                 return this.cachedVisibleRowPositionOrder;
274             }
275
276             protected void cacheVisibleRowIndexes() {
277                 this.cachedVisibleRowIndexOrder = new Int2IntOpenHashMap();
278                 this.cachedVisibleRowPositionOrder = new Int2IntOpenHashMap();
279                 this.cachedHiddenRowIndexToPositionMap = new Int2IntOpenHashMap();
280                 this.startYCache.clear();
281                 
282                 cachedVisibleRowPositionOrder.defaultReturnValue(-1);
283                 cachedVisibleRowIndexOrder.defaultReturnValue(-1);
284                 cachedHiddenRowIndexToPositionMap.defaultReturnValue(-1);
285                 startYCache.defaultReturnValue(-1);
286
287                 ILayer underlyingLayer = getUnderlyingLayer();
288                 int rowPosition = 0;
289                 for (int parentRowPosition = 0; parentRowPosition < underlyingLayer.getRowCount(); parentRowPosition++) {
290                     int rowIndex = underlyingLayer.getRowIndexByPosition(parentRowPosition);
291
292                     if (!isRowIndexHidden(rowIndex)) {
293                         this.cachedVisibleRowIndexOrder.put(rowIndex, rowPosition);
294                         this.cachedVisibleRowPositionOrder.put(rowPosition, rowIndex);
295                         rowPosition++;
296                     } else {
297                         this.cachedHiddenRowIndexToPositionMap.put(rowIndex, rowPosition);
298                     }
299                 }
300             }
301 }