| /******************************************************************************* |
| * Copyright (c) 2012, 2020 Original authors and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Original authors and others - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.hideshow; |
| |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Properties; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.collections.api.list.primitive.MutableIntList; |
| import org.eclipse.collections.api.set.primitive.MutableIntSet; |
| import org.eclipse.collections.impl.factory.primitive.IntLists; |
| import org.eclipse.collections.impl.factory.primitive.IntSets; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.ColumnHideCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.ColumnShowCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.HideColumnByIndexCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.MultiColumnHideCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.MultiColumnShowCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.command.ShowAllColumnsCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.hideshow.event.HideColumnPositionsEvent; |
| import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowColumnPositionsEvent; |
| import org.eclipse.nebula.widgets.nattable.hideshow.indicator.HideIndicatorConstants; |
| import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer; |
| import org.eclipse.nebula.widgets.nattable.layer.LabelStack; |
| 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.StructuralChangeEventHelper; |
| import org.eclipse.nebula.widgets.nattable.layer.event.StructuralDiff; |
| import org.eclipse.nebula.widgets.nattable.persistence.IPersistable; |
| import org.eclipse.nebula.widgets.nattable.util.ArrayUtil; |
| |
| /** |
| * Layer to add support for column hide/show feature to a NatTable. Technically |
| * the columns are hidden by this layer which leads to a index-position |
| * transformation. With percentage sizing this this leads to gaps for hidden |
| * columns as the size of the other columns is not re-calculated. For percentage |
| * sizing and size increase use the {@link ResizeColumnHideShowLayer}. |
| * |
| * @see ResizeColumnHideShowLayer |
| */ |
| public class ColumnHideShowLayer extends AbstractColumnHideShowLayer implements IColumnHideShowLayer { |
| |
| public static final String PERSISTENCE_KEY_HIDDEN_COLUMN_INDEXES = ".hiddenColumnIndexes"; //$NON-NLS-1$ |
| |
| private MutableIntSet hiddenColumnIndexes = IntSets.mutable.empty(); |
| |
| public ColumnHideShowLayer(IUniqueIndexLayer underlyingLayer) { |
| super(underlyingLayer); |
| |
| registerCommandHandler(new MultiColumnHideCommandHandler(this)); |
| registerCommandHandler(new ColumnHideCommandHandler(this)); |
| registerCommandHandler(new ShowAllColumnsCommandHandler(this)); |
| registerCommandHandler(new MultiColumnShowCommandHandler(this)); |
| registerCommandHandler(new ColumnShowCommandHandler(this)); |
| registerCommandHandler(new HideColumnByIndexCommandHandler(this)); |
| } |
| |
| @Override |
| public void handleLayerEvent(ILayerEvent event) { |
| if (event instanceof IStructuralChangeEvent) { |
| IStructuralChangeEvent structuralChangeEvent = (IStructuralChangeEvent) event; |
| if (structuralChangeEvent.isHorizontalStructureChanged()) { |
| Collection<StructuralDiff> columnDiffs = structuralChangeEvent.getColumnDiffs(); |
| |
| if (columnDiffs != null && !columnDiffs.isEmpty() |
| && !StructuralChangeEventHelper.isReorder(columnDiffs)) { |
| StructuralChangeEventHelper.handleColumnDelete( |
| columnDiffs, |
| this.underlyingLayer, |
| this.hiddenColumnIndexes, |
| false); |
| StructuralChangeEventHelper.handleColumnInsert( |
| columnDiffs, |
| this.underlyingLayer, |
| this.hiddenColumnIndexes, |
| false); |
| } |
| } |
| } |
| super.handleLayerEvent(event); |
| } |
| |
| // Persistence |
| |
| @Override |
| public void saveState(String prefix, Properties properties) { |
| if (this.hiddenColumnIndexes.size() > 0) { |
| properties.setProperty( |
| prefix + PERSISTENCE_KEY_HIDDEN_COLUMN_INDEXES, |
| this.hiddenColumnIndexes.toSortedList().makeString(IPersistable.VALUE_SEPARATOR)); |
| } else { |
| properties.remove(prefix + PERSISTENCE_KEY_HIDDEN_COLUMN_INDEXES); |
| } |
| |
| super.saveState(prefix, properties); |
| } |
| |
| @Override |
| public void loadState(String prefix, Properties properties) { |
| // Bug 396925: always clear the state of the hidden columns, whether |
| // there is a state saved or not |
| this.hiddenColumnIndexes = IntSets.mutable.empty(); |
| String property = properties.getProperty(prefix + PERSISTENCE_KEY_HIDDEN_COLUMN_INDEXES); |
| if (property != null) { |
| StringTokenizer tok = new StringTokenizer(property, IPersistable.VALUE_SEPARATOR); |
| while (tok.hasMoreTokens()) { |
| String index = tok.nextToken(); |
| this.hiddenColumnIndexes.add(Integer.parseInt(index)); |
| } |
| } |
| |
| super.loadState(prefix, properties); |
| } |
| |
| @Override |
| public LabelStack getConfigLabelsByPosition(int columnPosition, int rowPosition) { |
| LabelStack configLabels = super.getConfigLabelsByPosition(columnPosition, rowPosition); |
| |
| // we need to check the hidden state of an adjacent position via the |
| // underlying layer as in the hide layer the position might be |
| // hidden |
| int underlyingPosition = localToUnderlyingColumnPosition(columnPosition); |
| int leftColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition - 1); |
| if (isColumnIndexHidden(leftColumnIndex)) { |
| configLabels.addLabel(HideIndicatorConstants.COLUMN_LEFT_HIDDEN); |
| } |
| |
| int rightColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition + 1); |
| if (isColumnIndexHidden(rightColumnIndex)) { |
| configLabels.addLabel(HideIndicatorConstants.COLUMN_RIGHT_HIDDEN); |
| } |
| |
| return configLabels; |
| } |
| |
| // Hide/show |
| |
| @Override |
| public boolean isColumnIndexHidden(int columnIndex) { |
| return this.hiddenColumnIndexes.contains(columnIndex); |
| } |
| |
| @Override |
| public Collection<Integer> getHiddenColumnIndexes() { |
| return ArrayUtil.asIntegerList(this.hiddenColumnIndexes.toSortedArray()); |
| } |
| |
| @Override |
| public int[] getHiddenColumnIndexesArray() { |
| return this.hiddenColumnIndexes.toSortedArray(); |
| } |
| |
| @Override |
| public boolean hasHiddenColumns() { |
| return !this.hiddenColumnIndexes.isEmpty(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @since 1.6 |
| */ |
| @Override |
| public void hideColumnPositions(int... columnPositions) { |
| int[] columnIndexes = Arrays.stream(columnPositions) |
| .map(this::getColumnIndexByPosition) |
| .sorted() |
| .toArray(); |
| this.hiddenColumnIndexes.addAll(columnIndexes); |
| invalidateCache(); |
| fireLayerEvent(new HideColumnPositionsEvent(this, columnPositions, columnIndexes)); |
| } |
| |
| @Override |
| public void hideColumnPositions(Collection<Integer> columnPositions) { |
| hideColumnPositions(columnPositions.stream().mapToInt(Integer::intValue).toArray()); |
| } |
| |
| @Override |
| public void hideColumnIndexes(int... columnIndexes) { |
| int[] columnPositions = Arrays.stream(columnIndexes) |
| .map(this::getColumnPositionByIndex) |
| .sorted() |
| .toArray(); |
| this.hiddenColumnIndexes.addAll(columnIndexes); |
| invalidateCache(); |
| fireLayerEvent(new HideColumnPositionsEvent(this, columnPositions, columnIndexes)); |
| } |
| |
| @Override |
| public void hideColumnIndexes(Collection<Integer> columnIndexes) { |
| hideColumnIndexes(columnIndexes.stream().mapToInt(Integer::intValue).toArray()); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @since 1.6 |
| */ |
| @Override |
| public void showColumnIndexes(int... columnIndexes) { |
| MutableIntList toProcess = IntLists.mutable.of(columnIndexes); |
| |
| // only handle column indexes that are hidden |
| toProcess.retainAll(this.hiddenColumnIndexes); |
| |
| this.hiddenColumnIndexes.removeAll(toProcess); |
| invalidateCache(); |
| int[] positions = getColumnPositionsByIndexes(toProcess.toArray()); |
| fireLayerEvent(new ShowColumnPositionsEvent(this, positions)); |
| } |
| |
| @Override |
| public void showColumnIndexes(Collection<Integer> columnIndexes) { |
| showColumnIndexes(columnIndexes.stream().mapToInt(Integer::intValue).toArray()); |
| } |
| |
| @Override |
| public void showColumnPosition(int columnPosition, boolean showToLeft, boolean showAll) { |
| MutableIntSet columnIndexes = IntSets.mutable.empty(); |
| int underlyingPosition = localToUnderlyingColumnPosition(columnPosition); |
| if (showToLeft) { |
| int leftColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition - 1); |
| if (showAll) { |
| int move = 1; |
| while (isColumnIndexHidden(leftColumnIndex)) { |
| columnIndexes.add(leftColumnIndex); |
| move++; |
| leftColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition - move); |
| } |
| } else if (isColumnIndexHidden(leftColumnIndex)) { |
| columnIndexes.add(leftColumnIndex); |
| } |
| } else { |
| int rightColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition + 1); |
| if (showAll) { |
| int move = 1; |
| while (isColumnIndexHidden(rightColumnIndex)) { |
| columnIndexes.add(rightColumnIndex); |
| move++; |
| rightColumnIndex = this.underlyingLayer.getColumnIndexByPosition(underlyingPosition + move); |
| } |
| } else if (isColumnIndexHidden(rightColumnIndex)) { |
| columnIndexes.add(rightColumnIndex); |
| } |
| } |
| |
| if (!columnIndexes.isEmpty()) { |
| showColumnIndexes(columnIndexes.toArray()); |
| } |
| } |
| |
| @Override |
| public void showAllColumns() { |
| int[] hidden = this.hiddenColumnIndexes.toSortedArray(); |
| this.hiddenColumnIndexes = IntSets.mutable.empty(); |
| invalidateCache(); |
| fireLayerEvent(new ShowColumnPositionsEvent(this, getColumnPositionsByIndexes(hidden))); |
| } |
| |
| @Override |
| public Collection<String> getProvidedLabels() { |
| Collection<String> result = super.getProvidedLabels(); |
| result.add(HideIndicatorConstants.COLUMN_LEFT_HIDDEN); |
| result.add(HideIndicatorConstants.COLUMN_RIGHT_HIDDEN); |
| return result; |
| } |
| } |