X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.nattable%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fnattable%2Foverride%2FAbstractRowHideShowLayer2.java;fp=bundles%2Forg.simantics.browsing.ui.nattable%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fnattable%2Foverride%2FAbstractRowHideShowLayer2.java;h=44f4b7c15375ab5433f417c62174cd9b4d8475da;hb=96bb7ef9cbe42d82eb58306d8f9b62392cc29ba8;hp=0000000000000000000000000000000000000000;hpb=ae5bb63c5c88f6569518fed2a24df86fbd0570ff;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/override/AbstractRowHideShowLayer2.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/override/AbstractRowHideShowLayer2.java new file mode 100644 index 000000000..44f4b7c15 --- /dev/null +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/override/AbstractRowHideShowLayer2.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * Copyright (c) 2012 Original authors and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Original authors and others - initial API and implementation + ******************************************************************************/ +package org.simantics.browsing.ui.nattable.override; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.nebula.widgets.nattable.coordinate.Range; +import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer; +import org.eclipse.nebula.widgets.nattable.layer.LayerUtil; +import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent; +import org.eclipse.nebula.widgets.nattable.layer.event.IStructuralChangeEvent; +import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent; + +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; + +/** + * AbstractRowHideShowLayer implementation with FastUtils hashmaps. + * + * @see org.eclipse.nebula.widgets.nattable.hideshow.AbstractRowHideShowLayer + * + * @author MLMARKO + * + */ +public abstract class AbstractRowHideShowLayer2 extends AbstractLayerTransform implements IUniqueIndexLayer { + + private Int2IntOpenHashMap cachedVisibleRowIndexOrder; + private Int2IntOpenHashMap cachedVisibleRowPositionOrder; + + private Int2IntOpenHashMap cachedHiddenRowIndexToPositionMap; + + protected final Int2IntOpenHashMap startYCache = new Int2IntOpenHashMap(); + + + public AbstractRowHideShowLayer2(IUniqueIndexLayer underlyingLayer) { + super(underlyingLayer); + } + + @Override + public void handleLayerEvent(ILayerEvent event) { + if (event instanceof IStructuralChangeEvent) { + IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event; + if (structuralChangeEvent.isVerticalStructureChanged()) { + // vertical structure has changed, update cached row information + invalidateCache(); + } + } else if (event instanceof VisualRefreshEvent) { + // visual change, e.g. font change, the startYCache needs to be + // cleared in order to re-render correctly + this.startYCache.clear(); + } + super.handleLayerEvent(event); + } + + // Horizontal features + + // Columns + + @Override + public int getColumnPositionByIndex(int columnIndex) { + return ((IUniqueIndexLayer) getUnderlyingLayer()).getColumnPositionByIndex(columnIndex); + } + + // Vertical features + + // Rows + + @Override + public int getRowCount() { + return getCachedVisibleRowIndexes().size(); + } + + @Override + public int getRowIndexByPosition(int rowPosition) { + if (rowPosition < 0 || rowPosition >= getRowCount()) { + return -1; + } + return getCachedVisibleRowPositons().get(rowPosition); + } + + @Override + public int getRowPositionByIndex(int rowIndex) { + return getCachedVisibleRowIndexes().get(rowIndex); + } + + public Collection getRowPositionsByIndexes(Collection rowIndexes) { + IntOpenHashSet rowPositions = new IntOpenHashSet(); + for (int rowIndex : rowIndexes) { + rowPositions.add(getRowPositionByIndex(rowIndex)); + } + return rowPositions; + } + + @Override + public int localToUnderlyingRowPosition(int localRowPosition) { + int rowIndex = getRowIndexByPosition(localRowPosition); + return ((IUniqueIndexLayer) getUnderlyingLayer()).getRowPositionByIndex(rowIndex); + } + + @Override + public int underlyingToLocalRowPosition(ILayer sourceUnderlyingLayer, int underlyingRowPosition) { + int rowIndex = getUnderlyingLayer().getRowIndexByPosition(underlyingRowPosition); + int rowPosition = getRowPositionByIndex(rowIndex); + if (rowPosition >= 0) { + return rowPosition; + } else { + if (this.cachedHiddenRowIndexToPositionMap.containsKey(rowIndex)) { + return this.cachedHiddenRowIndexToPositionMap.get(rowIndex); + } else { + return -1; + } + } + } + + @Override + public Collection underlyingToLocalRowPositions( + ILayer sourceUnderlyingLayer, Collection underlyingRowPositionRanges) { + Collection localRowPositionRanges = new ArrayList(); + + for (Range underlyingRowPositionRange : underlyingRowPositionRanges) { + int startRowPosition = getAdjustedUnderlyingToLocalStartPosition( + sourceUnderlyingLayer, + underlyingRowPositionRange.start, + underlyingRowPositionRange.end); + int endRowPosition = getAdjustedUnderlyingToLocalEndPosition( + sourceUnderlyingLayer, + underlyingRowPositionRange.end, + underlyingRowPositionRange.start); + + // teichstaedt: fixes the problem that ranges where added even if + // the corresponding startPosition weren't found in the underlying + // layer. Without that fix a bunch of ranges of kind Range [-1, 180] + // which causes strange behaviour in Freeze- and other Layers were + // returned. + if (startRowPosition > -1) { + localRowPositionRanges.add(new Range(startRowPosition, endRowPosition)); + } + } + + return localRowPositionRanges; + } + + private int getAdjustedUnderlyingToLocalStartPosition( + ILayer sourceUnderlyingLayer, + int startUnderlyingPosition, + int endUnderlyingPosition) { + int localStartRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition); + int offset = 0; + while (localStartRowPosition < 0 + && (startUnderlyingPosition + offset < endUnderlyingPosition)) { + localStartRowPosition = + underlyingToLocalRowPosition(sourceUnderlyingLayer, startUnderlyingPosition + offset++); + } + return localStartRowPosition; + } + + private int getAdjustedUnderlyingToLocalEndPosition( + ILayer sourceUnderlyingLayer, + int endUnderlyingPosition, + int startUnderlyingPosition) { + int localEndRowPosition = underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - 1); + int offset = 0; + while (localEndRowPosition < 0 + && (endUnderlyingPosition - offset > startUnderlyingPosition)) { + localEndRowPosition = + underlyingToLocalRowPosition(sourceUnderlyingLayer, endUnderlyingPosition - offset++); + } + return localEndRowPosition + 1; + } + + // Height + + @Override + public int getHeight() { + int lastRowPosition = getRowCount() - 1; + return getStartYOfRowPosition(lastRowPosition) + getRowHeightByPosition(lastRowPosition); + } + + // Y + + @Override + public int getRowPositionByY(int y) { + return LayerUtil.getRowPositionByY(this, y); + } + + @Override + public int getStartYOfRowPosition(int localRowPosition) { + int index = this.startYCache.get(localRowPosition); + if (index >= 0) + return index; + + IUniqueIndexLayer underlyingLayer = (IUniqueIndexLayer) getUnderlyingLayer(); + int underlyingPosition = localToUnderlyingRowPosition(localRowPosition); + if (underlyingPosition < 0) { + return -1; + } + int underlyingStartY = underlyingLayer.getStartYOfRowPosition(underlyingPosition); + if (underlyingStartY < 0) { + return -1; + } + + for (Integer hiddenIndex : getHiddenRowIndexes()) { + int hiddenPosition = underlyingLayer.getRowPositionByIndex(hiddenIndex); + // if the hidden position is -1, it is hidden in the underlying + // layertherefore the underlying layer should handle the positioning + if (hiddenPosition >= 0 && hiddenPosition <= underlyingPosition) { + underlyingStartY -= underlyingLayer.getRowHeightByPosition(hiddenPosition); + } + } + + this.startYCache.put(localRowPosition, underlyingStartY); + return underlyingStartY; + } + + // Hide/show + + /** + * Will check if the row at the specified index is hidden or not. Checks + * this layer and also the sublayers for the visibility. + * + * @param rowIndex + * The row index of the row whose visibility state should be + * checked. + * @return true if the row at the specified index is hidden, + * false if it is visible. + */ + public abstract boolean isRowIndexHidden(int rowIndex); + + /** + * Will collect and return all indexes of the rows that are hidden in this + * layer. Note: It is not intended that it also collects the row indexes of + * underlying layers. This would cause issues on calculating positions as + * every layer is responsible for those calculations itself. + * + * @return Collection of all row indexes that are hidden in this layer. + */ + public abstract Collection getHiddenRowIndexes(); + + // Cache + + /** + * Invalidate the cache to ensure that information is rebuild. + */ + protected void invalidateCache() { + this.cachedVisibleRowIndexOrder = null; + this.cachedVisibleRowPositionOrder = null; + this.cachedHiddenRowIndexToPositionMap = null; + this.startYCache.clear(); + } + + private Int2IntOpenHashMap getCachedVisibleRowIndexes() { + if (this.cachedVisibleRowIndexOrder == null) { + cacheVisibleRowIndexes(); + } + return this.cachedVisibleRowIndexOrder; + } + + private Int2IntOpenHashMap getCachedVisibleRowPositons() { + if (this.cachedVisibleRowPositionOrder == null) { + cacheVisibleRowIndexes(); + } + return this.cachedVisibleRowPositionOrder; + } + + protected void cacheVisibleRowIndexes() { + this.cachedVisibleRowIndexOrder = new Int2IntOpenHashMap(); + this.cachedVisibleRowPositionOrder = new Int2IntOpenHashMap(); + this.cachedHiddenRowIndexToPositionMap = new Int2IntOpenHashMap(); + this.startYCache.clear(); + + cachedVisibleRowPositionOrder.defaultReturnValue(-1); + cachedVisibleRowIndexOrder.defaultReturnValue(-1); + cachedHiddenRowIndexToPositionMap.defaultReturnValue(-1); + startYCache.defaultReturnValue(-1); + + ILayer underlyingLayer = getUnderlyingLayer(); + int rowPosition = 0; + for (int parentRowPosition = 0; parentRowPosition < underlyingLayer.getRowCount(); parentRowPosition++) { + int rowIndex = underlyingLayer.getRowIndexByPosition(parentRowPosition); + + if (!isRowIndexHidden(rowIndex)) { + this.cachedVisibleRowIndexOrder.put(rowIndex, rowPosition); + this.cachedVisibleRowPositionOrder.put(rowPosition, rowIndex); + rowPosition++; + } else { + this.cachedHiddenRowIndexToPositionMap.put(rowIndex, rowPosition); + } + } + } +}