blob: 393a59fcadf24b086d651ccb8a9c65c112db9300 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019, 2020 Dirk Fauth.
*
* 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:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.group.performance.command;
import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler;
import org.eclipse.nebula.widgets.nattable.coordinate.PositionUtil;
import org.eclipse.nebula.widgets.nattable.group.ColumnGroupUtils;
import org.eclipse.nebula.widgets.nattable.group.performance.ColumnGroupHeaderLayer;
import org.eclipse.nebula.widgets.nattable.group.performance.GroupModel.Group;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
import org.eclipse.nebula.widgets.nattable.reorder.command.ColumnReorderEndCommand;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
/**
* Command handler for the {@link ColumnReorderEndCommand} that is registered on
* the positionLayer of the {@link ColumnGroupHeaderLayer} to avoid handling in
* case the reordering would break an unbreakable group.
*
* @since 1.6
*/
public class GroupColumnReorderEndCommandHandler extends AbstractLayerCommandHandler<ColumnReorderEndCommand> {
private final ColumnGroupHeaderLayer columnGroupHeaderLayer;
public GroupColumnReorderEndCommandHandler(ColumnGroupHeaderLayer columnGroupHeaderLayer) {
this.columnGroupHeaderLayer = columnGroupHeaderLayer;
}
@Override
protected boolean doCommand(ColumnReorderEndCommand command) {
int fromColumnPosition = this.columnGroupHeaderLayer.getReorderFromColumnPosition();
int toColumnPosition = command.getToColumnPosition();
boolean reorderToLeftEdge = command.isReorderToLeftEdge();
boolean isValid = ColumnGroupUtils.isReorderValid(this.columnGroupHeaderLayer, fromColumnPosition, toColumnPosition, reorderToLeftEdge);
// only if we visibly reorder we need to check the collapsed state and
// expand in order to update the GroupModel correctly
if (isValid) {
// as we are registered on the positionLayer, there is no need
// for transformation
int fromIndex = this.columnGroupHeaderLayer.getPositionLayer().getColumnIndexByPosition(fromColumnPosition);
int toIndex = this.columnGroupHeaderLayer.getPositionLayer().getColumnIndexByPosition(toColumnPosition);
MoveDirectionEnum moveDirection = PositionUtil.getHorizontalMoveDirection(fromColumnPosition, toColumnPosition);
int fromPositionToCheck = fromColumnPosition;
int toPositionToCheck = toColumnPosition;
if (MoveDirectionEnum.RIGHT == moveDirection && reorderToLeftEdge) {
toPositionToCheck--;
}
boolean toggleCoordinateByEdge = false;
Group groupToEnd = null;
Group groupToStart = null;
for (int level = 0; level < this.columnGroupHeaderLayer.getLevelCount(); level++) {
Group fromGroup = this.columnGroupHeaderLayer.getGroupByPosition(level, fromPositionToCheck);
Group toGroup = this.columnGroupHeaderLayer.getGroupByPosition(level, toPositionToCheck);
if (fromGroup != null
&& fromGroup.isCollapsed()
&& (!ColumnGroupUtils.isInTheSameGroup(this.columnGroupHeaderLayer, level, fromPositionToCheck, toPositionToCheck)
|| fromPositionToCheck == toPositionToCheck)) {
// if we are not reordering inside a collapsed group we need
// to expand first to ensure consistency of the GroupModel
this.columnGroupHeaderLayer.expandGroup(this.columnGroupHeaderLayer.getGroupModel(level), fromGroup);
// we update the toColumnPosition because we expanded a
// group
if (moveDirection != MoveDirectionEnum.RIGHT) {
fromPositionToCheck = this.columnGroupHeaderLayer.getPositionLayer().getColumnPositionByIndex(fromIndex);
this.columnGroupHeaderLayer.setReorderFromColumnPosition(fromPositionToCheck);
} else {
toPositionToCheck = this.columnGroupHeaderLayer.getPositionLayer().getColumnPositionByIndex(toIndex);
command.updateToColumnPosition(toPositionToCheck);
if (MoveDirectionEnum.RIGHT == moveDirection && reorderToLeftEdge) {
toPositionToCheck--;
}
}
}
if (toGroup != null
&& MoveDirectionEnum.RIGHT == moveDirection
&& toGroup.isGroupEnd(toPositionToCheck)) {
toggleCoordinateByEdge = true;
if (toGroup.isUnbreakable() && toGroup.getVisibleSpan() < toGroup.getOriginalSpan()) {
groupToEnd = toGroup;
}
} else if (toGroup != null
&& MoveDirectionEnum.LEFT == moveDirection
&& toGroup.isGroupStart(toPositionToCheck)
&& toGroup.isUnbreakable()
&& toGroup.getVisibleSpan() < toGroup.getOriginalSpan()) {
groupToStart = toGroup;
}
}
if (toggleCoordinateByEdge) {
command.toggleCoordinateByEdge();
}
if (groupToEnd != null) {
// if the group is unbreakable and the visible span is
// smaller than the original span, it could be that
// positions at the end are hidden and the reorder to
// the right edge could lead to a broken group
return this.columnGroupHeaderLayer.getPositionLayer().getUnderlyingLayerByPosition(0, 0).doCommand(
new ColumnReorderEndToGroupEndCommand(command, groupToEnd));
} else if (groupToStart != null) {
// if the group is unbreakable and the visible span is
// smaller than the original span, it could be that
// positions at the start are hidden and the reorder to
// the left edge could lead to a broken group
return this.columnGroupHeaderLayer.getPositionLayer().getUnderlyingLayerByPosition(0, 0).doCommand(
new ColumnReorderEndToGroupStartCommand(command, groupToStart));
}
}
// return false means process further and do not consume
return !isValid;
}
@Override
public Class<ColumnReorderEndCommand> getCommandClass() {
return ColumnReorderEndCommand.class;
}
/**
* Specialization of the {@link ColumnReorderEndCommand} to be able to
* reorder a column to the start of a {@link Group} even the first columns
* in the {@link Group} are hidden.
*
* @since 2.0
*/
class ColumnReorderEndToGroupStartCommand extends ColumnReorderEndCommand {
private final Group group;
public ColumnReorderEndToGroupStartCommand(ColumnReorderEndCommand command, Group group) {
super(command);
this.group = group;
}
/**
* Clone constructor.
*
* @param command
* The command to clone.
*/
protected ColumnReorderEndToGroupStartCommand(ColumnReorderEndToGroupStartCommand command) {
super(command);
this.group = command.group;
}
@Override
public boolean convertToTargetLayer(ILayer targetLayer) {
boolean convert = super.convertToTargetLayer(targetLayer);
// check if there are positions for the group members that would be
// more to the left. this could happen e.g. if columns at the group
// start are hidden
if (convert && isReorderToLeftEdge() && targetLayer instanceof IUniqueIndexLayer) {
int groupStartPosition = ((IUniqueIndexLayer) targetLayer).getColumnPositionByIndex(this.group.getStartIndex());
if (groupStartPosition >= 0 && groupStartPosition < getToColumnPosition()) {
updateToColumnPosition(groupStartPosition);
}
}
return convert;
}
@Override
public ColumnReorderEndToGroupStartCommand cloneCommand() {
return new ColumnReorderEndToGroupStartCommand(this);
}
}
/**
* Specialization of the {@link ColumnReorderEndCommand} to be able to
* reorder a column to the end of a {@link Group} even the last columns in
* the {@link Group} are hidden.
*
* @since 2.0
*/
class ColumnReorderEndToGroupEndCommand extends ColumnReorderEndCommand {
private final Group group;
public ColumnReorderEndToGroupEndCommand(ColumnReorderEndCommand command, Group group) {
super(command);
this.group = group;
}
/**
* Clone constructor.
*
* @param command
* The command to clone.
*/
protected ColumnReorderEndToGroupEndCommand(ColumnReorderEndToGroupEndCommand command) {
super(command);
this.group = command.group;
}
@Override
public boolean convertToTargetLayer(ILayer targetLayer) {
boolean convert = super.convertToTargetLayer(targetLayer);
// check if there are positions for the group members that would be
// more to the right. this could happen e.g. if columns at the group
// end are hidden
if (convert && !isReorderToLeftEdge() && targetLayer instanceof IUniqueIndexLayer) {
int groupEndPosition = this.group.getGroupEndPosition((IUniqueIndexLayer) targetLayer);
if (groupEndPosition >= 0 && groupEndPosition > getToColumnPosition()) {
updateToColumnPosition(groupEndPosition);
}
}
return convert;
}
@Override
public ColumnReorderEndToGroupEndCommand cloneCommand() {
return new ColumnReorderEndToGroupEndCommand(this);
}
}
}