]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/override/AbstractRowHideShowLayer2.java
Merge "Testing SonarQube with Simantics Platform SDK"
[simantics/platform.git] / bundles / org.simantics.browsing.ui.nattable / src / org / simantics / browsing / ui / nattable / override / AbstractRowHideShowLayer2.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012 Original authors and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  * \r
8  * Contributors:\r
9  *     Original authors and others - initial API and implementation\r
10  ******************************************************************************/\r
11 package org.simantics.browsing.ui.nattable.override;\r
12 \r
13 import java.util.ArrayList;\r
14 import java.util.Collection;\r
15 \r
16 import org.eclipse.nebula.widgets.nattable.coordinate.Range;\r
17 import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform;\r
18 import org.eclipse.nebula.widgets.nattable.layer.ILayer;\r
19 import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;\r
20 import org.eclipse.nebula.widgets.nattable.layer.LayerUtil;\r
21 import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;\r
22 import org.eclipse.nebula.widgets.nattable.layer.event.IStructuralChangeEvent;\r
23 import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent;\r
24 \r
25 import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;\r
26 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;\r
27 \r
28 /**\r
29  * AbstractRowHideShowLayer implementation with FastUtils hashmaps.\r
30  * \r
31  * @see org.eclipse.nebula.widgets.nattable.hideshow.AbstractRowHideShowLayer\r
32  * \r
33  * @author MLMARKO\r
34  *\r
35  */\r
36 public abstract class AbstractRowHideShowLayer2 extends AbstractLayerTransform implements IUniqueIndexLayer {\r
37 \r
38         private Int2IntOpenHashMap cachedVisibleRowIndexOrder;\r
39         private Int2IntOpenHashMap cachedVisibleRowPositionOrder;\r
40         \r
41         private Int2IntOpenHashMap cachedHiddenRowIndexToPositionMap;\r
42 \r
43         protected final Int2IntOpenHashMap startYCache = new Int2IntOpenHashMap();      \r
44         \r
45         \r
46         public AbstractRowHideShowLayer2(IUniqueIndexLayer underlyingLayer) {\r
47                 super(underlyingLayer);\r
48         }\r
49         \r
50          @Override\r
51             public void handleLayerEvent(ILayerEvent event) {\r
52                 if (event instanceof IStructuralChangeEvent) {\r
53                     IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event;\r
54                     if (structuralChangeEvent.isVerticalStructureChanged()) {\r
55                         // vertical structure has changed, update cached row information\r
56                         invalidateCache();\r
57                     }\r
58                 } else if (event instanceof VisualRefreshEvent) {\r
59                     // visual change, e.g. font change, the startYCache needs to be\r
60                     // cleared in order to re-render correctly\r
61                     this.startYCache.clear();\r
62                 }\r
63                 super.handleLayerEvent(event);\r
64             }\r
65 \r
66             // Horizontal features\r
67 \r
68             // Columns\r
69 \r
70             @Override\r
71             public int getColumnPositionByIndex(int columnIndex) {\r
72                 return ((IUniqueIndexLayer) getUnderlyingLayer()).getColumnPositionByIndex(columnIndex);\r
73             }\r
74 \r
75             // Vertical features\r
76 \r
77             // Rows\r
78 \r
79             @Override\r
80             public int getRowCount() {\r
81                 return getCachedVisibleRowIndexes().size();\r
82             }\r
83 \r
84             @Override\r
85             public int getRowIndexByPosition(int rowPosition) {\r
86                 if (rowPosition < 0 || rowPosition >= getRowCount()) {\r
87                     return -1;\r
88                 }\r
89                 return getCachedVisibleRowPositons().get(rowPosition);\r
90             }\r
91 \r
92             @Override\r
93             public int getRowPositionByIndex(int rowIndex) {\r
94                 return getCachedVisibleRowIndexes().get(rowIndex);\r
95             }\r
96 \r
97             public Collection<Integer> getRowPositionsByIndexes(Collection<Integer> rowIndexes) {\r
98                 IntOpenHashSet rowPositions = new IntOpenHashSet();\r
99                 for (int rowIndex : rowIndexes) {\r
100                     rowPositions.add(getRowPositionByIndex(rowIndex));\r
101                 }\r
102                 return rowPositions;\r
103             }\r
104 \r
105             @Override\r
106             public int localToUnderlyingRowPosition(int localRowPosition) {\r
107                 int rowIndex = getRowIndexByPosition(localRowPosition);\r
108                 return ((IUniqueIndexLayer) getUnderlyingLayer()).getRowPositionByIndex(rowIndex);\r
109             }\r
110 \r
111             @Override\r
112             public int underlyingToLocalRowPosition(ILayer sourceUnderlyingLayer, int underlyingRowPosition) {\r
113                 int rowIndex = getUnderlyingLayer().getRowIndexByPosition(underlyingRowPosition);\r
114                 int rowPosition = getRowPositionByIndex(rowIndex);\r
115                 if (rowPosition >= 0) {\r
116                     return rowPosition;\r
117                 } else {\r
118                         if (this.cachedHiddenRowIndexToPositionMap.containsKey(rowIndex)) {\r
119                       return this.cachedHiddenRowIndexToPositionMap.get(rowIndex);\r
120                     } else {\r
121                         return -1;\r
122                     }\r
123                 }\r
124             }\r
125 \r
126             @Override\r
127             public Collection<Range> underlyingToLocalRowPositions(\r
128                     ILayer sourceUnderlyingLayer, Collection<Range> underlyingRowPositionRanges) {\r
129                 Collection<Range> localRowPositionRanges = new ArrayList<Range>();\r
130 \r
131                 for (Range underlyingRowPositionRange : underlyingRowPositionRanges) {\r
132                     int startRowPosition = getAdjustedUnderlyingToLocalStartPosition(\r
133                             sourceUnderlyingLayer,\r
134                             underlyingRowPositionRange.start,\r
135                             underlyingRowPositionRange.end);\r
136                     int endRowPosition = getAdjustedUnderlyingToLocalEndPosition(\r
137                             sourceUnderlyingLayer,\r
138                             underlyingRowPositionRange.end,\r
139                             underlyingRowPositionRange.start);\r
140 \r
141                     // teichstaedt: fixes the problem that ranges where added even if\r
142                     // the corresponding startPosition weren't found in the underlying\r
143                     // layer. Without that fix a bunch of ranges of kind Range [-1, 180]\r
144                     // which causes strange behaviour in Freeze- and other Layers were\r
145                     // returned.\r
146                     if (startRowPosition > -1) {\r
147                         localRowPositionRanges.add(new Range(startRowPosition, endRowPosition));\r
148                     }\r
149                 }\r
150 \r
151                 return localRowPositionRanges;\r
152             }\r
153 \r
154             private int getAdjustedUnderlyingToLocalStartPosition(\r
155                     ILayer sourceUnderlyingLayer,\r
156                     int startUnderlyingPosition,\r
157                     int endUnderlyingPosition) {\r
158                 int localStartRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition);\r
159                 int offset = 0;\r
160                 while (localStartRowPosition < 0\r
161                         && (startUnderlyingPosition + offset < endUnderlyingPosition)) {\r
162                     localStartRowPosition =\r
163                             underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition + offset++);\r
164                 }\r
165                 return localStartRowPosition;\r
166             }\r
167 \r
168             private int getAdjustedUnderlyingToLocalEndPosition(\r
169                     ILayer sourceUnderlyingLayer,\r
170                     int endUnderlyingPosition,\r
171                     int startUnderlyingPosition) {\r
172                 int localEndRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - 1);\r
173                 int offset = 0;\r
174                 while (localEndRowPosition < 0\r
175                         && (endUnderlyingPosition - offset > startUnderlyingPosition)) {\r
176                     localEndRowPosition =\r
177                             underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - offset++);\r
178                 }\r
179                 return localEndRowPosition + 1;\r
180             }\r
181 \r
182             // Height\r
183 \r
184             @Override\r
185             public int getHeight() {\r
186                 int lastRowPosition = getRowCount() - 1;\r
187                 return getStartYOfRowPosition(lastRowPosition) + getRowHeightByPosition(lastRowPosition);\r
188             }\r
189 \r
190             // Y\r
191 \r
192             @Override\r
193             public int getRowPositionByY(int y) {\r
194                 return LayerUtil.getRowPositionByY(this, y);\r
195             }\r
196 \r
197             @Override\r
198             public int getStartYOfRowPosition(int localRowPosition) {\r
199                 int index = this.startYCache.get(localRowPosition);\r
200                 if (index >= 0)\r
201                         return index;\r
202 \r
203                 IUniqueIndexLayer underlyingLayer = (IUniqueIndexLayer) getUnderlyingLayer();\r
204                 int underlyingPosition = localToUnderlyingRowPosition(localRowPosition);\r
205                 if (underlyingPosition < 0) {\r
206                     return -1;\r
207                 }\r
208                 int underlyingStartY = underlyingLayer.getStartYOfRowPosition(underlyingPosition);\r
209                 if (underlyingStartY < 0) {\r
210                     return -1;\r
211                 }\r
212 \r
213                 for (Integer hiddenIndex : getHiddenRowIndexes()) {\r
214                     int hiddenPosition = underlyingLayer.getRowPositionByIndex(hiddenIndex);\r
215                     // if the hidden position is -1, it is hidden in the underlying\r
216                     // layertherefore the underlying layer should handle the positioning\r
217                     if (hiddenPosition >= 0 && hiddenPosition <= underlyingPosition) {\r
218                         underlyingStartY -= underlyingLayer.getRowHeightByPosition(hiddenPosition);\r
219                     }\r
220                 }\r
221 \r
222                 this.startYCache.put(localRowPosition, underlyingStartY);\r
223                 return underlyingStartY;\r
224             }\r
225 \r
226             // Hide/show\r
227 \r
228             /**\r
229              * Will check if the row at the specified index is hidden or not. Checks\r
230              * this layer and also the sublayers for the visibility.\r
231              *\r
232              * @param rowIndex\r
233              *            The row index of the row whose visibility state should be\r
234              *            checked.\r
235              * @return <code>true</code> if the row at the specified index is hidden,\r
236              *         <code>false</code> if it is visible.\r
237              */\r
238             public abstract boolean isRowIndexHidden(int rowIndex);\r
239 \r
240             /**\r
241              * Will collect and return all indexes of the rows that are hidden in this\r
242              * layer. Note: It is not intended that it also collects the row indexes of\r
243              * underlying layers. This would cause issues on calculating positions as\r
244              * every layer is responsible for those calculations itself.\r
245              *\r
246              * @return Collection of all row indexes that are hidden in this layer.\r
247              */\r
248             public abstract Collection<Integer> getHiddenRowIndexes();\r
249 \r
250             // Cache\r
251 \r
252             /**\r
253              * Invalidate the cache to ensure that information is rebuild.\r
254              */\r
255             protected void invalidateCache() {\r
256                 this.cachedVisibleRowIndexOrder = null;\r
257                 this.cachedVisibleRowPositionOrder = null;\r
258                 this.cachedHiddenRowIndexToPositionMap = null;\r
259                 this.startYCache.clear();\r
260             }\r
261 \r
262             private Int2IntOpenHashMap getCachedVisibleRowIndexes() {\r
263                 if (this.cachedVisibleRowIndexOrder == null) {\r
264                     cacheVisibleRowIndexes();\r
265                 }\r
266                 return this.cachedVisibleRowIndexOrder;\r
267             }\r
268 \r
269             private Int2IntOpenHashMap getCachedVisibleRowPositons() {\r
270                 if (this.cachedVisibleRowPositionOrder == null) {\r
271                     cacheVisibleRowIndexes();\r
272                 }\r
273                 return this.cachedVisibleRowPositionOrder;\r
274             }\r
275 \r
276             protected void cacheVisibleRowIndexes() {\r
277                 this.cachedVisibleRowIndexOrder = new Int2IntOpenHashMap();\r
278                 this.cachedVisibleRowPositionOrder = new Int2IntOpenHashMap();\r
279                 this.cachedHiddenRowIndexToPositionMap = new Int2IntOpenHashMap();\r
280                 this.startYCache.clear();\r
281                 \r
282                 cachedVisibleRowPositionOrder.defaultReturnValue(-1);\r
283                 cachedVisibleRowIndexOrder.defaultReturnValue(-1);\r
284                 cachedHiddenRowIndexToPositionMap.defaultReturnValue(-1);\r
285                 startYCache.defaultReturnValue(-1);\r
286 \r
287                 ILayer underlyingLayer = getUnderlyingLayer();\r
288                 int rowPosition = 0;\r
289                 for (int parentRowPosition = 0; parentRowPosition < underlyingLayer.getRowCount(); parentRowPosition++) {\r
290                     int rowIndex = underlyingLayer.getRowIndexByPosition(parentRowPosition);\r
291 \r
292                     if (!isRowIndexHidden(rowIndex)) {\r
293                         this.cachedVisibleRowIndexOrder.put(rowIndex, rowPosition);\r
294                         this.cachedVisibleRowPositionOrder.put(rowPosition, rowIndex);\r
295                         rowPosition++;\r
296                     } else {\r
297                         this.cachedHiddenRowIndexToPositionMap.put(rowIndex, rowPosition);\r
298                     }\r
299                 }\r
300             }\r
301 }\r