blob: 441c2f2f78cd02f8dc39799973abb3d95b54af17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019, 2020 Dirk Fauth.
* 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:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.group.performance;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.primitive.MutableIntList;
import org.eclipse.collections.api.map.MutableMap;
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.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.group.performance.GroupModel.Group;
import org.eclipse.nebula.widgets.nattable.group.performance.command.ColumnGroupCollapseCommand;
import org.eclipse.nebula.widgets.nattable.group.performance.command.ColumnGroupExpandCommand;
import org.eclipse.nebula.widgets.nattable.group.performance.command.UpdateColumnGroupCollapseCommand;
import org.eclipse.nebula.widgets.nattable.hideshow.AbstractColumnHideShowLayer;
import org.eclipse.nebula.widgets.nattable.hideshow.event.HideColumnPositionsEvent;
import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowColumnPositionsEvent;
import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent;
import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
/**
* Layer that is used in combination with the performance
* {@link ColumnGroupHeaderLayer} to support expand/collapse of column groups.
*
* @since 1.6
*/
public class ColumnGroupExpandCollapseLayer extends AbstractColumnHideShowLayer {
private final MutableMap<Group, MutableIntSet> hidden = Maps.mutable.empty();
public ColumnGroupExpandCollapseLayer(IUniqueIndexLayer underlyingLayer) {
super(underlyingLayer);
}
@Override
public boolean doCommand(ILayerCommand command) {
if (command instanceof ColumnGroupExpandCommand) {
List<Group> groups = ((ColumnGroupExpandCommand) command).getGroups();
MutableIntSet shownIndexes = IntSets.mutable.empty();
for (Group group : groups) {
// if group is not collapseable return without any further
// operation
if (group == null || !group.isCollapseable()) {
continue;
}
if (group.isCollapsed()) {
group.setCollapsed(false);
MutableIntSet columnIndexes = this.hidden.get(group);
this.hidden.remove(group);
shownIndexes.addAll(columnIndexes);
}
}
if (!shownIndexes.isEmpty()) {
invalidateCache();
fireLayerEvent(new ShowColumnPositionsEvent(this, getColumnPositionsByIndexes(shownIndexes.toArray())));
} else {
fireLayerEvent(new VisualRefreshEvent(this));
}
return true;
} else if (command instanceof ColumnGroupCollapseCommand) {
GroupModel groupModel = ((ColumnGroupCollapseCommand) command).getGroupModel();
List<Group> groups = ((ColumnGroupCollapseCommand) command).getGroups();
Collections.sort(groups, (Group o1, Group o2) -> {
return o2.getVisibleStartPosition() - o1.getVisibleStartPosition();
});
MutableIntSet hiddenPositions = IntSets.mutable.empty();
MutableIntSet hiddenIndexes = IntSets.mutable.empty();
for (Group group : groups) {
// if group is not collapseable return without any further
// operation
if (group == null || !group.isCollapseable()) {
continue;
}
MutableIntSet columnIndexes = IntSets.mutable.empty();
if (!group.isCollapsed()) {
columnIndexes.addAll(group.getVisibleIndexes());
group.setCollapsed(true);
} else if (!this.hidden.containsKey(group)) {
for (int member : group.getMembers()) {
int pos = groupModel.getPositionByIndex(member);
if (pos > -1) {
columnIndexes.add(pos);
}
}
}
modifyForVisible(group, columnIndexes);
this.hidden.put(group, columnIndexes);
hiddenPositions.addAll(getColumnPositionsByIndexes(columnIndexes.toArray()));
hiddenIndexes.addAll(columnIndexes);
}
if (!hiddenPositions.isEmpty()) {
invalidateCache();
fireLayerEvent(new HideColumnPositionsEvent(this, hiddenPositions.toArray(), hiddenIndexes.toArray()));
} else {
fireLayerEvent(new VisualRefreshEvent(this));
}
return true;
} else if (command instanceof UpdateColumnGroupCollapseCommand) {
UpdateColumnGroupCollapseCommand cmd = (UpdateColumnGroupCollapseCommand) command;
Group group = cmd.getGroup();
MutableIntSet hiddenColumnIndexes = this.hidden.get(group);
if (group.getVisibleIndexes().length + hiddenColumnIndexes.size() <= group.getOriginalSpan()) {
MutableIntSet indexesToHide = IntSets.mutable.of(cmd.getIndexesToHide());
MutableIntSet indexesToShow = IntSets.mutable.of(cmd.getIndexesToShow());
// remove already hidden indexes
indexesToHide.removeAll(hiddenColumnIndexes);
// remove static indexes
modifyForVisible(group, indexesToHide);
int[] hiddenPositions = getColumnPositionsByIndexes(indexesToHide.toArray());
hiddenColumnIndexes.addAll(indexesToHide);
hiddenColumnIndexes.removeAll(indexesToShow);
invalidateCache();
fireLayerEvent(new HideColumnPositionsEvent(this, hiddenPositions, indexesToHide.toArray()));
}
return true;
}
return super.doCommand(command);
}
/**
* Ensure that a group is never hidden completely via collapse operations.
* Removes either the configured static indexes of the group or the first
* visible column in a group from the given collection of indexes for this.
*
* @param group
* The group to check.
* @param columnIndexes
* The collection of indexes that should be hidden.
*/
private void modifyForVisible(Group group, MutableIntSet columnIndexes) {
int[] staticIndexes = group.getStaticIndexes();
if (staticIndexes.length == 0) {
// keep the first column
columnIndexes.remove(group.getVisibleStartIndex());
} else {
// do not hide static indexes
columnIndexes.removeAll(staticIndexes);
}
}
@Override
public boolean isColumnIndexHidden(int columnIndex) {
MutableIntSet found = this.hidden.detect(indexes -> indexes.contains(columnIndex));
return found != null;
}
@Override
public Collection<Integer> getHiddenColumnIndexes() {
MutableIntList hiddenColumnIndexes = IntLists.mutable.empty();
for (MutableIntSet indexes : this.hidden.values()) {
hiddenColumnIndexes.addAll(indexes);
}
return ArrayUtil.asIntegerList(hiddenColumnIndexes.distinct().toSortedArray());
}
@Override
public int[] getHiddenColumnIndexesArray() {
MutableIntList hiddenColumnIndexes = IntLists.mutable.empty();
for (MutableIntSet indexes : this.hidden.values()) {
hiddenColumnIndexes.addAll(indexes);
}
return hiddenColumnIndexes.distinct().toSortedArray();
}
@Override
public boolean hasHiddenColumns() {
return !this.hidden.isEmpty();
}
}