blob: 3e17ff916a8633580b590542d0af9d019209817e [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.grid.layer;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.export.command.ExportCommandHandler;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeColumnCommandHandler;
import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeRowCommandHandler;
import org.eclipse.nebula.widgets.nattable.grid.command.ClientAreaResizeCommand;
import org.eclipse.nebula.widgets.nattable.grid.layer.config.DefaultGridLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.layer.CompositeLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.print.command.PrintCommandHandler;
import org.eclipse.nebula.widgets.nattable.resize.command.AutoResizeColumnsCommand;
import org.eclipse.nebula.widgets.nattable.resize.command.AutoResizeRowsCommand;
import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;
import org.eclipse.swt.graphics.Rectangle;
/**
* Top level layer. It is composed of the smaller child layers: RowHeader,
* ColumnHeader, Corner and Body It does not have its own coordinate system
* unlike the other layers. It simply delegates most functions to its child
* layers.
*/
public class GridLayer extends CompositeLayer {
public GridLayer(
ILayer bodyLayer,
ILayer columnHeaderLayer,
ILayer rowHeaderLayer,
ILayer cornerLayer) {
this(bodyLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer, true);
}
public GridLayer(
ILayer bodyLayer,
ILayer columnHeaderLayer,
ILayer rowHeaderLayer,
ILayer cornerLayer,
boolean useDefaultConfiguration) {
super(2, 2);
setBodyLayer(bodyLayer);
setColumnHeaderLayer(columnHeaderLayer);
setRowHeaderLayer(rowHeaderLayer);
setCornerLayer(cornerLayer);
init(useDefaultConfiguration);
}
protected GridLayer(boolean useDefaultConfiguration) {
super(2, 2);
init(useDefaultConfiguration);
}
protected void init(boolean useDefaultConfiguration) {
registerCommandHandlers();
if (useDefaultConfiguration) {
addConfiguration(new DefaultGridLayerConfiguration(this));
}
}
@Override
protected void registerCommandHandlers() {
registerCommandHandler(new PrintCommandHandler(this));
registerCommandHandler(new ExportCommandHandler(this));
registerCommandHandler(new AutoResizeColumnCommandHandler(this));
registerCommandHandler(new AutoResizeRowCommandHandler(this));
}
/**
* How the GridLayer processes commands is very important. <strong>Do not
* change this unless you know what you are doing and understand the full
* ramifications of your change. Otherwise your grid will not behave
* correctly!</strong>
*
* The Body is always given the first chance to process a command. There are
* two reasons for this: (1) most commands (80%) are destined for the body
* anyways so it's faster to check there first (2) the other layers all
* transitively depend on the body so it's not wise to ask them to do stuff
* until after the body has done it. This is especially true of grid
* initialization where the body must be initialized before any of its
* dependent layers.
*
* Because of this, if you want to intercept well-known commands to
* implement custom behavior (for example, you want to intercept the
* {@link SelectCellCommand}) then <strong>you must inject your special
* layer into the body. </strong> An injected column or row header will
* never see the command because it will be consumed first by the body. In
* practice, it's a good idea to implement all your command-handling logic
* in the body.
**/
@Override
protected boolean doCommandOnChildLayers(ILayerCommand command) {
if (doCommandOnChildLayer(command, getBodyLayer())) {
return true;
} else if (doCommandOnChildLayer(command, getColumnHeaderLayer())) {
return true;
} else if (doCommandOnChildLayer(command, getRowHeaderLayer())) {
return true;
} else {
return doCommandOnChildLayer(command, getCornerLayer());
}
}
private boolean doCommandOnChildLayer(ILayerCommand command, ILayer childLayer) {
ILayerCommand childCommand = command.cloneCommand();
return childLayer.doCommand(childCommand);
}
// Sub-layer accessors
public ILayer getCornerLayer() {
return getChildLayerByLayoutCoordinate(0, 0);
}
public void setCornerLayer(ILayer cornerLayer) {
setChildLayer(GridRegion.CORNER, cornerLayer, 0, 0);
}
public ILayer getColumnHeaderLayer() {
return getChildLayerByLayoutCoordinate(1, 0);
}
public void setColumnHeaderLayer(ILayer columnHeaderLayer) {
setChildLayer(GridRegion.COLUMN_HEADER, columnHeaderLayer, 1, 0);
}
public ILayer getRowHeaderLayer() {
return getChildLayerByLayoutCoordinate(0, 1);
}
public void setRowHeaderLayer(ILayer rowHeaderLayer) {
setChildLayer(GridRegion.ROW_HEADER, rowHeaderLayer, 0, 1);
}
public ILayer getBodyLayer() {
return getChildLayerByLayoutCoordinate(1, 1);
}
public void setBodyLayer(ILayer bodyLayer) {
setChildLayer(GridRegion.BODY, bodyLayer, 1, 1);
// update the command handlers for auto resize because of the connection
// to the body layer stack
unregisterCommandHandler(AutoResizeColumnsCommand.class);
unregisterCommandHandler(AutoResizeRowsCommand.class);
registerCommandHandler(new AutoResizeColumnCommandHandler(this));
registerCommandHandler(new AutoResizeRowCommandHandler(this));
}
@Override
public String toString() {
return getClass().getSimpleName() + "[corner=" + getCornerLayer() //$NON-NLS-1$
+ " columnHeader=" + getColumnHeaderLayer() //$NON-NLS-1$
+ " rowHeader=" + getRowHeaderLayer() //$NON-NLS-1$
+ " bodyLayer=" + getBodyLayer() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public boolean doCommand(ILayerCommand command) {
if (command instanceof ClientAreaResizeCommand
&& command.convertToTargetLayer(this)) {
ClientAreaResizeCommand clientAreaResizeCommand = (ClientAreaResizeCommand) command;
Rectangle possibleArea = clientAreaResizeCommand.getScrollable()
.getClientArea();
// remove the column header height and the row header width from the
// client area to
// ensure that only the body region is used for percentage
// calculation
Rectangle rowLayerArea = getRowHeaderLayer()
.getClientAreaProvider().getClientArea();
Rectangle columnLayerArea = getColumnHeaderLayer()
.getClientAreaProvider().getClientArea();
possibleArea.width = possibleArea.width - rowLayerArea.width;
possibleArea.height = possibleArea.height - columnLayerArea.height;
clientAreaResizeCommand.setCalcArea(possibleArea);
}
return super.doCommand(command);
}
}