/******************************************************************************* * Copyright (c) 2012, 2013, 2014 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 * Dirk Fauth - added ITraversalStrategy handling ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.selection; import org.eclipse.nebula.widgets.nattable.command.ILayerCommand; import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; import org.eclipse.nebula.widgets.nattable.layer.ILayer; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; import org.eclipse.nebula.widgets.nattable.selection.command.MoveSelectionCommand; /** * Abstraction of the selection behavior during navigation in the grid. * Implementations of this class specify what to select when the selection moves * by responding to the {@link MoveSelectionCommand}. * * @param <T> * The type of the {@link ILayerCommand} this * {@link ILayerCommandHandler} handles. Needs to be a * {@link MoveSelectionCommand} or subtype. * * @see MoveCellSelectionCommandHandler * @see MoveRowSelectionCommandHandler */ public abstract class MoveSelectionCommandHandler<T extends MoveSelectionCommand> implements ILayerCommandHandler<T> { /** * The SelectionLayer instance which is needed to perform selection * operations. */ protected final SelectionLayer selectionLayer; /** * The strategy to use on horizontal traversal. Specifies the behavior when * the movement reaches a border. */ protected final ITraversalStrategy horizontalTraversalStrategy; /** * The strategy to use on vertical traversal. Specifies the behavior when * the movement reaches a border. */ protected final ITraversalStrategy verticalTraversalStrategy; /** * Create a MoveSelectionCommandHandler for the given {@link SelectionLayer} * . Uses the {@link ITraversalStrategy#AXIS_TRAVERSAL_STRATEGY} as default * strategy for selection movement. * * @param selectionLayer * The {@link SelectionLayer} on which the selection should be * performed. */ public MoveSelectionCommandHandler(SelectionLayer selectionLayer) { this(selectionLayer, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY); } /** * Create a MoveSelectionCommandHandler for the given {@link SelectionLayer} * . * * @param selectionLayer * The {@link SelectionLayer} on which the selection should be * performed. * @param traversalStrategy * The strategy that should be used for selection movements. Can * not be <code>null</code>. */ public MoveSelectionCommandHandler(SelectionLayer selectionLayer, ITraversalStrategy traversalStrategy) { this(selectionLayer, traversalStrategy, traversalStrategy); } /** * Create a MoveSelectionCommandHandler for the given {@link SelectionLayer} * . * * @param selectionLayer * The {@link SelectionLayer} on which the selection should be * performed. * @param horizontalTraversalStrategy * The strategy that should be used for horizontal selection * movements. Can not be <code>null</code>. * @param verticalTraversalStrategy * The strategy that should be used for vertical selection * movements. Can not be <code>null</code>. */ public MoveSelectionCommandHandler(SelectionLayer selectionLayer, ITraversalStrategy horizontalTraversalStrategy, ITraversalStrategy verticalTraversalStrategy) { if (horizontalTraversalStrategy == null || verticalTraversalStrategy == null) { throw new IllegalArgumentException("You need to specify an ITraversalStrategy!"); //$NON-NLS-1$ } this.selectionLayer = selectionLayer; this.horizontalTraversalStrategy = horizontalTraversalStrategy; this.verticalTraversalStrategy = verticalTraversalStrategy; } @Override public boolean doCommand(ILayer targetLayer, T command) { if (command.convertToTargetLayer(this.selectionLayer)) { moveSelection(command.getDirection(), getTraversalStrategy(command), command.isShiftMask(), command.isControlMask()); return true; } return false; } /** * Determines the {@link ITraversalStrategy} that should be used to move the * selection on handling the given command. The strategy is determined in * the following way: * <ol> * <li>Return the {@link ITraversalStrategy} carried by the command</li> * <li>If it doesn't contain a {@link ITraversalStrategy} but a carries a * dedicated step count, create a temporary {@link ITraversalStrategy} that * is configured with the locally configured {@link ITraversalStrategy} but * returns the step count carried by the command.</li> * <li>If the command doesn't carry a {@link ITraversalStrategy} and no * dedicated step count, the {@link ITraversalStrategy} registered with this * command handler is returned.</li> * </ol> * * @param command * The current handled command. * @return The {@link ITraversalStrategy} that should be used to move the * selection. <code>null</code> for {@link MoveDirectionEnum#NONE}. */ protected ITraversalStrategy getTraversalStrategy(final T command) { if (MoveDirectionEnum.DOWN.equals(command.getDirection()) || MoveDirectionEnum.UP.equals(command.getDirection())) { return getTraversalStrategy(command, this.verticalTraversalStrategy); } else if (MoveDirectionEnum.LEFT.equals(command.getDirection()) || MoveDirectionEnum.RIGHT.equals(command.getDirection())) { return getTraversalStrategy(command, this.horizontalTraversalStrategy); } // the MoveDirectionEnum that is not handled yet is NONE // so since no movement is involved, we return null return null; } /** * Determines the {@link ITraversalStrategy} that should be used to move the * selection on handling the given command. The strategy is determined in * the following way: * <ol> * <li>Return the {@link ITraversalStrategy} carried by the command</li> * <li>If it doesn't contain a {@link ITraversalStrategy} but a carries a * dedicated step count, create a temporary {@link ITraversalStrategy} that * is configured with the locally configured {@link ITraversalStrategy} but * returns the step count carried by the command.</li> * <li>If the command doesn't carry a {@link ITraversalStrategy} and no * dedicated step count, the {@link ITraversalStrategy} registered with this * command handler is returned.</li> * </ol> * * @param command * The current handled command. * @param baseTraversalStrategy * The {@link ITraversalStrategy} that should be used in case the * given command does not carry one. * @return The {@link ITraversalStrategy} that should be used to move the * selection. */ private ITraversalStrategy getTraversalStrategy(final T command, final ITraversalStrategy baseTraversalStrategy) { // if the command comes with a strategy we use it ITraversalStrategy result = command.getTraversalStrategy(); if (result == null) { if (command.getStepSize() != null) { // command carries a step size, so we use the provided strategy // with the transported step size this is mainly for backwards // compatibility result = new ITraversalStrategy() { @Override public TraversalScope getTraversalScope() { return baseTraversalStrategy.getTraversalScope(); } @Override public boolean isCycle() { return baseTraversalStrategy.isCycle(); } @Override public int getStepCount() { return command.getStepSize(); } @Override public boolean isValidTarget(ILayerCell from, ILayerCell to) { return baseTraversalStrategy.isValidTarget(from, to); } }; } else { result = baseTraversalStrategy; } } return result; } /** * Moves the selection from the current position into the given move * direction. * * @param moveDirection * The direction to move to. * @param traversalStrategy * the traversal strategy to determine the number of steps to * move and the behavior on moving over the border * @param withShiftMask * boolean flag to indicate whether the shift key modifier is * enabled or not * @param withControlMask * boolean flag to indicate whether the control key modifier is * enabled or not */ protected void moveSelection(MoveDirectionEnum moveDirection, ITraversalStrategy traversalStrategy, boolean withShiftMask, boolean withControlMask) { switch (moveDirection) { case UP: moveLastSelectedUp(traversalStrategy, withShiftMask, withControlMask); break; case DOWN: moveLastSelectedDown(traversalStrategy, withShiftMask, withControlMask); break; case LEFT: moveLastSelectedLeft(traversalStrategy, withShiftMask, withControlMask); break; case RIGHT: moveLastSelectedRight(traversalStrategy, withShiftMask, withControlMask); break; default: break; } } /** * Moves the selection from the current position to the right. * * @param traversalStrategy * the traversal strategy to determine the number of steps to * move and the behavior on moving over the border * @param withShiftMask * boolean flag to indicate whether the shift key modifier is * enabled or not * @param withControlMask * boolean flag to indicate whether the control key modifier is * enabled or not */ protected abstract void moveLastSelectedRight(ITraversalStrategy traversalStrategy, boolean withShiftMask, boolean withControlMask); /** * Moves the selection from the current position to the left. * * @param traversalStrategy * the traversal strategy to determine the number of steps to * move and the behavior on moving over the border * @param withShiftMask * boolean flag to indicate whether the shift key modifier is * enabled or not * @param withControlMask * boolean flag to indicate whether the control key modifier is * enabled or not */ protected abstract void moveLastSelectedLeft(ITraversalStrategy traversalStrategy, boolean withShiftMask, boolean withControlMask); /** * Moves the selection from the current position up. * * @param traversalStrategy * the traversal strategy to determine the number of steps to * move and the behavior on moving over the border * @param withShiftMask * boolean flag to indicate whether the shift key modifier is * enabled or not * @param withControlMask * boolean flag to indicate whether the control key modifier is * enabled or not */ protected abstract void moveLastSelectedUp(ITraversalStrategy traversalStrategy, boolean withShiftMask, boolean withControlMask); /** * Moves the selection from the current position down. * * @param traversalStrategy * the traversal strategy to determine the number of steps to * move and the behavior on moving over the border * @param withShiftMask * boolean flag to indicate whether the shift key modifier is * enabled or not * @param withControlMask * boolean flag to indicate whether the control key modifier is * enabled or not */ protected abstract void moveLastSelectedDown(ITraversalStrategy traversalStrategy, boolean withShiftMask, boolean withControlMask); }