blob: 72ea4834c1333b9f635a4e949829dd90c2820059 [file] [log] [blame]
/*******************************************************************************
* 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.tickupdate.command;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.IEditableRule;
import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
import org.eclipse.nebula.widgets.nattable.data.validate.IDataValidator;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.command.EditUtils;
import org.eclipse.nebula.widgets.nattable.edit.command.UpdateDataCommand;
import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.tickupdate.ITickUpdateHandler;
import org.eclipse.nebula.widgets.nattable.tickupdate.TickUpdateConfigAttributes;
/**
* The command handler that will handle {@link TickUpdateCommand}s on selected
* cells.
*/
public class TickUpdateCommandHandler extends AbstractLayerCommandHandler<TickUpdateCommand> {
private static final Log LOG = LogFactory.getLog(TickUpdateCommandHandler.class);
/**
* The {@link SelectionLayer} needed to retrieve the selected cells on which
* the tick update should be processed.
*/
private SelectionLayer selectionLayer;
/**
* The layer on top of the given {@link SelectionLayer} to which the
* selection should be converted to. Can be <code>null</code> which causes
* the resulting selected cells to be related to the {@link SelectionLayer}.
*/
private IUniqueIndexLayer upperLayer;
/**
* @param selectionLayer
* The {@link SelectionLayer} needed to retrieve the selected
* cells on which the tick update should be processed.
*/
public TickUpdateCommandHandler(SelectionLayer selectionLayer) {
this(selectionLayer, null);
}
/**
* Creates a command handler that performs the edit checks based on the
* given upper layer. Needed for example if the upper layer adds information
* that is needed for checks, e.g. a tree layer.
*
* @param selectionLayer
* The {@link SelectionLayer} needed to retrieve the selected
* cells on which the tick update should be processed.
* @param upperLayer
* The layer on top of the given {@link SelectionLayer} to which
* the selection should be converted to. Can be <code>null</code>
* which causes the resulting selected cells to be related to the
* {@link SelectionLayer}.
*
* @since 1.6
*/
public TickUpdateCommandHandler(SelectionLayer selectionLayer, IUniqueIndexLayer upperLayer) {
this.selectionLayer = selectionLayer;
this.upperLayer = upperLayer;
}
@Override
public boolean doCommand(TickUpdateCommand command) {
PositionCoordinate[] selectedPositions = this.selectionLayer.getSelectedCellPositions();
IConfigRegistry configRegistry = command.getConfigRegistry();
// Tick update for multiple cells in selection
if (selectedPositions.length > 1) {
// Can all cells be updated ?
if (EditUtils.allCellsEditable(this.selectionLayer, this.upperLayer, configRegistry)
&& EditUtils.isEditorSame(this.selectionLayer, this.upperLayer, configRegistry)
&& EditUtils.isConverterSame(this.selectionLayer, this.upperLayer, configRegistry)) {
for (PositionCoordinate position : selectedPositions) {
updateSingleCell(command, position);
}
}
} else {
// Tick update for single selected cell
updateSingleCell(command, this.selectionLayer.getLastSelectedCellPosition());
}
return true;
}
/**
* Will calculate the new value after tick update processing for the cell at
* the given coordinates, trying to update the value represented by that
* cell. The update will only be processed if the new value is valid.
*
* @param command
* The command to process
* @param selectedPosition
* The coordinates of the cell on which the tick update should be
* executed
*/
private void updateSingleCell(TickUpdateCommand command, PositionCoordinate selectedPosition) {
if (selectedPosition != null) {
ILayerCell cell = this.selectionLayer.getCellByPosition(
selectedPosition.columnPosition,
selectedPosition.rowPosition);
IConfigRegistry configRegistry = command.getConfigRegistry();
IEditableRule editableRule = configRegistry.getConfigAttribute(
EditConfigAttributes.CELL_EDITABLE_RULE,
DisplayMode.EDIT,
cell.getConfigLabels());
IDataValidator validator = configRegistry.getConfigAttribute(
EditConfigAttributes.DATA_VALIDATOR,
DisplayMode.EDIT,
cell.getConfigLabels());
if (editableRule.isEditable(cell, configRegistry)) {
// process the tick update
Object newValue = getNewCellValue(command, cell);
// validate the value
try {
if (validator == null
|| validator.validate(cell, configRegistry, newValue)) {
this.selectionLayer.doCommand(
new UpdateDataCommand(
this.selectionLayer,
selectedPosition.columnPosition,
selectedPosition.rowPosition,
newValue));
} else {
LOG.warn("Tick update failed for cell at " + selectedPosition + " and value " + newValue //$NON-NLS-1$ //$NON-NLS-2$
+ ". New value is not valid!"); //$NON-NLS-1$
}
} catch (Exception e) {
LOG.warn("Tick update failed for cell at " + selectedPosition + " and value " + newValue //$NON-NLS-1$ //$NON-NLS-2$
+ ". " + e.getLocalizedMessage()); //$NON-NLS-1$
}
}
}
}
/**
* Will calculate the new value for the given cell after tick update is
* processed.
*
* @param command
* The command to process
* @param cell
* The cell on which the command should be processed
* @return The processed value after the command was executed on the current
* cell value
*/
private Object getNewCellValue(TickUpdateCommand command, ILayerCell cell) {
ITickUpdateHandler tickUpdateHandler = command.getConfigRegistry().getConfigAttribute(
TickUpdateConfigAttributes.UPDATE_HANDLER,
DisplayMode.EDIT,
cell.getConfigLabels());
Object dataValue = cell.getDataValue();
if (tickUpdateHandler != null
&& tickUpdateHandler.isApplicableFor(dataValue)) {
if (command.isIncrement()) {
return tickUpdateHandler.getIncrementedValue(dataValue);
} else {
return tickUpdateHandler.getDecrementedValue(dataValue);
}
} else {
return dataValue;
}
}
@Override
public Class<TickUpdateCommand> getCommandClass() {
return TickUpdateCommand.class;
}
}